• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/ssb/
1/*
2 * Sonics Silicon Backplane
3 * Bus scanning
4 *
5 * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
6 * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
7 * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
8 * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
9 * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10 * Copyright (C) 2006 Broadcom Corporation.
11 *
12 * Licensed under the GNU/GPL. See COPYING for details.
13 */
14
15#include <linux/ssb/ssb.h>
16#include <linux/ssb/ssb_regs.h>
17#include <linux/pci.h>
18#include <linux/io.h>
19
20#include <pcmcia/cs.h>
21#include <pcmcia/cistpl.h>
22#include <pcmcia/ds.h>
23
24#include "ssb_private.h"
25
26
27const char *ssb_core_name(u16 coreid)
28{
29	switch (coreid) {
30	case SSB_DEV_CHIPCOMMON:
31		return "ChipCommon";
32	case SSB_DEV_ILINE20:
33		return "ILine 20";
34	case SSB_DEV_SDRAM:
35		return "SDRAM";
36	case SSB_DEV_PCI:
37		return "PCI";
38	case SSB_DEV_MIPS:
39		return "MIPS";
40	case SSB_DEV_ETHERNET:
41		return "Fast Ethernet";
42	case SSB_DEV_V90:
43		return "V90";
44	case SSB_DEV_USB11_HOSTDEV:
45		return "USB 1.1 Hostdev";
46	case SSB_DEV_ADSL:
47		return "ADSL";
48	case SSB_DEV_ILINE100:
49		return "ILine 100";
50	case SSB_DEV_IPSEC:
51		return "IPSEC";
52	case SSB_DEV_PCMCIA:
53		return "PCMCIA";
54	case SSB_DEV_INTERNAL_MEM:
55		return "Internal Memory";
56	case SSB_DEV_MEMC_SDRAM:
57		return "MEMC SDRAM";
58	case SSB_DEV_EXTIF:
59		return "EXTIF";
60	case SSB_DEV_80211:
61		return "IEEE 802.11";
62	case SSB_DEV_MIPS_3302:
63		return "MIPS 3302";
64	case SSB_DEV_USB11_HOST:
65		return "USB 1.1 Host";
66	case SSB_DEV_USB11_DEV:
67		return "USB 1.1 Device";
68	case SSB_DEV_USB20_HOST:
69		return "USB 2.0 Host";
70	case SSB_DEV_USB20_DEV:
71		return "USB 2.0 Device";
72	case SSB_DEV_SDIO_HOST:
73		return "SDIO Host";
74	case SSB_DEV_ROBOSWITCH:
75		return "Roboswitch";
76	case SSB_DEV_PARA_ATA:
77		return "PATA";
78	case SSB_DEV_SATA_XORDMA:
79		return "SATA XOR-DMA";
80	case SSB_DEV_ETHERNET_GBIT:
81		return "GBit Ethernet";
82	case SSB_DEV_PCIE:
83		return "PCI-E";
84	case SSB_DEV_MIMO_PHY:
85		return "MIMO PHY";
86	case SSB_DEV_SRAM_CTRLR:
87		return "SRAM Controller";
88	case SSB_DEV_MINI_MACPHY:
89		return "Mini MACPHY";
90	case SSB_DEV_ARM_1176:
91		return "ARM 1176";
92	case SSB_DEV_ARM_7TDMI:
93		return "ARM 7TDMI";
94	}
95	return "UNKNOWN";
96}
97
98static u16 pcidev_to_chipid(struct pci_dev *pci_dev)
99{
100	u16 chipid_fallback = 0;
101
102	switch (pci_dev->device) {
103	case 0x4301:
104		chipid_fallback = 0x4301;
105		break;
106	case 0x4305 ... 0x4307:
107		chipid_fallback = 0x4307;
108		break;
109	case 0x4403:
110		chipid_fallback = 0x4402;
111		break;
112	case 0x4610 ... 0x4615:
113		chipid_fallback = 0x4610;
114		break;
115	case 0x4710 ... 0x4715:
116		chipid_fallback = 0x4710;
117		break;
118	case 0x4320 ... 0x4325:
119		chipid_fallback = 0x4309;
120		break;
121	case PCI_DEVICE_ID_BCM4401:
122	case PCI_DEVICE_ID_BCM4401B0:
123	case PCI_DEVICE_ID_BCM4401B1:
124		chipid_fallback = 0x4401;
125		break;
126	default:
127		ssb_printk(KERN_ERR PFX
128			   "PCI-ID not in fallback list\n");
129	}
130
131	return chipid_fallback;
132}
133
134static u8 chipid_to_nrcores(u16 chipid)
135{
136	switch (chipid) {
137	case 0x5365:
138		return 7;
139	case 0x4306:
140		return 6;
141	case 0x4310:
142		return 8;
143	case 0x4307:
144	case 0x4301:
145		return 5;
146	case 0x4401:
147	case 0x4402:
148		return 3;
149	case 0x4710:
150	case 0x4610:
151	case 0x4704:
152		return 9;
153	default:
154		ssb_printk(KERN_ERR PFX
155			   "CHIPID not in nrcores fallback list\n");
156	}
157
158	return 1;
159}
160
161static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx,
162		       u16 offset)
163{
164	u32 lo, hi;
165
166	switch (bus->bustype) {
167	case SSB_BUSTYPE_SSB:
168		offset += current_coreidx * SSB_CORE_SIZE;
169		break;
170	case SSB_BUSTYPE_PCI:
171		break;
172	case SSB_BUSTYPE_PCMCIA:
173		if (offset >= 0x800) {
174			ssb_pcmcia_switch_segment(bus, 1);
175			offset -= 0x800;
176		} else
177			ssb_pcmcia_switch_segment(bus, 0);
178		lo = readw(bus->mmio + offset);
179		hi = readw(bus->mmio + offset + 2);
180		return lo | (hi << 16);
181	case SSB_BUSTYPE_SDIO:
182		offset += current_coreidx * SSB_CORE_SIZE;
183		return ssb_sdio_scan_read32(bus, offset);
184	}
185	return readl(bus->mmio + offset);
186}
187
188static int scan_switchcore(struct ssb_bus *bus, u8 coreidx)
189{
190	switch (bus->bustype) {
191	case SSB_BUSTYPE_SSB:
192		break;
193	case SSB_BUSTYPE_PCI:
194		return ssb_pci_switch_coreidx(bus, coreidx);
195	case SSB_BUSTYPE_PCMCIA:
196		return ssb_pcmcia_switch_coreidx(bus, coreidx);
197	case SSB_BUSTYPE_SDIO:
198		return ssb_sdio_scan_switch_coreidx(bus, coreidx);
199	}
200	return 0;
201}
202
203void ssb_iounmap(struct ssb_bus *bus)
204{
205	switch (bus->bustype) {
206	case SSB_BUSTYPE_SSB:
207	case SSB_BUSTYPE_PCMCIA:
208		iounmap(bus->mmio);
209		break;
210	case SSB_BUSTYPE_PCI:
211#ifdef CONFIG_SSB_PCIHOST
212		pci_iounmap(bus->host_pci, bus->mmio);
213#else
214		SSB_BUG_ON(1); /* Can't reach this code. */
215#endif
216		break;
217	case SSB_BUSTYPE_SDIO:
218		break;
219	}
220	bus->mmio = NULL;
221	bus->mapped_device = NULL;
222}
223
224static void __iomem *ssb_ioremap(struct ssb_bus *bus,
225				 unsigned long baseaddr)
226{
227	void __iomem *mmio = NULL;
228
229	switch (bus->bustype) {
230	case SSB_BUSTYPE_SSB:
231		/* Only map the first core for now. */
232		/* fallthrough... */
233	case SSB_BUSTYPE_PCMCIA:
234		mmio = ioremap(baseaddr, SSB_CORE_SIZE);
235		break;
236	case SSB_BUSTYPE_PCI:
237#ifdef CONFIG_SSB_PCIHOST
238		mmio = pci_iomap(bus->host_pci, 0, ~0UL);
239#else
240		SSB_BUG_ON(1); /* Can't reach this code. */
241#endif
242		break;
243	case SSB_BUSTYPE_SDIO:
244		/* Nothing to ioremap in the SDIO case, just fake it */
245		mmio = (void __iomem *)baseaddr;
246		break;
247	}
248
249	return mmio;
250}
251
252static int we_support_multiple_80211_cores(struct ssb_bus *bus)
253{
254	/* More than one 802.11 core is only supported by special chips.
255	 * There are chips with two 802.11 cores, but with dangling
256	 * pins on the second core. Be careful and reject them here.
257	 */
258
259#ifdef CONFIG_SSB_PCIHOST
260	if (bus->bustype == SSB_BUSTYPE_PCI) {
261		if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
262		    bus->host_pci->device == 0x4324)
263			return 1;
264	}
265#endif /* CONFIG_SSB_PCIHOST */
266	return 0;
267}
268
269int ssb_bus_scan(struct ssb_bus *bus,
270		 unsigned long baseaddr)
271{
272	int err = -ENOMEM;
273	void __iomem *mmio;
274	u32 idhi, cc, rev, tmp;
275	int dev_i, i;
276	struct ssb_device *dev;
277	int nr_80211_cores = 0;
278
279	mmio = ssb_ioremap(bus, baseaddr);
280	if (!mmio)
281		goto out;
282	bus->mmio = mmio;
283
284	err = scan_switchcore(bus, 0); /* Switch to first core */
285	if (err)
286		goto err_unmap;
287
288	idhi = scan_read32(bus, 0, SSB_IDHIGH);
289	cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
290	rev = (idhi & SSB_IDHIGH_RCLO);
291	rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
292
293	bus->nr_devices = 0;
294	if (cc == SSB_DEV_CHIPCOMMON) {
295		tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID);
296
297		bus->chip_id = (tmp & SSB_CHIPCO_IDMASK);
298		bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >>
299				SSB_CHIPCO_REVSHIFT;
300		bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >>
301				    SSB_CHIPCO_PACKSHIFT;
302		if (rev >= 4) {
303			bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >>
304					  SSB_CHIPCO_NRCORESSHIFT;
305		}
306		tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
307		bus->chipco.capabilities = tmp;
308	} else {
309		if (bus->bustype == SSB_BUSTYPE_PCI) {
310			bus->chip_id = pcidev_to_chipid(bus->host_pci);
311			pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
312					     &bus->chip_rev);
313			bus->chip_package = 0;
314		} else {
315			bus->chip_id = 0x4710;
316			bus->chip_rev = 0;
317			bus->chip_package = 0;
318		}
319	}
320	if (!bus->nr_devices)
321		bus->nr_devices = chipid_to_nrcores(bus->chip_id);
322	if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
323		ssb_printk(KERN_ERR PFX
324			   "More than %d ssb cores found (%d)\n",
325			   SSB_MAX_NR_CORES, bus->nr_devices);
326		goto err_unmap;
327	}
328	if (bus->bustype == SSB_BUSTYPE_SSB) {
329		/* Now that we know the number of cores,
330		 * remap the whole IO space for all cores.
331		 */
332		err = -ENOMEM;
333		iounmap(mmio);
334		mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices);
335		if (!mmio)
336			goto out;
337		bus->mmio = mmio;
338	}
339
340	/* Fetch basic information about each core/device */
341	for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {
342		err = scan_switchcore(bus, i);
343		if (err)
344			goto err_unmap;
345		dev = &(bus->devices[dev_i]);
346
347		idhi = scan_read32(bus, i, SSB_IDHIGH);
348		dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
349		dev->id.revision = (idhi & SSB_IDHIGH_RCLO);
350		dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
351		dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;
352		dev->core_index = i;
353		dev->bus = bus;
354		dev->ops = bus->ops;
355
356		printk(KERN_DEBUG PFX
357			    "Core %d found: %s "
358			    "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
359			    i, ssb_core_name(dev->id.coreid),
360			    dev->id.coreid, dev->id.revision, dev->id.vendor);
361
362		switch (dev->id.coreid) {
363		case SSB_DEV_80211:
364			nr_80211_cores++;
365			if (nr_80211_cores > 1) {
366				if (!we_support_multiple_80211_cores(bus)) {
367					ssb_dprintk(KERN_INFO PFX "Ignoring additional "
368						    "802.11 core\n");
369					continue;
370				}
371			}
372			break;
373		case SSB_DEV_EXTIF:
374#ifdef CONFIG_SSB_DRIVER_EXTIF
375			if (bus->extif.dev) {
376				ssb_printk(KERN_WARNING PFX
377					   "WARNING: Multiple EXTIFs found\n");
378				break;
379			}
380			bus->extif.dev = dev;
381#endif /* CONFIG_SSB_DRIVER_EXTIF */
382			break;
383		case SSB_DEV_CHIPCOMMON:
384			if (bus->chipco.dev) {
385				ssb_printk(KERN_WARNING PFX
386					   "WARNING: Multiple ChipCommon found\n");
387				break;
388			}
389			bus->chipco.dev = dev;
390			break;
391		case SSB_DEV_MIPS:
392		case SSB_DEV_MIPS_3302:
393#ifdef CONFIG_SSB_DRIVER_MIPS
394			if (bus->mipscore.dev) {
395				ssb_printk(KERN_WARNING PFX
396					   "WARNING: Multiple MIPS cores found\n");
397				break;
398			}
399			bus->mipscore.dev = dev;
400#endif /* CONFIG_SSB_DRIVER_MIPS */
401			break;
402		case SSB_DEV_PCI:
403		case SSB_DEV_PCIE:
404#ifdef CONFIG_SSB_DRIVER_PCICORE
405			if (bus->bustype == SSB_BUSTYPE_PCI) {
406				/* Ignore PCI cores on PCI-E cards.
407				 * Ignore PCI-E cores on PCI cards. */
408				if (dev->id.coreid == SSB_DEV_PCI) {
409					if (bus->host_pci->is_pcie)
410						continue;
411				} else {
412					if (!bus->host_pci->is_pcie)
413						continue;
414				}
415			}
416			if (bus->pcicore.dev) {
417				ssb_printk(KERN_WARNING PFX
418					   "WARNING: Multiple PCI(E) cores found\n");
419				break;
420			}
421			bus->pcicore.dev = dev;
422#endif /* CONFIG_SSB_DRIVER_PCICORE */
423			break;
424		default:
425			break;
426		}
427
428		dev_i++;
429	}
430	bus->nr_devices = dev_i;
431
432	err = 0;
433out:
434	return err;
435err_unmap:
436	ssb_iounmap(bus);
437	goto out;
438}
439