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