]> Pileus Git - ~andy/linux/blob - drivers/bcma/scan.c
5672b13d09516f0b257b7c3f704c868c8c5c30c4
[~andy/linux] / drivers / bcma / scan.c
1 /*
2  * Broadcom specific AMBA
3  * Bus scanning
4  *
5  * Licensed under the GNU/GPL. See COPYING for details.
6  */
7
8 #include "scan.h"
9 #include "bcma_private.h"
10
11 #include <linux/bcma/bcma.h>
12 #include <linux/bcma/bcma_regs.h>
13 #include <linux/pci.h>
14 #include <linux/io.h>
15 #include <linux/dma-mapping.h>
16 #include <linux/slab.h>
17
18 struct bcma_device_id_name {
19         u16 id;
20         const char *name;
21 };
22
23 static const struct bcma_device_id_name bcma_arm_device_names[] = {
24         { BCMA_CORE_4706_MAC_GBIT_COMMON, "BCM4706 GBit MAC Common" },
25         { BCMA_CORE_ARM_1176, "ARM 1176" },
26         { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
27         { BCMA_CORE_ARM_CM3, "ARM CM3" },
28 };
29
30 static const struct bcma_device_id_name bcma_bcm_device_names[] = {
31         { BCMA_CORE_OOB_ROUTER, "OOB Router" },
32         { BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" },
33         { BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" },
34         { BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" },
35         { BCMA_CORE_AMEMC, "AMEMC (DDR)" },
36         { BCMA_CORE_ALTA, "ALTA (I2S)" },
37         { BCMA_CORE_INVALID, "Invalid" },
38         { BCMA_CORE_CHIPCOMMON, "ChipCommon" },
39         { BCMA_CORE_ILINE20, "ILine 20" },
40         { BCMA_CORE_SRAM, "SRAM" },
41         { BCMA_CORE_SDRAM, "SDRAM" },
42         { BCMA_CORE_PCI, "PCI" },
43         { BCMA_CORE_ETHERNET, "Fast Ethernet" },
44         { BCMA_CORE_V90, "V90" },
45         { BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" },
46         { BCMA_CORE_ADSL, "ADSL" },
47         { BCMA_CORE_ILINE100, "ILine 100" },
48         { BCMA_CORE_IPSEC, "IPSEC" },
49         { BCMA_CORE_UTOPIA, "UTOPIA" },
50         { BCMA_CORE_PCMCIA, "PCMCIA" },
51         { BCMA_CORE_INTERNAL_MEM, "Internal Memory" },
52         { BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" },
53         { BCMA_CORE_OFDM, "OFDM" },
54         { BCMA_CORE_EXTIF, "EXTIF" },
55         { BCMA_CORE_80211, "IEEE 802.11" },
56         { BCMA_CORE_PHY_A, "PHY A" },
57         { BCMA_CORE_PHY_B, "PHY B" },
58         { BCMA_CORE_PHY_G, "PHY G" },
59         { BCMA_CORE_USB11_HOST, "USB 1.1 Host" },
60         { BCMA_CORE_USB11_DEV, "USB 1.1 Device" },
61         { BCMA_CORE_USB20_HOST, "USB 2.0 Host" },
62         { BCMA_CORE_USB20_DEV, "USB 2.0 Device" },
63         { BCMA_CORE_SDIO_HOST, "SDIO Host" },
64         { BCMA_CORE_ROBOSWITCH, "Roboswitch" },
65         { BCMA_CORE_PARA_ATA, "PATA" },
66         { BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" },
67         { BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" },
68         { BCMA_CORE_PCIE, "PCIe" },
69         { BCMA_CORE_PHY_N, "PHY N" },
70         { BCMA_CORE_SRAM_CTL, "SRAM Controller" },
71         { BCMA_CORE_MINI_MACPHY, "Mini MACPHY" },
72         { BCMA_CORE_PHY_LP, "PHY LP" },
73         { BCMA_CORE_PMU, "PMU" },
74         { BCMA_CORE_PHY_SSN, "PHY SSN" },
75         { BCMA_CORE_SDIO_DEV, "SDIO Device" },
76         { BCMA_CORE_PHY_HT, "PHY HT" },
77         { BCMA_CORE_MAC_GBIT, "GBit MAC" },
78         { BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" },
79         { BCMA_CORE_PCIE_RC, "PCIe Root Complex" },
80         { BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" },
81         { BCMA_CORE_SHARED_COMMON, "Common Shared" },
82         { BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" },
83         { BCMA_CORE_SPI_HOST, "SPI Host" },
84         { BCMA_CORE_I2S, "I2S" },
85         { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
86         { BCMA_CORE_SHIM, "SHIM" },
87         { BCMA_CORE_DEFAULT, "Default" },
88 };
89
90 static const struct bcma_device_id_name bcma_mips_device_names[] = {
91         { BCMA_CORE_MIPS, "MIPS" },
92         { BCMA_CORE_MIPS_3302, "MIPS 3302" },
93         { BCMA_CORE_MIPS_74K, "MIPS 74K" },
94 };
95
96 static const char *bcma_device_name(const struct bcma_device_id *id)
97 {
98         const struct bcma_device_id_name *names;
99         int size, i;
100
101         /* search manufacturer specific names */
102         switch (id->manuf) {
103         case BCMA_MANUF_ARM:
104                 names = bcma_arm_device_names;
105                 size = ARRAY_SIZE(bcma_arm_device_names);
106                 break;
107         case BCMA_MANUF_BCM:
108                 names = bcma_bcm_device_names;
109                 size = ARRAY_SIZE(bcma_bcm_device_names);
110                 break;
111         case BCMA_MANUF_MIPS:
112                 names = bcma_mips_device_names;
113                 size = ARRAY_SIZE(bcma_mips_device_names);
114                 break;
115         default:
116                 return "UNKNOWN";
117         }
118
119         for (i = 0; i < size; i++) {
120                 if (names[i].id == id->id)
121                         return names[i].name;
122         }
123
124         return "UNKNOWN";
125 }
126
127 static u32 bcma_scan_read32(struct bcma_bus *bus, u8 current_coreidx,
128                        u16 offset)
129 {
130         return readl(bus->mmio + offset);
131 }
132
133 static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr)
134 {
135         if (bus->hosttype == BCMA_HOSTTYPE_PCI)
136                 pci_write_config_dword(bus->host_pci, BCMA_PCI_BAR0_WIN,
137                                        addr);
138 }
139
140 static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 **eromptr)
141 {
142         u32 ent = readl(*eromptr);
143         (*eromptr)++;
144         return ent;
145 }
146
147 static void bcma_erom_push_ent(u32 **eromptr)
148 {
149         (*eromptr)--;
150 }
151
152 static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr)
153 {
154         u32 ent = bcma_erom_get_ent(bus, eromptr);
155         if (!(ent & SCAN_ER_VALID))
156                 return -ENOENT;
157         if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI)
158                 return -ENOENT;
159         return ent;
160 }
161
162 static bool bcma_erom_is_end(struct bcma_bus *bus, u32 **eromptr)
163 {
164         u32 ent = bcma_erom_get_ent(bus, eromptr);
165         bcma_erom_push_ent(eromptr);
166         return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID));
167 }
168
169 static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr)
170 {
171         u32 ent = bcma_erom_get_ent(bus, eromptr);
172         bcma_erom_push_ent(eromptr);
173         return (((ent & SCAN_ER_VALID)) &&
174                 ((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) &&
175                 ((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
176 }
177
178 static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr)
179 {
180         u32 ent;
181         while (1) {
182                 ent = bcma_erom_get_ent(bus, eromptr);
183                 if ((ent & SCAN_ER_VALID) &&
184                     ((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI))
185                         break;
186                 if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID))
187                         break;
188         }
189         bcma_erom_push_ent(eromptr);
190 }
191
192 static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr)
193 {
194         u32 ent = bcma_erom_get_ent(bus, eromptr);
195         if (!(ent & SCAN_ER_VALID))
196                 return -ENOENT;
197         if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP)
198                 return -ENOENT;
199         return ent;
200 }
201
202 static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
203                                   u32 type, u8 port)
204 {
205         u32 addrl, addrh, sizel, sizeh = 0;
206         u32 size;
207
208         u32 ent = bcma_erom_get_ent(bus, eromptr);
209         if ((!(ent & SCAN_ER_VALID)) ||
210             ((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) ||
211             ((ent & SCAN_ADDR_TYPE) != type) ||
212             (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) {
213                 bcma_erom_push_ent(eromptr);
214                 return -EINVAL;
215         }
216
217         addrl = ent & SCAN_ADDR_ADDR;
218         if (ent & SCAN_ADDR_AG32)
219                 addrh = bcma_erom_get_ent(bus, eromptr);
220         else
221                 addrh = 0;
222
223         if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) {
224                 size = bcma_erom_get_ent(bus, eromptr);
225                 sizel = size & SCAN_SIZE_SZ;
226                 if (size & SCAN_SIZE_SG32)
227                         sizeh = bcma_erom_get_ent(bus, eromptr);
228         } else
229                 sizel = SCAN_ADDR_SZ_BASE <<
230                                 ((ent & SCAN_ADDR_SZ) >> SCAN_ADDR_SZ_SHIFT);
231
232         return addrl;
233 }
234
235 static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
236                                                    u16 index)
237 {
238         struct bcma_device *core;
239
240         list_for_each_entry(core, &bus->cores, list) {
241                 if (core->core_index == index)
242                         return core;
243         }
244         return NULL;
245 }
246
247 static struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 coreid)
248 {
249         struct bcma_device *core;
250
251         list_for_each_entry_reverse(core, &bus->cores, list) {
252                 if (core->id.id == coreid)
253                         return core;
254         }
255         return NULL;
256 }
257
258 static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
259                               struct bcma_device_id *match, int core_num,
260                               struct bcma_device *core)
261 {
262         s32 tmp;
263         u8 i, j;
264         s32 cia, cib;
265         u8 ports[2], wrappers[2];
266
267         /* get CIs */
268         cia = bcma_erom_get_ci(bus, eromptr);
269         if (cia < 0) {
270                 bcma_erom_push_ent(eromptr);
271                 if (bcma_erom_is_end(bus, eromptr))
272                         return -ESPIPE;
273                 return -EILSEQ;
274         }
275         cib = bcma_erom_get_ci(bus, eromptr);
276         if (cib < 0)
277                 return -EILSEQ;
278
279         /* parse CIs */
280         core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
281         core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
282         core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
283         ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
284         ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
285         wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
286         wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
287         core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
288
289         if (((core->id.manuf == BCMA_MANUF_ARM) &&
290              (core->id.id == 0xFFF)) ||
291             (ports[1] == 0)) {
292                 bcma_erom_skip_component(bus, eromptr);
293                 return -ENXIO;
294         }
295
296         /* check if component is a core at all */
297         if (wrappers[0] + wrappers[1] == 0) {
298                 /* Some specific cores don't need wrappers */
299                 switch (core->id.id) {
300                 case BCMA_CORE_4706_MAC_GBIT_COMMON:
301                 /* Not used yet: case BCMA_CORE_OOB_ROUTER: */
302                         break;
303                 default:
304                         bcma_erom_skip_component(bus, eromptr);
305                         return -ENXIO;
306                 }
307         }
308
309         if (bcma_erom_is_bridge(bus, eromptr)) {
310                 bcma_erom_skip_component(bus, eromptr);
311                 return -ENXIO;
312         }
313
314         if (bcma_find_core_by_index(bus, core_num)) {
315                 bcma_erom_skip_component(bus, eromptr);
316                 return -ENODEV;
317         }
318
319         if (match && ((match->manuf != BCMA_ANY_MANUF &&
320               match->manuf != core->id.manuf) ||
321              (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
322              (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
323              (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
324             )) {
325                 bcma_erom_skip_component(bus, eromptr);
326                 return -ENODEV;
327         }
328
329         /* get & parse master ports */
330         for (i = 0; i < ports[0]; i++) {
331                 s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
332                 if (mst_port_d < 0)
333                         return -EILSEQ;
334         }
335
336         /* First Slave Address Descriptor should be port 0:
337          * the main register space for the core
338          */
339         tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
340         if (tmp <= 0) {
341                 /* Try again to see if it is a bridge */
342                 tmp = bcma_erom_get_addr_desc(bus, eromptr,
343                                               SCAN_ADDR_TYPE_BRIDGE, 0);
344                 if (tmp <= 0) {
345                         return -EILSEQ;
346                 } else {
347                         bcma_info(bus, "Bridge found\n");
348                         return -ENXIO;
349                 }
350         }
351         core->addr = tmp;
352
353         /* get & parse slave ports */
354         for (i = 0; i < ports[1]; i++) {
355                 for (j = 0; ; j++) {
356                         tmp = bcma_erom_get_addr_desc(bus, eromptr,
357                                 SCAN_ADDR_TYPE_SLAVE, i);
358                         if (tmp < 0) {
359                                 /* no more entries for port _i_ */
360                                 /* pr_debug("erom: slave port %d "
361                                  * "has %d descriptors\n", i, j); */
362                                 break;
363                         } else {
364                                 if (i == 0 && j == 0)
365                                         core->addr1 = tmp;
366                         }
367                 }
368         }
369
370         /* get & parse master wrappers */
371         for (i = 0; i < wrappers[0]; i++) {
372                 for (j = 0; ; j++) {
373                         tmp = bcma_erom_get_addr_desc(bus, eromptr,
374                                 SCAN_ADDR_TYPE_MWRAP, i);
375                         if (tmp < 0) {
376                                 /* no more entries for port _i_ */
377                                 /* pr_debug("erom: master wrapper %d "
378                                  * "has %d descriptors\n", i, j); */
379                                 break;
380                         } else {
381                                 if (i == 0 && j == 0)
382                                         core->wrap = tmp;
383                         }
384                 }
385         }
386
387         /* get & parse slave wrappers */
388         for (i = 0; i < wrappers[1]; i++) {
389                 u8 hack = (ports[1] == 1) ? 0 : 1;
390                 for (j = 0; ; j++) {
391                         tmp = bcma_erom_get_addr_desc(bus, eromptr,
392                                 SCAN_ADDR_TYPE_SWRAP, i + hack);
393                         if (tmp < 0) {
394                                 /* no more entries for port _i_ */
395                                 /* pr_debug("erom: master wrapper %d "
396                                  * has %d descriptors\n", i, j); */
397                                 break;
398                         } else {
399                                 if (wrappers[0] == 0 && !i && !j)
400                                         core->wrap = tmp;
401                         }
402                 }
403         }
404         if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
405                 core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
406                 if (!core->io_addr)
407                         return -ENOMEM;
408                 core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
409                 if (!core->io_wrap) {
410                         iounmap(core->io_addr);
411                         return -ENOMEM;
412                 }
413         }
414         return 0;
415 }
416
417 void bcma_init_bus(struct bcma_bus *bus)
418 {
419         s32 tmp;
420         struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
421
422         if (bus->init_done)
423                 return;
424
425         INIT_LIST_HEAD(&bus->cores);
426         bus->nr_cores = 0;
427
428         bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
429
430         tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
431         chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
432         chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
433         chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
434         bcma_info(bus, "Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
435                   chipinfo->id, chipinfo->rev, chipinfo->pkg);
436
437         bus->init_done = true;
438 }
439
440 int bcma_bus_scan(struct bcma_bus *bus)
441 {
442         u32 erombase;
443         u32 __iomem *eromptr, *eromend;
444
445         int err, core_num = 0;
446
447         bcma_init_bus(bus);
448
449         erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
450         if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
451                 eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
452                 if (!eromptr)
453                         return -ENOMEM;
454         } else {
455                 eromptr = bus->mmio;
456         }
457
458         eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
459
460         bcma_scan_switch_core(bus, erombase);
461
462         while (eromptr < eromend) {
463                 struct bcma_device *other_core;
464                 struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
465                 if (!core)
466                         return -ENOMEM;
467                 INIT_LIST_HEAD(&core->list);
468                 core->bus = bus;
469
470                 err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
471                 if (err < 0) {
472                         kfree(core);
473                         if (err == -ENODEV) {
474                                 core_num++;
475                                 continue;
476                         } else if (err == -ENXIO) {
477                                 continue;
478                         } else if (err == -ESPIPE) {
479                                 break;
480                         }
481                         return err;
482                 }
483
484                 core->core_index = core_num++;
485                 bus->nr_cores++;
486                 other_core = bcma_find_core_reverse(bus, core->id.id);
487                 core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
488
489                 bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
490                           core->core_index, bcma_device_name(&core->id),
491                           core->id.manuf, core->id.id, core->id.rev,
492                           core->id.class);
493
494                 list_add_tail(&core->list, &bus->cores);
495         }
496
497         if (bus->hosttype == BCMA_HOSTTYPE_SOC)
498                 iounmap(eromptr);
499
500         return 0;
501 }
502
503 int __init bcma_bus_scan_early(struct bcma_bus *bus,
504                                struct bcma_device_id *match,
505                                struct bcma_device *core)
506 {
507         u32 erombase;
508         u32 __iomem *eromptr, *eromend;
509
510         int err = -ENODEV;
511         int core_num = 0;
512
513         erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
514         if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
515                 eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
516                 if (!eromptr)
517                         return -ENOMEM;
518         } else {
519                 eromptr = bus->mmio;
520         }
521
522         eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
523
524         bcma_scan_switch_core(bus, erombase);
525
526         while (eromptr < eromend) {
527                 memset(core, 0, sizeof(*core));
528                 INIT_LIST_HEAD(&core->list);
529                 core->bus = bus;
530
531                 err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
532                 if (err == -ENODEV) {
533                         core_num++;
534                         continue;
535                 } else if (err == -ENXIO)
536                         continue;
537                 else if (err == -ESPIPE)
538                         break;
539                 else if (err < 0)
540                         return err;
541
542                 core->core_index = core_num++;
543                 bus->nr_cores++;
544                 bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
545                           core->core_index, bcma_device_name(&core->id),
546                           core->id.manuf, core->id.id, core->id.rev,
547                           core->id.class);
548
549                 list_add_tail(&core->list, &bus->cores);
550                 err = 0;
551                 break;
552         }
553
554         if (bus->hosttype == BCMA_HOSTTYPE_SOC)
555                 iounmap(eromptr);
556
557         return err;
558 }