Root/
1 | /* |
2 | * Broadcom specific AMBA |
3 | * Bus subsystem |
4 | * |
5 | * Licensed under the GNU/GPL. See COPYING for details. |
6 | */ |
7 | |
8 | #include "bcma_private.h" |
9 | #include <linux/module.h> |
10 | #include <linux/platform_device.h> |
11 | #include <linux/bcma/bcma.h> |
12 | #include <linux/slab.h> |
13 | |
14 | MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); |
15 | MODULE_LICENSE("GPL"); |
16 | |
17 | /* contains the number the next bus should get. */ |
18 | static unsigned int bcma_bus_next_num = 0; |
19 | |
20 | /* bcma_buses_mutex locks the bcma_bus_next_num */ |
21 | static DEFINE_MUTEX(bcma_buses_mutex); |
22 | |
23 | static int bcma_bus_match(struct device *dev, struct device_driver *drv); |
24 | static int bcma_device_probe(struct device *dev); |
25 | static int bcma_device_remove(struct device *dev); |
26 | static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env); |
27 | |
28 | static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf) |
29 | { |
30 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
31 | return sprintf(buf, "0x%03X\n", core->id.manuf); |
32 | } |
33 | static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) |
34 | { |
35 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
36 | return sprintf(buf, "0x%03X\n", core->id.id); |
37 | } |
38 | static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf) |
39 | { |
40 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
41 | return sprintf(buf, "0x%02X\n", core->id.rev); |
42 | } |
43 | static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf) |
44 | { |
45 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
46 | return sprintf(buf, "0x%X\n", core->id.class); |
47 | } |
48 | static struct device_attribute bcma_device_attrs[] = { |
49 | __ATTR_RO(manuf), |
50 | __ATTR_RO(id), |
51 | __ATTR_RO(rev), |
52 | __ATTR_RO(class), |
53 | __ATTR_NULL, |
54 | }; |
55 | |
56 | static struct bus_type bcma_bus_type = { |
57 | .name = "bcma", |
58 | .match = bcma_bus_match, |
59 | .probe = bcma_device_probe, |
60 | .remove = bcma_device_remove, |
61 | .uevent = bcma_device_uevent, |
62 | .dev_attrs = bcma_device_attrs, |
63 | }; |
64 | |
65 | static u16 bcma_cc_core_id(struct bcma_bus *bus) |
66 | { |
67 | if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) |
68 | return BCMA_CORE_4706_CHIPCOMMON; |
69 | return BCMA_CORE_CHIPCOMMON; |
70 | } |
71 | |
72 | struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid) |
73 | { |
74 | struct bcma_device *core; |
75 | |
76 | list_for_each_entry(core, &bus->cores, list) { |
77 | if (core->id.id == coreid) |
78 | return core; |
79 | } |
80 | return NULL; |
81 | } |
82 | EXPORT_SYMBOL_GPL(bcma_find_core); |
83 | |
84 | struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid, |
85 | u8 unit) |
86 | { |
87 | struct bcma_device *core; |
88 | |
89 | list_for_each_entry(core, &bus->cores, list) { |
90 | if (core->id.id == coreid && core->core_unit == unit) |
91 | return core; |
92 | } |
93 | return NULL; |
94 | } |
95 | |
96 | static void bcma_release_core_dev(struct device *dev) |
97 | { |
98 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
99 | if (core->io_addr) |
100 | iounmap(core->io_addr); |
101 | if (core->io_wrap) |
102 | iounmap(core->io_wrap); |
103 | kfree(core); |
104 | } |
105 | |
106 | static int bcma_register_cores(struct bcma_bus *bus) |
107 | { |
108 | struct bcma_device *core; |
109 | int err, dev_id = 0; |
110 | |
111 | list_for_each_entry(core, &bus->cores, list) { |
112 | /* We support that cores ourself */ |
113 | switch (core->id.id) { |
114 | case BCMA_CORE_4706_CHIPCOMMON: |
115 | case BCMA_CORE_CHIPCOMMON: |
116 | case BCMA_CORE_PCI: |
117 | case BCMA_CORE_PCIE: |
118 | case BCMA_CORE_MIPS_74K: |
119 | case BCMA_CORE_4706_MAC_GBIT_COMMON: |
120 | continue; |
121 | } |
122 | |
123 | core->dev.release = bcma_release_core_dev; |
124 | core->dev.bus = &bcma_bus_type; |
125 | dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id); |
126 | |
127 | switch (bus->hosttype) { |
128 | case BCMA_HOSTTYPE_PCI: |
129 | core->dev.parent = &bus->host_pci->dev; |
130 | core->dma_dev = &bus->host_pci->dev; |
131 | core->irq = bus->host_pci->irq; |
132 | break; |
133 | case BCMA_HOSTTYPE_SOC: |
134 | core->dev.dma_mask = &core->dev.coherent_dma_mask; |
135 | core->dma_dev = &core->dev; |
136 | break; |
137 | case BCMA_HOSTTYPE_SDIO: |
138 | break; |
139 | } |
140 | |
141 | err = device_register(&core->dev); |
142 | if (err) { |
143 | bcma_err(bus, |
144 | "Could not register dev for core 0x%03X\n", |
145 | core->id.id); |
146 | continue; |
147 | } |
148 | core->dev_registered = true; |
149 | dev_id++; |
150 | } |
151 | |
152 | #ifdef CONFIG_BCMA_DRIVER_MIPS |
153 | if (bus->drv_cc.pflash.present) { |
154 | err = platform_device_register(&bcma_pflash_dev); |
155 | if (err) |
156 | bcma_err(bus, "Error registering parallel flash\n"); |
157 | } |
158 | #endif |
159 | |
160 | #ifdef CONFIG_BCMA_SFLASH |
161 | if (bus->drv_cc.sflash.present) { |
162 | err = platform_device_register(&bcma_sflash_dev); |
163 | if (err) |
164 | bcma_err(bus, "Error registering serial flash\n"); |
165 | } |
166 | #endif |
167 | |
168 | #ifdef CONFIG_BCMA_NFLASH |
169 | if (bus->drv_cc.nflash.present) { |
170 | err = platform_device_register(&bcma_nflash_dev); |
171 | if (err) |
172 | bcma_err(bus, "Error registering NAND flash\n"); |
173 | } |
174 | #endif |
175 | err = bcma_gpio_init(&bus->drv_cc); |
176 | if (err == -ENOTSUPP) |
177 | bcma_debug(bus, "GPIO driver not activated\n"); |
178 | else if (err) |
179 | bcma_err(bus, "Error registering GPIO driver: %i\n", err); |
180 | |
181 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { |
182 | err = bcma_chipco_watchdog_register(&bus->drv_cc); |
183 | if (err) |
184 | bcma_err(bus, "Error registering watchdog driver\n"); |
185 | } |
186 | |
187 | return 0; |
188 | } |
189 | |
190 | static void bcma_unregister_cores(struct bcma_bus *bus) |
191 | { |
192 | struct bcma_device *core, *tmp; |
193 | |
194 | list_for_each_entry_safe(core, tmp, &bus->cores, list) { |
195 | list_del(&core->list); |
196 | if (core->dev_registered) |
197 | device_unregister(&core->dev); |
198 | } |
199 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) |
200 | platform_device_unregister(bus->drv_cc.watchdog); |
201 | } |
202 | |
203 | int bcma_bus_register(struct bcma_bus *bus) |
204 | { |
205 | int err; |
206 | struct bcma_device *core; |
207 | |
208 | mutex_lock(&bcma_buses_mutex); |
209 | bus->num = bcma_bus_next_num++; |
210 | mutex_unlock(&bcma_buses_mutex); |
211 | |
212 | /* Scan for devices (cores) */ |
213 | err = bcma_bus_scan(bus); |
214 | if (err) { |
215 | bcma_err(bus, "Failed to scan: %d\n", err); |
216 | return -1; |
217 | } |
218 | |
219 | /* Early init CC core */ |
220 | core = bcma_find_core(bus, bcma_cc_core_id(bus)); |
221 | if (core) { |
222 | bus->drv_cc.core = core; |
223 | bcma_core_chipcommon_early_init(&bus->drv_cc); |
224 | } |
225 | |
226 | /* Try to get SPROM */ |
227 | err = bcma_sprom_get(bus); |
228 | if (err == -ENOENT) { |
229 | bcma_err(bus, "No SPROM available\n"); |
230 | } else if (err) |
231 | bcma_err(bus, "Failed to get SPROM: %d\n", err); |
232 | |
233 | /* Init CC core */ |
234 | core = bcma_find_core(bus, bcma_cc_core_id(bus)); |
235 | if (core) { |
236 | bus->drv_cc.core = core; |
237 | bcma_core_chipcommon_init(&bus->drv_cc); |
238 | } |
239 | |
240 | /* Init MIPS core */ |
241 | core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); |
242 | if (core) { |
243 | bus->drv_mips.core = core; |
244 | bcma_core_mips_init(&bus->drv_mips); |
245 | } |
246 | |
247 | /* Init PCIE core */ |
248 | core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 0); |
249 | if (core) { |
250 | bus->drv_pci[0].core = core; |
251 | bcma_core_pci_init(&bus->drv_pci[0]); |
252 | } |
253 | |
254 | /* Init PCIE core */ |
255 | core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 1); |
256 | if (core) { |
257 | bus->drv_pci[1].core = core; |
258 | bcma_core_pci_init(&bus->drv_pci[1]); |
259 | } |
260 | |
261 | /* Init GBIT MAC COMMON core */ |
262 | core = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON); |
263 | if (core) { |
264 | bus->drv_gmac_cmn.core = core; |
265 | bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn); |
266 | } |
267 | |
268 | /* Register found cores */ |
269 | bcma_register_cores(bus); |
270 | |
271 | bcma_info(bus, "Bus registered\n"); |
272 | |
273 | return 0; |
274 | } |
275 | |
276 | void bcma_bus_unregister(struct bcma_bus *bus) |
277 | { |
278 | struct bcma_device *cores[3]; |
279 | int err; |
280 | |
281 | err = bcma_gpio_unregister(&bus->drv_cc); |
282 | if (err == -EBUSY) |
283 | bcma_err(bus, "Some GPIOs are still in use.\n"); |
284 | else if (err) |
285 | bcma_err(bus, "Can not unregister GPIO driver: %i\n", err); |
286 | |
287 | cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K); |
288 | cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE); |
289 | cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON); |
290 | |
291 | bcma_unregister_cores(bus); |
292 | |
293 | kfree(cores[2]); |
294 | kfree(cores[1]); |
295 | kfree(cores[0]); |
296 | } |
297 | |
298 | int __init bcma_bus_early_register(struct bcma_bus *bus, |
299 | struct bcma_device *core_cc, |
300 | struct bcma_device *core_mips) |
301 | { |
302 | int err; |
303 | struct bcma_device *core; |
304 | struct bcma_device_id match; |
305 | |
306 | bcma_init_bus(bus); |
307 | |
308 | match.manuf = BCMA_MANUF_BCM; |
309 | match.id = bcma_cc_core_id(bus); |
310 | match.class = BCMA_CL_SIM; |
311 | match.rev = BCMA_ANY_REV; |
312 | |
313 | /* Scan for chip common core */ |
314 | err = bcma_bus_scan_early(bus, &match, core_cc); |
315 | if (err) { |
316 | bcma_err(bus, "Failed to scan for common core: %d\n", err); |
317 | return -1; |
318 | } |
319 | |
320 | match.manuf = BCMA_MANUF_MIPS; |
321 | match.id = BCMA_CORE_MIPS_74K; |
322 | match.class = BCMA_CL_SIM; |
323 | match.rev = BCMA_ANY_REV; |
324 | |
325 | /* Scan for mips core */ |
326 | err = bcma_bus_scan_early(bus, &match, core_mips); |
327 | if (err) { |
328 | bcma_err(bus, "Failed to scan for mips core: %d\n", err); |
329 | return -1; |
330 | } |
331 | |
332 | /* Early init CC core */ |
333 | core = bcma_find_core(bus, bcma_cc_core_id(bus)); |
334 | if (core) { |
335 | bus->drv_cc.core = core; |
336 | bcma_core_chipcommon_early_init(&bus->drv_cc); |
337 | } |
338 | |
339 | /* Early init MIPS core */ |
340 | core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); |
341 | if (core) { |
342 | bus->drv_mips.core = core; |
343 | bcma_core_mips_early_init(&bus->drv_mips); |
344 | } |
345 | |
346 | bcma_info(bus, "Early bus registered\n"); |
347 | |
348 | return 0; |
349 | } |
350 | |
351 | #ifdef CONFIG_PM |
352 | int bcma_bus_suspend(struct bcma_bus *bus) |
353 | { |
354 | struct bcma_device *core; |
355 | |
356 | list_for_each_entry(core, &bus->cores, list) { |
357 | struct device_driver *drv = core->dev.driver; |
358 | if (drv) { |
359 | struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv); |
360 | if (adrv->suspend) |
361 | adrv->suspend(core); |
362 | } |
363 | } |
364 | return 0; |
365 | } |
366 | |
367 | int bcma_bus_resume(struct bcma_bus *bus) |
368 | { |
369 | struct bcma_device *core; |
370 | |
371 | /* Init CC core */ |
372 | if (bus->drv_cc.core) { |
373 | bus->drv_cc.setup_done = false; |
374 | bcma_core_chipcommon_init(&bus->drv_cc); |
375 | } |
376 | |
377 | list_for_each_entry(core, &bus->cores, list) { |
378 | struct device_driver *drv = core->dev.driver; |
379 | if (drv) { |
380 | struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv); |
381 | if (adrv->resume) |
382 | adrv->resume(core); |
383 | } |
384 | } |
385 | |
386 | return 0; |
387 | } |
388 | #endif |
389 | |
390 | int __bcma_driver_register(struct bcma_driver *drv, struct module *owner) |
391 | { |
392 | drv->drv.name = drv->name; |
393 | drv->drv.bus = &bcma_bus_type; |
394 | drv->drv.owner = owner; |
395 | |
396 | return driver_register(&drv->drv); |
397 | } |
398 | EXPORT_SYMBOL_GPL(__bcma_driver_register); |
399 | |
400 | void bcma_driver_unregister(struct bcma_driver *drv) |
401 | { |
402 | driver_unregister(&drv->drv); |
403 | } |
404 | EXPORT_SYMBOL_GPL(bcma_driver_unregister); |
405 | |
406 | static int bcma_bus_match(struct device *dev, struct device_driver *drv) |
407 | { |
408 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
409 | struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv); |
410 | const struct bcma_device_id *cid = &core->id; |
411 | const struct bcma_device_id *did; |
412 | |
413 | for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) { |
414 | if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) && |
415 | (did->id == cid->id || did->id == BCMA_ANY_ID) && |
416 | (did->rev == cid->rev || did->rev == BCMA_ANY_REV) && |
417 | (did->class == cid->class || did->class == BCMA_ANY_CLASS)) |
418 | return 1; |
419 | } |
420 | return 0; |
421 | } |
422 | |
423 | static int bcma_device_probe(struct device *dev) |
424 | { |
425 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
426 | struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver, |
427 | drv); |
428 | int err = 0; |
429 | |
430 | if (adrv->probe) |
431 | err = adrv->probe(core); |
432 | |
433 | return err; |
434 | } |
435 | |
436 | static int bcma_device_remove(struct device *dev) |
437 | { |
438 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
439 | struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver, |
440 | drv); |
441 | |
442 | if (adrv->remove) |
443 | adrv->remove(core); |
444 | |
445 | return 0; |
446 | } |
447 | |
448 | static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env) |
449 | { |
450 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
451 | |
452 | return add_uevent_var(env, |
453 | "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X", |
454 | core->id.manuf, core->id.id, |
455 | core->id.rev, core->id.class); |
456 | } |
457 | |
458 | static int __init bcma_modinit(void) |
459 | { |
460 | int err; |
461 | |
462 | err = bus_register(&bcma_bus_type); |
463 | if (err) |
464 | return err; |
465 | |
466 | #ifdef CONFIG_BCMA_HOST_PCI |
467 | err = bcma_host_pci_init(); |
468 | if (err) { |
469 | pr_err("PCI host initialization failed\n"); |
470 | err = 0; |
471 | } |
472 | #endif |
473 | |
474 | return err; |
475 | } |
476 | fs_initcall(bcma_modinit); |
477 | |
478 | static void __exit bcma_modexit(void) |
479 | { |
480 | #ifdef CONFIG_BCMA_HOST_PCI |
481 | bcma_host_pci_exit(); |
482 | #endif |
483 | bus_unregister(&bcma_bus_type); |
484 | } |
485 | module_exit(bcma_modexit) |
486 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9