• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/ssb/
1/*
2 * Sonics Silicon Backplane
3 * SDIO-Hostbus related functions
4 *
5 * Copyright 2009 Albert Herranz <albert_herranz@yahoo.es>
6 *
7 * Based on drivers/ssb/pcmcia.c
8 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
9 * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
10 *
11 * Licensed under the GNU/GPL. See COPYING for details.
12 *
13 */
14
15#include <linux/ssb/ssb.h>
16#include <linux/delay.h>
17#include <linux/io.h>
18#include <linux/etherdevice.h>
19#include <linux/mmc/sdio_func.h>
20
21#include "ssb_private.h"
22
23/* Define the following to 1 to enable a printk on each coreswitch. */
24#define SSB_VERBOSE_SDIOCORESWITCH_DEBUG		0
25
26
27/* Hardware invariants CIS tuples */
28#define SSB_SDIO_CIS			0x80
29#define  SSB_SDIO_CIS_SROMREV		0x00
30#define  SSB_SDIO_CIS_ID		0x01
31#define  SSB_SDIO_CIS_BOARDREV		0x02
32#define  SSB_SDIO_CIS_PA		0x03
33#define   SSB_SDIO_CIS_PA_PA0B0_LO	0
34#define   SSB_SDIO_CIS_PA_PA0B0_HI	1
35#define   SSB_SDIO_CIS_PA_PA0B1_LO	2
36#define   SSB_SDIO_CIS_PA_PA0B1_HI	3
37#define   SSB_SDIO_CIS_PA_PA0B2_LO	4
38#define   SSB_SDIO_CIS_PA_PA0B2_HI	5
39#define   SSB_SDIO_CIS_PA_ITSSI		6
40#define   SSB_SDIO_CIS_PA_MAXPOW	7
41#define  SSB_SDIO_CIS_OEMNAME		0x04
42#define  SSB_SDIO_CIS_CCODE		0x05
43#define  SSB_SDIO_CIS_ANTENNA		0x06
44#define  SSB_SDIO_CIS_ANTGAIN		0x07
45#define  SSB_SDIO_CIS_BFLAGS		0x08
46#define  SSB_SDIO_CIS_LEDS		0x09
47
48#define CISTPL_FUNCE_LAN_NODE_ID        0x04	/* same as in PCMCIA */
49
50
51/*
52 * Function 1 miscellaneous registers.
53 *
54 * Definitions match src/include/sbsdio.h from the
55 * Android Open Source Project
56 * http://android.git.kernel.org/?p=platform/system/wlan/broadcom.git
57 *
58 */
59#define SBSDIO_FUNC1_SBADDRLOW	0x1000a	/* SB Address window Low (b15) */
60#define SBSDIO_FUNC1_SBADDRMID	0x1000b	/* SB Address window Mid (b23-b16) */
61#define SBSDIO_FUNC1_SBADDRHIGH	0x1000c	/* SB Address window High (b24-b31) */
62
63/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */
64#define SBSDIO_SBADDRLOW_MASK	0x80	/* Valid address bits in SBADDRLOW */
65#define SBSDIO_SBADDRMID_MASK	0xff	/* Valid address bits in SBADDRMID */
66#define SBSDIO_SBADDRHIGH_MASK	0xff	/* Valid address bits in SBADDRHIGH */
67
68#define SBSDIO_SB_OFT_ADDR_MASK	0x7FFF	/* sb offset addr is <= 15 bits, 32k */
69
70/* REVISIT: this flag doesn't seem to matter */
71#define SBSDIO_SB_ACCESS_2_4B_FLAG	0x8000	/* forces 32-bit SB access */
72
73
74/*
75 * Address map within the SDIO function address space (128K).
76 *
77 *   Start   End     Description
78 *   ------- ------- ------------------------------------------
79 *   0x00000 0x0ffff selected backplane address window (64K)
80 *   0x10000 0x1ffff backplane control registers (max 64K)
81 *
82 * The current address window is configured by writing to registers
83 * SBADDRLOW, SBADDRMID and SBADDRHIGH.
84 *
85 * In order to access the contents of a 32-bit Silicon Backplane address
86 * the backplane address window must be first loaded with the highest
87 * 16 bits of the target address. Then, an access must be done to the
88 * SDIO function address space using the lower 15 bits of the address.
89 * Bit 15 of the address must be set when doing 32 bit accesses.
90 *
91 * 10987654321098765432109876543210
92 * WWWWWWWWWWWWWWWWW                 SB Address Window
93 *                 OOOOOOOOOOOOOOOO  Offset within SB Address Window
94 *                 a                 32-bit access flag
95 */
96
97
98/*
99 * SSB I/O via SDIO.
100 *
101 * NOTE: SDIO address @addr is 17 bits long (SDIO address space is 128K).
102 */
103
104static inline struct device *ssb_sdio_dev(struct ssb_bus *bus)
105{
106	return &bus->host_sdio->dev;
107}
108
109/* host claimed */
110static int ssb_sdio_writeb(struct ssb_bus *bus, unsigned int addr, u8 val)
111{
112	int error = 0;
113
114	sdio_writeb(bus->host_sdio, val, addr, &error);
115	if (unlikely(error)) {
116		dev_dbg(ssb_sdio_dev(bus), "%08X <- %02x, error %d\n",
117			addr, val, error);
118	}
119
120	return error;
121}
122
123
124/* host claimed */
125static int ssb_sdio_set_sbaddr_window(struct ssb_bus *bus, u32 address)
126{
127	int error;
128
129	error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRLOW,
130				(address >> 8) & SBSDIO_SBADDRLOW_MASK);
131	if (error)
132		goto out;
133	error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRMID,
134				(address >> 16) & SBSDIO_SBADDRMID_MASK);
135	if (error)
136		goto out;
137	error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRHIGH,
138				(address >> 24) & SBSDIO_SBADDRHIGH_MASK);
139	if (error)
140		goto out;
141	bus->sdio_sbaddr = address;
142out:
143	if (error) {
144		dev_dbg(ssb_sdio_dev(bus), "failed to set address window"
145			" to 0x%08x, error %d\n", address, error);
146	}
147
148	return error;
149}
150
151/* for enumeration use only */
152u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset)
153{
154	u32 val;
155	int error;
156
157	sdio_claim_host(bus->host_sdio);
158	val = sdio_readl(bus->host_sdio, offset, &error);
159	sdio_release_host(bus->host_sdio);
160	if (unlikely(error)) {
161		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n",
162			bus->sdio_sbaddr >> 16, offset, val, error);
163	}
164
165	return val;
166}
167
168/* for enumeration use only */
169int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
170{
171	u32 sbaddr;
172	int error;
173
174	sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
175	sdio_claim_host(bus->host_sdio);
176	error = ssb_sdio_set_sbaddr_window(bus, sbaddr);
177	sdio_release_host(bus->host_sdio);
178	if (error) {
179		dev_err(ssb_sdio_dev(bus), "failed to switch to core %u,"
180			" error %d\n", coreidx, error);
181		goto out;
182	}
183out:
184	return error;
185}
186
187/* host must be already claimed */
188int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
189{
190	u8 coreidx = dev->core_index;
191	u32 sbaddr;
192	int error = 0;
193
194	sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
195	if (unlikely(bus->sdio_sbaddr != sbaddr)) {
196#if SSB_VERBOSE_SDIOCORESWITCH_DEBUG
197		dev_info(ssb_sdio_dev(bus),
198			   "switching to %s core, index %d\n",
199			   ssb_core_name(dev->id.coreid), coreidx);
200#endif
201		error = ssb_sdio_set_sbaddr_window(bus, sbaddr);
202		if (error) {
203			dev_dbg(ssb_sdio_dev(bus), "failed to switch to"
204				" core %u, error %d\n", coreidx, error);
205			goto out;
206		}
207		bus->mapped_device = dev;
208	}
209
210out:
211	return error;
212}
213
214static u8 ssb_sdio_read8(struct ssb_device *dev, u16 offset)
215{
216	struct ssb_bus *bus = dev->bus;
217	u8 val = 0xff;
218	int error = 0;
219
220	sdio_claim_host(bus->host_sdio);
221	if (unlikely(ssb_sdio_switch_core(bus, dev)))
222		goto out;
223	offset |= bus->sdio_sbaddr & 0xffff;
224	offset &= SBSDIO_SB_OFT_ADDR_MASK;
225	val = sdio_readb(bus->host_sdio, offset, &error);
226	if (error) {
227		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %02x, error %d\n",
228			bus->sdio_sbaddr >> 16, offset, val, error);
229	}
230out:
231	sdio_release_host(bus->host_sdio);
232
233	return val;
234}
235
236static u16 ssb_sdio_read16(struct ssb_device *dev, u16 offset)
237{
238	struct ssb_bus *bus = dev->bus;
239	u16 val = 0xffff;
240	int error = 0;
241
242	sdio_claim_host(bus->host_sdio);
243	if (unlikely(ssb_sdio_switch_core(bus, dev)))
244		goto out;
245	offset |= bus->sdio_sbaddr & 0xffff;
246	offset &= SBSDIO_SB_OFT_ADDR_MASK;
247	val = sdio_readw(bus->host_sdio, offset, &error);
248	if (error) {
249		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %04x, error %d\n",
250			bus->sdio_sbaddr >> 16, offset, val, error);
251	}
252out:
253	sdio_release_host(bus->host_sdio);
254
255	return val;
256}
257
258static u32 ssb_sdio_read32(struct ssb_device *dev, u16 offset)
259{
260	struct ssb_bus *bus = dev->bus;
261	u32 val = 0xffffffff;
262	int error = 0;
263
264	sdio_claim_host(bus->host_sdio);
265	if (unlikely(ssb_sdio_switch_core(bus, dev)))
266		goto out;
267	offset |= bus->sdio_sbaddr & 0xffff;
268	offset &= SBSDIO_SB_OFT_ADDR_MASK;
269	offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;	/* 32 bit data access */
270	val = sdio_readl(bus->host_sdio, offset, &error);
271	if (error) {
272		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n",
273			bus->sdio_sbaddr >> 16, offset, val, error);
274	}
275out:
276	sdio_release_host(bus->host_sdio);
277
278	return val;
279}
280
281#ifdef CONFIG_SSB_BLOCKIO
282static void ssb_sdio_block_read(struct ssb_device *dev, void *buffer,
283				  size_t count, u16 offset, u8 reg_width)
284{
285	size_t saved_count = count;
286	struct ssb_bus *bus = dev->bus;
287	int error = 0;
288
289	sdio_claim_host(bus->host_sdio);
290	if (unlikely(ssb_sdio_switch_core(bus, dev))) {
291		error = -EIO;
292		memset(buffer, 0xff, count);
293		goto err_out;
294	}
295	offset |= bus->sdio_sbaddr & 0xffff;
296	offset &= SBSDIO_SB_OFT_ADDR_MASK;
297
298	switch (reg_width) {
299	case sizeof(u8): {
300		error = sdio_readsb(bus->host_sdio, buffer, offset, count);
301		break;
302	}
303	case sizeof(u16): {
304		SSB_WARN_ON(count & 1);
305		error = sdio_readsb(bus->host_sdio, buffer, offset, count);
306		break;
307	}
308	case sizeof(u32): {
309		SSB_WARN_ON(count & 3);
310		offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;	/* 32 bit data access */
311		error = sdio_readsb(bus->host_sdio, buffer, offset, count);
312		break;
313	}
314	default:
315		SSB_WARN_ON(1);
316	}
317	if (!error)
318		goto out;
319
320err_out:
321	dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%zu), error %d\n",
322		bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error);
323out:
324	sdio_release_host(bus->host_sdio);
325}
326#endif /* CONFIG_SSB_BLOCKIO */
327
328static void ssb_sdio_write8(struct ssb_device *dev, u16 offset, u8 val)
329{
330	struct ssb_bus *bus = dev->bus;
331	int error = 0;
332
333	sdio_claim_host(bus->host_sdio);
334	if (unlikely(ssb_sdio_switch_core(bus, dev)))
335		goto out;
336	offset |= bus->sdio_sbaddr & 0xffff;
337	offset &= SBSDIO_SB_OFT_ADDR_MASK;
338	sdio_writeb(bus->host_sdio, val, offset, &error);
339	if (error) {
340		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %02x, error %d\n",
341			bus->sdio_sbaddr >> 16, offset, val, error);
342	}
343out:
344	sdio_release_host(bus->host_sdio);
345}
346
347static void ssb_sdio_write16(struct ssb_device *dev, u16 offset, u16 val)
348{
349	struct ssb_bus *bus = dev->bus;
350	int error = 0;
351
352	sdio_claim_host(bus->host_sdio);
353	if (unlikely(ssb_sdio_switch_core(bus, dev)))
354		goto out;
355	offset |= bus->sdio_sbaddr & 0xffff;
356	offset &= SBSDIO_SB_OFT_ADDR_MASK;
357	sdio_writew(bus->host_sdio, val, offset, &error);
358	if (error) {
359		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %04x, error %d\n",
360			bus->sdio_sbaddr >> 16, offset, val, error);
361	}
362out:
363	sdio_release_host(bus->host_sdio);
364}
365
366static void ssb_sdio_write32(struct ssb_device *dev, u16 offset, u32 val)
367{
368	struct ssb_bus *bus = dev->bus;
369	int error = 0;
370
371	sdio_claim_host(bus->host_sdio);
372	if (unlikely(ssb_sdio_switch_core(bus, dev)))
373		goto out;
374	offset |= bus->sdio_sbaddr & 0xffff;
375	offset &= SBSDIO_SB_OFT_ADDR_MASK;
376	offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;	/* 32 bit data access */
377	sdio_writel(bus->host_sdio, val, offset, &error);
378	if (error) {
379		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %08x, error %d\n",
380			bus->sdio_sbaddr >> 16, offset, val, error);
381	}
382	if (bus->quirks & SSB_QUIRK_SDIO_READ_AFTER_WRITE32)
383		sdio_readl(bus->host_sdio, 0, &error);
384out:
385	sdio_release_host(bus->host_sdio);
386}
387
388#ifdef CONFIG_SSB_BLOCKIO
389static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer,
390				   size_t count, u16 offset, u8 reg_width)
391{
392	size_t saved_count = count;
393	struct ssb_bus *bus = dev->bus;
394	int error = 0;
395
396	sdio_claim_host(bus->host_sdio);
397	if (unlikely(ssb_sdio_switch_core(bus, dev))) {
398		error = -EIO;
399		memset((void *)buffer, 0xff, count);
400		goto err_out;
401	}
402	offset |= bus->sdio_sbaddr & 0xffff;
403	offset &= SBSDIO_SB_OFT_ADDR_MASK;
404
405	switch (reg_width) {
406	case sizeof(u8):
407		error = sdio_writesb(bus->host_sdio, offset,
408				     (void *)buffer, count);
409		break;
410	case sizeof(u16):
411		SSB_WARN_ON(count & 1);
412		error = sdio_writesb(bus->host_sdio, offset,
413				     (void *)buffer, count);
414		break;
415	case sizeof(u32):
416		SSB_WARN_ON(count & 3);
417		offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;	/* 32 bit data access */
418		error = sdio_writesb(bus->host_sdio, offset,
419				     (void *)buffer, count);
420		break;
421	default:
422		SSB_WARN_ON(1);
423	}
424	if (!error)
425		goto out;
426
427err_out:
428	dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%zu), error %d\n",
429		bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error);
430out:
431	sdio_release_host(bus->host_sdio);
432}
433
434#endif /* CONFIG_SSB_BLOCKIO */
435
436/* Not "static", as it's used in main.c */
437const struct ssb_bus_ops ssb_sdio_ops = {
438	.read8		= ssb_sdio_read8,
439	.read16		= ssb_sdio_read16,
440	.read32		= ssb_sdio_read32,
441	.write8		= ssb_sdio_write8,
442	.write16	= ssb_sdio_write16,
443	.write32	= ssb_sdio_write32,
444#ifdef CONFIG_SSB_BLOCKIO
445	.block_read	= ssb_sdio_block_read,
446	.block_write	= ssb_sdio_block_write,
447#endif
448};
449
450#define GOTO_ERROR_ON(condition, description) do {	\
451	if (unlikely(condition)) {			\
452		error_description = description;	\
453		goto error;				\
454	}						\
455  } while (0)
456
457int ssb_sdio_get_invariants(struct ssb_bus *bus,
458			    struct ssb_init_invariants *iv)
459{
460	struct ssb_sprom *sprom = &iv->sprom;
461	struct ssb_boardinfo *bi = &iv->boardinfo;
462	const char *error_description = "none";
463	struct sdio_func_tuple *tuple;
464	void *mac;
465
466	memset(sprom, 0xFF, sizeof(*sprom));
467	sprom->boardflags_lo = 0;
468	sprom->boardflags_hi = 0;
469
470	tuple = bus->host_sdio->tuples;
471	while (tuple) {
472		switch (tuple->code) {
473		case 0x22: /* extended function */
474			switch (tuple->data[0]) {
475			case CISTPL_FUNCE_LAN_NODE_ID:
476				GOTO_ERROR_ON((tuple->size != 7) &&
477					      (tuple->data[1] != 6),
478					      "mac tpl size");
479				/* fetch the MAC address. */
480				mac = tuple->data + 2;
481				memcpy(sprom->il0mac, mac, ETH_ALEN);
482				memcpy(sprom->et1mac, mac, ETH_ALEN);
483				break;
484			default:
485				break;
486			}
487			break;
488		case 0x80: /* vendor specific tuple */
489			switch (tuple->data[0]) {
490			case SSB_SDIO_CIS_SROMREV:
491				GOTO_ERROR_ON(tuple->size != 2,
492					      "sromrev tpl size");
493				sprom->revision = tuple->data[1];
494				break;
495			case SSB_SDIO_CIS_ID:
496				GOTO_ERROR_ON((tuple->size != 5) &&
497					      (tuple->size != 7),
498					      "id tpl size");
499				bi->vendor = tuple->data[1] |
500					     (tuple->data[2]<<8);
501				break;
502			case SSB_SDIO_CIS_BOARDREV:
503				GOTO_ERROR_ON(tuple->size != 2,
504					      "boardrev tpl size");
505				sprom->board_rev = tuple->data[1];
506				break;
507			case SSB_SDIO_CIS_PA:
508				GOTO_ERROR_ON((tuple->size != 9) &&
509					      (tuple->size != 10),
510					      "pa tpl size");
511				sprom->pa0b0 = tuple->data[1] |
512					 ((u16)tuple->data[2] << 8);
513				sprom->pa0b1 = tuple->data[3] |
514					 ((u16)tuple->data[4] << 8);
515				sprom->pa0b2 = tuple->data[5] |
516					 ((u16)tuple->data[6] << 8);
517				sprom->itssi_a = tuple->data[7];
518				sprom->itssi_bg = tuple->data[7];
519				sprom->maxpwr_a = tuple->data[8];
520				sprom->maxpwr_bg = tuple->data[8];
521				break;
522			case SSB_SDIO_CIS_OEMNAME:
523				/* Not present */
524				break;
525			case SSB_SDIO_CIS_CCODE:
526				GOTO_ERROR_ON(tuple->size != 2,
527					      "ccode tpl size");
528				sprom->country_code = tuple->data[1];
529				break;
530			case SSB_SDIO_CIS_ANTENNA:
531				GOTO_ERROR_ON(tuple->size != 2,
532					      "ant tpl size");
533				sprom->ant_available_a = tuple->data[1];
534				sprom->ant_available_bg = tuple->data[1];
535				break;
536			case SSB_SDIO_CIS_ANTGAIN:
537				GOTO_ERROR_ON(tuple->size != 2,
538					      "antg tpl size");
539				sprom->antenna_gain.ghz24.a0 = tuple->data[1];
540				sprom->antenna_gain.ghz24.a1 = tuple->data[1];
541				sprom->antenna_gain.ghz24.a2 = tuple->data[1];
542				sprom->antenna_gain.ghz24.a3 = tuple->data[1];
543				sprom->antenna_gain.ghz5.a0 = tuple->data[1];
544				sprom->antenna_gain.ghz5.a1 = tuple->data[1];
545				sprom->antenna_gain.ghz5.a2 = tuple->data[1];
546				sprom->antenna_gain.ghz5.a3 = tuple->data[1];
547				break;
548			case SSB_SDIO_CIS_BFLAGS:
549				GOTO_ERROR_ON((tuple->size != 3) &&
550					      (tuple->size != 5),
551					      "bfl tpl size");
552				sprom->boardflags_lo = tuple->data[1] |
553						 ((u16)tuple->data[2] << 8);
554				break;
555			case SSB_SDIO_CIS_LEDS:
556				GOTO_ERROR_ON(tuple->size != 5,
557					      "leds tpl size");
558				sprom->gpio0 = tuple->data[1];
559				sprom->gpio1 = tuple->data[2];
560				sprom->gpio2 = tuple->data[3];
561				sprom->gpio3 = tuple->data[4];
562				break;
563			default:
564				break;
565			}
566			break;
567		default:
568			break;
569		}
570		tuple = tuple->next;
571	}
572
573	return 0;
574error:
575	dev_err(ssb_sdio_dev(bus), "failed to fetch device invariants: %s\n",
576		error_description);
577	return -ENODEV;
578}
579
580void ssb_sdio_exit(struct ssb_bus *bus)
581{
582	if (bus->bustype != SSB_BUSTYPE_SDIO)
583		return;
584	/* Nothing to do here. */
585}
586
587int ssb_sdio_init(struct ssb_bus *bus)
588{
589	if (bus->bustype != SSB_BUSTYPE_SDIO)
590		return 0;
591
592	bus->sdio_sbaddr = ~0;
593
594	return 0;
595}
596