aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ssb/scan.c
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2007-09-18 15:12:50 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:51:36 -0400
commit61e115a56d1aafd6e6a8a9fee8ac099a6128ac7b (patch)
treeadd97bf6a1207a4caea3a86cf13495ad3dc477de /drivers/ssb/scan.c
parent5ee3afba88f5a79d0bff07ddd87af45919259f91 (diff)
[SSB]: add Sonics Silicon Backplane bus support
SSB is an SoC bus used in a number of embedded devices. The most well-known of these devices is probably the Linksys WRT54G, but there are others as well. The bus is also used internally on the BCM43xx and BCM44xx devices from Broadcom. This patch also includes support for SSB ID tables in modules, so that SSB drivers can be loaded automatically. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/ssb/scan.c')
-rw-r--r--drivers/ssb/scan.c413
1 files changed, 413 insertions, 0 deletions
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
new file mode 100644
index 000000000000..96258c60919d
--- /dev/null
+++ b/drivers/ssb/scan.c
@@ -0,0 +1,413 @@
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_types.h>
21#include <pcmcia/cs.h>
22#include <pcmcia/cistpl.h>
23#include <pcmcia/ds.h>
24
25#include "ssb_private.h"
26
27
28const char *ssb_core_name(u16 coreid)
29{
30 switch (coreid) {
31 case SSB_DEV_CHIPCOMMON:
32 return "ChipCommon";
33 case SSB_DEV_ILINE20:
34 return "ILine 20";
35 case SSB_DEV_SDRAM:
36 return "SDRAM";
37 case SSB_DEV_PCI:
38 return "PCI";
39 case SSB_DEV_MIPS:
40 return "MIPS";
41 case SSB_DEV_ETHERNET:
42 return "Fast Ethernet";
43 case SSB_DEV_V90:
44 return "V90";
45 case SSB_DEV_USB11_HOSTDEV:
46 return "USB 1.1 Hostdev";
47 case SSB_DEV_ADSL:
48 return "ADSL";
49 case SSB_DEV_ILINE100:
50 return "ILine 100";
51 case SSB_DEV_IPSEC:
52 return "IPSEC";
53 case SSB_DEV_PCMCIA:
54 return "PCMCIA";
55 case SSB_DEV_INTERNAL_MEM:
56 return "Internal Memory";
57 case SSB_DEV_MEMC_SDRAM:
58 return "MEMC SDRAM";
59 case SSB_DEV_EXTIF:
60 return "EXTIF";
61 case SSB_DEV_80211:
62 return "IEEE 802.11";
63 case SSB_DEV_MIPS_3302:
64 return "MIPS 3302";
65 case SSB_DEV_USB11_HOST:
66 return "USB 1.1 Host";
67 case SSB_DEV_USB11_DEV:
68 return "USB 1.1 Device";
69 case SSB_DEV_USB20_HOST:
70 return "USB 2.0 Host";
71 case SSB_DEV_USB20_DEV:
72 return "USB 2.0 Device";
73 case SSB_DEV_SDIO_HOST:
74 return "SDIO Host";
75 case SSB_DEV_ROBOSWITCH:
76 return "Roboswitch";
77 case SSB_DEV_PARA_ATA:
78 return "PATA";
79 case SSB_DEV_SATA_XORDMA:
80 return "SATA XOR-DMA";
81 case SSB_DEV_ETHERNET_GBIT:
82 return "GBit Ethernet";
83 case SSB_DEV_PCIE:
84 return "PCI-E";
85 case SSB_DEV_MIMO_PHY:
86 return "MIMO PHY";
87 case SSB_DEV_SRAM_CTRLR:
88 return "SRAM Controller";
89 case SSB_DEV_MINI_MACPHY:
90 return "Mini MACPHY";
91 case SSB_DEV_ARM_1176:
92 return "ARM 1176";
93 case SSB_DEV_ARM_7TDMI:
94 return "ARM 7TDMI";
95 }
96 return "UNKNOWN";
97}
98
99static u16 pcidev_to_chipid(struct pci_dev *pci_dev)
100{
101 u16 chipid_fallback = 0;
102
103 switch (pci_dev->device) {
104 case 0x4301:
105 chipid_fallback = 0x4301;
106 break;
107 case 0x4305 ... 0x4307:
108 chipid_fallback = 0x4307;
109 break;
110 case 0x4403:
111 chipid_fallback = 0x4402;
112 break;
113 case 0x4610 ... 0x4615:
114 chipid_fallback = 0x4610;
115 break;
116 case 0x4710 ... 0x4715:
117 chipid_fallback = 0x4710;
118 break;
119 case 0x4320 ... 0x4325:
120 chipid_fallback = 0x4309;
121 break;
122 case PCI_DEVICE_ID_BCM4401:
123 case PCI_DEVICE_ID_BCM4401B0:
124 case PCI_DEVICE_ID_BCM4401B1:
125 chipid_fallback = 0x4401;
126 break;
127 default:
128 ssb_printk(KERN_ERR PFX
129 "PCI-ID not in fallback list\n");
130 }
131
132 return chipid_fallback;
133}
134
135static u8 chipid_to_nrcores(u16 chipid)
136{
137 switch (chipid) {
138 case 0x5365:
139 return 7;
140 case 0x4306:
141 return 6;
142 case 0x4310:
143 return 8;
144 case 0x4307:
145 case 0x4301:
146 return 5;
147 case 0x4401:
148 case 0x4402:
149 return 3;
150 case 0x4710:
151 case 0x4610:
152 case 0x4704:
153 return 9;
154 default:
155 ssb_printk(KERN_ERR PFX
156 "CHIPID not in nrcores fallback list\n");
157 }
158
159 return 1;
160}
161
162static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx,
163 u16 offset)
164{
165 switch (bus->bustype) {
166 case SSB_BUSTYPE_SSB:
167 offset += current_coreidx * SSB_CORE_SIZE;
168 break;
169 case SSB_BUSTYPE_PCI:
170 break;
171 case SSB_BUSTYPE_PCMCIA:
172 if (offset >= 0x800) {
173 ssb_pcmcia_switch_segment(bus, 1);
174 offset -= 0x800;
175 } else
176 ssb_pcmcia_switch_segment(bus, 0);
177 break;
178 }
179 return readl(bus->mmio + offset);
180}
181
182static int scan_switchcore(struct ssb_bus *bus, u8 coreidx)
183{
184 switch (bus->bustype) {
185 case SSB_BUSTYPE_SSB:
186 break;
187 case SSB_BUSTYPE_PCI:
188 return ssb_pci_switch_coreidx(bus, coreidx);
189 case SSB_BUSTYPE_PCMCIA:
190 return ssb_pcmcia_switch_coreidx(bus, coreidx);
191 }
192 return 0;
193}
194
195void ssb_iounmap(struct ssb_bus *bus)
196{
197 switch (bus->bustype) {
198 case SSB_BUSTYPE_SSB:
199 case SSB_BUSTYPE_PCMCIA:
200 iounmap(bus->mmio);
201 break;
202 case SSB_BUSTYPE_PCI:
203#ifdef CONFIG_SSB_PCIHOST
204 pci_iounmap(bus->host_pci, bus->mmio);
205#else
206 SSB_BUG_ON(1); /* Can't reach this code. */
207#endif
208 break;
209 }
210 bus->mmio = NULL;
211 bus->mapped_device = NULL;
212}
213
214static void __iomem *ssb_ioremap(struct ssb_bus *bus,
215 unsigned long baseaddr)
216{
217 void __iomem *mmio = NULL;
218
219 switch (bus->bustype) {
220 case SSB_BUSTYPE_SSB:
221 /* Only map the first core for now. */
222 /* fallthrough... */
223 case SSB_BUSTYPE_PCMCIA:
224 mmio = ioremap(baseaddr, SSB_CORE_SIZE);
225 break;
226 case SSB_BUSTYPE_PCI:
227#ifdef CONFIG_SSB_PCIHOST
228 mmio = pci_iomap(bus->host_pci, 0, ~0UL);
229#else
230 SSB_BUG_ON(1); /* Can't reach this code. */
231#endif
232 break;
233 }
234
235 return mmio;
236}
237
238static int we_support_multiple_80211_cores(struct ssb_bus *bus)
239{
240 /* More than one 802.11 core is only supported by special chips.
241 * There are chips with two 802.11 cores, but with dangling
242 * pins on the second core. Be careful and reject them here.
243 */
244
245#ifdef CONFIG_SSB_PCIHOST
246 if (bus->bustype == SSB_BUSTYPE_PCI) {
247 if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
248 bus->host_pci->device == 0x4324)
249 return 1;
250 }
251#endif /* CONFIG_SSB_PCIHOST */
252 return 0;
253}
254
255int ssb_bus_scan(struct ssb_bus *bus,
256 unsigned long baseaddr)
257{
258 int err = -ENOMEM;
259 void __iomem *mmio;
260 u32 idhi, cc, rev, tmp;
261 int dev_i, i;
262 struct ssb_device *dev;
263 int nr_80211_cores = 0;
264
265 mmio = ssb_ioremap(bus, baseaddr);
266 if (!mmio)
267 goto out;
268 bus->mmio = mmio;
269
270 err = scan_switchcore(bus, 0); /* Switch to first core */
271 if (err)
272 goto err_unmap;
273
274 idhi = scan_read32(bus, 0, SSB_IDHIGH);
275 cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
276 rev = (idhi & SSB_IDHIGH_RCLO);
277 rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
278
279 bus->nr_devices = 0;
280 if (cc == SSB_DEV_CHIPCOMMON) {
281 tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID);
282
283 bus->chip_id = (tmp & SSB_CHIPCO_IDMASK);
284 bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >>
285 SSB_CHIPCO_REVSHIFT;
286 bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >>
287 SSB_CHIPCO_PACKSHIFT;
288 if (rev >= 4) {
289 bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >>
290 SSB_CHIPCO_NRCORESSHIFT;
291 }
292 tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
293 bus->chipco.capabilities = tmp;
294 } else {
295 if (bus->bustype == SSB_BUSTYPE_PCI) {
296 bus->chip_id = pcidev_to_chipid(bus->host_pci);
297 pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
298 &bus->chip_rev);
299 bus->chip_package = 0;
300 } else {
301 bus->chip_id = 0x4710;
302 bus->chip_rev = 0;
303 bus->chip_package = 0;
304 }
305 }
306 if (!bus->nr_devices)
307 bus->nr_devices = chipid_to_nrcores(bus->chip_id);
308 if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
309 ssb_printk(KERN_ERR PFX
310 "More than %d ssb cores found (%d)\n",
311 SSB_MAX_NR_CORES, bus->nr_devices);
312 goto err_unmap;
313 }
314 if (bus->bustype == SSB_BUSTYPE_SSB) {
315 /* Now that we know the number of cores,
316 * remap the whole IO space for all cores.
317 */
318 err = -ENOMEM;
319 iounmap(mmio);
320 mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices);
321 if (!mmio)
322 goto out;
323 bus->mmio = mmio;
324 }
325
326 /* Fetch basic information about each core/device */
327 for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {
328 err = scan_switchcore(bus, i);
329 if (err)
330 goto err_unmap;
331 dev = &(bus->devices[dev_i]);
332
333 idhi = scan_read32(bus, i, SSB_IDHIGH);
334 dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
335 dev->id.revision = (idhi & SSB_IDHIGH_RCLO);
336 dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
337 dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;
338 dev->core_index = i;
339 dev->bus = bus;
340 dev->ops = bus->ops;
341
342 ssb_dprintk(KERN_INFO PFX
343 "Core %d found: %s "
344 "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
345 i, ssb_core_name(dev->id.coreid),
346 dev->id.coreid, dev->id.revision, dev->id.vendor);
347
348 switch (dev->id.coreid) {
349 case SSB_DEV_80211:
350 nr_80211_cores++;
351 if (nr_80211_cores > 1) {
352 if (!we_support_multiple_80211_cores(bus)) {
353 ssb_dprintk(KERN_INFO PFX "Ignoring additional "
354 "802.11 core\n");
355 continue;
356 }
357 }
358 break;
359 case SSB_DEV_EXTIF:
360#ifdef CONFIG_SSB_DRIVER_EXTIF
361 if (bus->extif.dev) {
362 ssb_printk(KERN_WARNING PFX
363 "WARNING: Multiple EXTIFs found\n");
364 break;
365 }
366 bus->extif.dev = dev;
367#endif /* CONFIG_SSB_DRIVER_EXTIF */
368 break;
369 case SSB_DEV_CHIPCOMMON:
370 if (bus->chipco.dev) {
371 ssb_printk(KERN_WARNING PFX
372 "WARNING: Multiple ChipCommon found\n");
373 break;
374 }
375 bus->chipco.dev = dev;
376 break;
377 case SSB_DEV_MIPS:
378 case SSB_DEV_MIPS_3302:
379#ifdef CONFIG_SSB_DRIVER_MIPS
380 if (bus->mipscore.dev) {
381 ssb_printk(KERN_WARNING PFX
382 "WARNING: Multiple MIPS cores found\n");
383 break;
384 }
385 bus->mipscore.dev = dev;
386#endif /* CONFIG_SSB_DRIVER_MIPS */
387 break;
388 case SSB_DEV_PCI:
389 case SSB_DEV_PCIE:
390#ifdef CONFIG_SSB_DRIVER_PCICORE
391 if (bus->pcicore.dev) {
392 ssb_printk(KERN_WARNING PFX
393 "WARNING: Multiple PCI(E) cores found\n");
394 break;
395 }
396 bus->pcicore.dev = dev;
397#endif /* CONFIG_SSB_DRIVER_PCICORE */
398 break;
399 default:
400 break;
401 }
402
403 dev_i++;
404 }
405 bus->nr_devices = dev_i;
406
407 err = 0;
408out:
409 return err;
410err_unmap:
411 ssb_iounmap(bus);
412 goto out;
413}