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