Blame view
arch/sparc/kernel/of_device_64.c
15.9 KB
a2bd4fd17
|
1 2 |
#include <linux/string.h> #include <linux/kernel.h> |
f85ff3056
|
3 |
#include <linux/of.h> |
a2bd4fd17
|
4 |
#include <linux/init.h> |
066bcaca5
|
5 |
#include <linux/export.h> |
a2bd4fd17
|
6 7 |
#include <linux/mod_devicetable.h> #include <linux/slab.h> |
3f23de10f
|
8 |
#include <linux/errno.h> |
c1b1a5f1f
|
9 |
#include <linux/irq.h> |
3f23de10f
|
10 11 |
#include <linux/of_device.h> #include <linux/of_platform.h> |
c2068dabe
|
12 |
#include <asm/spitfire.h> |
a2bd4fd17
|
13 |
|
c9f5b7e77
|
14 |
#include "of_device_common.h" |
3ca9fab41
|
15 16 17 |
void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name) { unsigned long ret = res->start + offset; |
6bda57365
|
18 |
struct resource *r; |
3ca9fab41
|
19 |
|
6bda57365
|
20 21 22 23 24 |
if (res->flags & IORESOURCE_MEM) r = request_mem_region(ret, size, name); else r = request_region(ret, size, name); if (!r) |
3ca9fab41
|
25 26 27 28 29 |
ret = 0; return (void __iomem *) ret; } EXPORT_SYMBOL(of_ioremap); |
e3a411a3d
|
30 |
void of_iounmap(struct resource *res, void __iomem *base, unsigned long size) |
3ca9fab41
|
31 |
{ |
e3a411a3d
|
32 33 34 35 |
if (res->flags & IORESOURCE_MEM) release_mem_region((unsigned long) base, size); else release_region((unsigned long) base, size); |
3ca9fab41
|
36 37 |
} EXPORT_SYMBOL(of_iounmap); |
cf44bbc26
|
38 39 40 41 42 43 |
/* * PCI bus specific translator */ static int of_bus_pci_match(struct device_node *np) { |
7ee766d8f
|
44 |
if (!strcmp(np->name, "pci")) { |
a165b4205
|
45 |
const char *model = of_get_property(np, "model", NULL); |
01f94c4a6
|
46 47 48 |
if (model && !strcmp(model, "SUNW,simba")) return 0; |
a83f98231
|
49 50 51 52 53 54 55 56 57 58 59 60 61 |
/* Do not do PCI specific frobbing if the * PCI bridge lacks a ranges property. We * want to pass it through up to the next * parent as-is, not with the PCI translate * method which chops off the top address cell. */ if (!of_find_property(np, "ranges", NULL)) return 0; return 1; } return 0; |
cf44bbc26
|
62 |
} |
01f94c4a6
|
63 64 |
static int of_bus_simba_match(struct device_node *np) { |
a165b4205
|
65 |
const char *model = of_get_property(np, "model", NULL); |
01f94c4a6
|
66 67 68 |
if (model && !strcmp(model, "SUNW,simba")) return 1; |
8c2786cfa
|
69 70 71 72 |
/* Treat PCI busses lacking ranges property just like * simba. */ |
7ee766d8f
|
73 |
if (!strcmp(np->name, "pci")) { |
8c2786cfa
|
74 75 76 |
if (!of_find_property(np, "ranges", NULL)) return 1; } |
01f94c4a6
|
77 78 79 80 81 82 83 84 |
return 0; } static int of_bus_simba_map(u32 *addr, const u32 *range, int na, int ns, int pna) { return 0; } |
cf44bbc26
|
85 86 87 88 89 90 91 92 |
static void of_bus_pci_count_cells(struct device_node *np, int *addrc, int *sizec) { if (addrc) *addrc = 3; if (sizec) *sizec = 2; } |
a83f98231
|
93 94 |
static int of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna) |
cf44bbc26
|
95 |
{ |
a83f98231
|
96 97 |
u32 result[OF_MAX_ADDR_CELLS]; int i; |
cf44bbc26
|
98 99 |
/* Check address type match */ |
4230fa3b8
|
100 101 102 103 104 105 106 107 108 109 110 |
if (!((addr[0] ^ range[0]) & 0x03000000)) goto type_match; /* Special exception, we can map a 64-bit address into * a 32-bit range. */ if ((addr[0] & 0x03000000) == 0x03000000 && (range[0] & 0x03000000) == 0x02000000) goto type_match; return -EINVAL; |
cf44bbc26
|
111 |
|
4230fa3b8
|
112 |
type_match: |
a83f98231
|
113 114 115 |
if (of_out_of_range(addr + 1, range + 1, range + na + pna, na - 1, ns)) return -EINVAL; |
cf44bbc26
|
116 |
|
a83f98231
|
117 118 |
/* Start with the parent range base. */ memcpy(result, range + na, pna * 4); |
cf44bbc26
|
119 |
|
a83f98231
|
120 121 122 123 124 125 126 127 128 |
/* Add in the child address offset, skipping high cell. */ for (i = 0; i < na - 1; i++) result[pna - 1 - i] += (addr[na - 1 - i] - range[na - 1 - i]); memcpy(addr, result, pna * 4); return 0; |
cf44bbc26
|
129 |
} |
e3c71a329
|
130 |
static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags) |
cf44bbc26
|
131 |
{ |
cf44bbc26
|
132 |
u32 w = addr[0]; |
e3c71a329
|
133 134 |
/* For PCI, we override whatever child busses may have used. */ flags = 0; |
cf44bbc26
|
135 136 137 |
switch((w >> 24) & 0x03) { case 0x01: flags |= IORESOURCE_IO; |
e3c71a329
|
138 |
break; |
cf44bbc26
|
139 140 141 |
case 0x02: /* 32 bits */ case 0x03: /* 64 bits */ flags |= IORESOURCE_MEM; |
e3c71a329
|
142 |
break; |
cf44bbc26
|
143 144 145 146 147 148 149 |
} if (w & 0x40000000) flags |= IORESOURCE_PREFETCH; return flags; } /* |
4130a4b20
|
150 151 152 153 154 155 156 157 158 |
* FHC/Central bus specific translator. * * This is just needed to hard-code the address and size cell * counts. 'fhc' and 'central' nodes lack the #address-cells and * #size-cells properties, and if you walk to the root on such * Enterprise boxes all you'll get is a #size-cells of 2 which is * not what we want to use. */ static int of_bus_fhc_match(struct device_node *np) |
cf44bbc26
|
159 |
{ |
4130a4b20
|
160 161 |
return !strcmp(np->name, "fhc") || !strcmp(np->name, "central"); |
cf44bbc26
|
162 |
} |
4130a4b20
|
163 |
#define of_bus_fhc_count_cells of_bus_sbus_count_cells |
cf44bbc26
|
164 165 166 167 168 169 170 171 172 173 174 175 176 |
/* * Array of bus specific translators */ static struct of_bus of_busses[] = { /* PCI */ { .name = "pci", .addr_prop_name = "assigned-addresses", .match = of_bus_pci_match, .count_cells = of_bus_pci_count_cells, .map = of_bus_pci_map, |
cf44bbc26
|
177 178 |
.get_flags = of_bus_pci_get_flags, }, |
01f94c4a6
|
179 180 181 182 183 184 185 186 187 |
/* SIMBA */ { .name = "simba", .addr_prop_name = "assigned-addresses", .match = of_bus_simba_match, .count_cells = of_bus_pci_count_cells, .map = of_bus_simba_map, .get_flags = of_bus_pci_get_flags, }, |
cf44bbc26
|
188 189 190 191 192 193 |
/* SBUS */ { .name = "sbus", .addr_prop_name = "reg", .match = of_bus_sbus_match, .count_cells = of_bus_sbus_count_cells, |
4130a4b20
|
194 195 196 197 198 199 200 201 202 203 204 |
.map = of_bus_default_map, .get_flags = of_bus_default_get_flags, }, /* FHC */ { .name = "fhc", .addr_prop_name = "reg", .match = of_bus_fhc_match, .count_cells = of_bus_fhc_count_cells, .map = of_bus_default_map, .get_flags = of_bus_default_get_flags, |
cf44bbc26
|
205 206 207 208 209 210 211 212 |
}, /* Default */ { .name = "default", .addr_prop_name = "reg", .match = NULL, .count_cells = of_bus_default_count_cells, .map = of_bus_default_map, |
cf44bbc26
|
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
.get_flags = of_bus_default_get_flags, }, }; static struct of_bus *of_match_bus(struct device_node *np) { int i; for (i = 0; i < ARRAY_SIZE(of_busses); i ++) if (!of_busses[i].match || of_busses[i].match(np)) return &of_busses[i]; BUG(); return NULL; } static int __init build_one_resource(struct device_node *parent, struct of_bus *bus, struct of_bus *pbus, u32 *addr, int na, int ns, int pna) { |
6a23acf39
|
234 |
const u32 *ranges; |
21cd88339
|
235 |
int rone, rlen; |
cf44bbc26
|
236 237 238 |
ranges = of_get_property(parent, "ranges", &rlen); if (ranges == NULL || rlen == 0) { |
a83f98231
|
239 240 241 242 243 244 245 246 247 248 |
u32 result[OF_MAX_ADDR_CELLS]; int i; memset(result, 0, pna * 4); for (i = 0; i < na; i++) result[pna - 1 - i] = addr[na - 1 - i]; memcpy(addr, result, pna * 4); return 0; |
cf44bbc26
|
249 250 251 252 253 254 |
} /* Now walk through the ranges */ rlen /= 4; rone = na + pna + ns; for (; rlen >= rone; rlen -= rone, ranges += rone) { |
a83f98231
|
255 256 |
if (!bus->map(addr, ranges, na, ns, pna)) return 0; |
cf44bbc26
|
257 |
} |
a83f98231
|
258 |
|
49d23cfce
|
259 260 261 262 263 264 |
/* When we miss an I/O space match on PCI, just pass it up * to the next PCI bridge and/or controller. */ if (!strcmp(bus->name, "pci") && (addr[0] & 0x03000000) == 0x01000000) return 0; |
a83f98231
|
265 266 267 268 269 |
return 1; } static int __init use_1to1_mapping(struct device_node *pp) { |
a83f98231
|
270 271 272 |
/* If we have a ranges property in the parent, use it. */ if (of_find_property(pp, "ranges", NULL) != NULL) return 0; |
cf44bbc26
|
273 |
|
a83f98231
|
274 275 |
/* If the parent is the dma node of an ISA bus, pass * the translation up to the root. |
5280267c1
|
276 277 278 279 280 281 |
* * Some SBUS devices use intermediate nodes to express * hierarchy within the device itself. These aren't * real bus nodes, and don't have a 'ranges' property. * But, we should still pass the translation work up * to the SBUS itself. |
a83f98231
|
282 |
*/ |
5280267c1
|
283 284 285 286 |
if (!strcmp(pp->name, "dma") || !strcmp(pp->name, "espdma") || !strcmp(pp->name, "ledma") || !strcmp(pp->name, "lebuffer")) |
a83f98231
|
287 |
return 0; |
8c2786cfa
|
288 289 290 291 |
/* Similarly for all PCI bridges, if we get this far * it lacks a ranges property, and this will include * cases like Simba. */ |
7ee766d8f
|
292 |
if (!strcmp(pp->name, "pci")) |
a83f98231
|
293 294 295 |
return 0; return 1; |
cf44bbc26
|
296 |
} |
a83f98231
|
297 |
static int of_resource_verbose; |
cd4cd7306
|
298 |
static void __init build_device_resources(struct platform_device *op, |
cf44bbc26
|
299 300 |
struct device *parent) { |
cd4cd7306
|
301 |
struct platform_device *p_op; |
cf44bbc26
|
302 303 304 |
struct of_bus *bus; int na, ns; int index, num_reg; |
6a23acf39
|
305 |
const void *preg; |
cf44bbc26
|
306 307 308 |
if (!parent) return; |
cd4cd7306
|
309 |
p_op = to_platform_device(parent); |
61c7a080a
|
310 311 |
bus = of_match_bus(p_op->dev.of_node); bus->count_cells(op->dev.of_node, &na, &ns); |
cf44bbc26
|
312 |
|
61c7a080a
|
313 |
preg = of_get_property(op->dev.of_node, bus->addr_prop_name, &num_reg); |
cf44bbc26
|
314 315 316 317 318 |
if (!preg || num_reg == 0) return; /* Convert to num-cells. */ num_reg /= 4; |
46ba6d7d8
|
319 |
/* Convert to num-entries. */ |
cf44bbc26
|
320 |
num_reg /= na + ns; |
e5dd42e4f
|
321 |
/* Prevent overrunning the op->resources[] array. */ |
46ba6d7d8
|
322 323 324 325 |
if (num_reg > PROMREG_MAX) { printk(KERN_WARNING "%s: Too many regs (%d), " "limiting to %d. ", |
61c7a080a
|
326 |
op->dev.of_node->full_name, num_reg, PROMREG_MAX); |
46ba6d7d8
|
327 328 |
num_reg = PROMREG_MAX; } |
1636f8ac2
|
329 330 |
op->resource = op->archdata.resource; op->num_resources = num_reg; |
cf44bbc26
|
331 332 333 |
for (index = 0; index < num_reg; index++) { struct resource *r = &op->resource[index]; u32 addr[OF_MAX_ADDR_CELLS]; |
6a23acf39
|
334 |
const u32 *reg = (preg + (index * ((na + ns) * 4))); |
61c7a080a
|
335 336 |
struct device_node *dp = op->dev.of_node; struct device_node *pp = p_op->dev.of_node; |
b85cdd490
|
337 |
struct of_bus *pbus, *dbus; |
cf44bbc26
|
338 339 340 341 342 343 |
u64 size, result = OF_BAD_ADDR; unsigned long flags; int dna, dns; int pna, pns; size = of_read_addr(reg + na, ns); |
cf44bbc26
|
344 |
memcpy(addr, reg, na * 4); |
e3c71a329
|
345 |
flags = bus->get_flags(addr, 0); |
a83f98231
|
346 |
if (use_1to1_mapping(pp)) { |
cf44bbc26
|
347 348 349 350 351 352 |
result = of_read_addr(addr, na); goto build_res; } dna = na; dns = ns; |
b85cdd490
|
353 |
dbus = bus; |
cf44bbc26
|
354 355 356 357 358 359 360 361 362 363 364 |
while (1) { dp = pp; pp = dp->parent; if (!pp) { result = of_read_addr(addr, dna); break; } pbus = of_match_bus(pp); pbus->count_cells(dp, &pna, &pns); |
b85cdd490
|
365 |
if (build_one_resource(dp, dbus, pbus, addr, |
a83f98231
|
366 |
dna, dns, pna)) |
cf44bbc26
|
367 |
break; |
e3c71a329
|
368 |
flags = pbus->get_flags(addr, flags); |
cf44bbc26
|
369 370 |
dna = pna; dns = pns; |
b85cdd490
|
371 |
dbus = pbus; |
cf44bbc26
|
372 373 374 375 |
} build_res: memset(r, 0, sizeof(*r)); |
a83f98231
|
376 377 |
if (of_resource_verbose) |
901811364
|
378 379 |
printk("%s reg[%d] -> %llx ", |
61c7a080a
|
380 |
op->dev.of_node->full_name, index, |
a83f98231
|
381 |
result); |
cf44bbc26
|
382 |
if (result != OF_BAD_ADDR) { |
1815aed5e
|
383 384 |
if (tlb_type == hypervisor) result &= 0x0fffffffffffffffUL; |
cf44bbc26
|
385 386 387 |
r->start = result; r->end = result + size - 1; r->flags = flags; |
cf44bbc26
|
388 |
} |
61c7a080a
|
389 |
r->name = op->dev.of_node->name; |
cf44bbc26
|
390 391 |
} } |
2b1e59787
|
392 393 |
static struct device_node * __init apply_interrupt_map(struct device_node *dp, struct device_node *pp, |
6a23acf39
|
394 |
const u32 *imap, int imlen, const u32 *imask, |
2b1e59787
|
395 396 397 398 399 400 |
unsigned int *irq_p) { struct device_node *cp; unsigned int irq = *irq_p; struct of_bus *bus; phandle handle; |
6a23acf39
|
401 |
const u32 *reg; |
2b1e59787
|
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
int na, num_reg, i; bus = of_match_bus(pp); bus->count_cells(dp, &na, NULL); reg = of_get_property(dp, "reg", &num_reg); if (!reg || !num_reg) return NULL; imlen /= ((na + 3) * 4); handle = 0; for (i = 0; i < imlen; i++) { int j; for (j = 0; j < na; j++) { if ((reg[j] & imask[j]) != imap[j]) goto next; } if (imap[na] == irq) { handle = imap[na + 1]; irq = imap[na + 2]; break; } next: imap += (na + 3); } |
46ba6d7d8
|
429 430 431 432 433 434 435 436 |
if (i == imlen) { /* Psycho and Sabre PCI controllers can have 'interrupt-map' * properties that do not include the on-board device * interrupts. Instead, the device's 'interrupts' property * is already a fully specified INO value. * * Handle this by deciding that, if we didn't get a * match in the parent's 'interrupt-map', and the |
25985edce
|
437 |
* parent is an IRQ translator, then use the parent as |
46ba6d7d8
|
438 439 440 441 |
* our IRQ controller. */ if (pp->irq_trans) return pp; |
2b1e59787
|
442 |
return NULL; |
46ba6d7d8
|
443 |
} |
2b1e59787
|
444 445 446 447 448 449 450 451 452 453 454 |
*irq_p = irq; cp = of_find_node_by_phandle(handle); return cp; } static unsigned int __init pci_irq_swizzle(struct device_node *dp, struct device_node *pp, unsigned int irq) { |
6a23acf39
|
455 |
const struct linux_prom_pci_registers *regs; |
bb4c18cbb
|
456 |
unsigned int bus, devfn, slot, ret; |
2b1e59787
|
457 458 459 460 461 462 463 |
if (irq < 1 || irq > 4) return irq; regs = of_get_property(dp, "reg", NULL); if (!regs) return irq; |
bb4c18cbb
|
464 |
bus = (regs->phys_hi >> 16) & 0xff; |
2b1e59787
|
465 466 |
devfn = (regs->phys_hi >> 8) & 0xff; slot = (devfn >> 3) & 0x1f; |
bb4c18cbb
|
467 468 469 470 471 472 473 474 475 476 477 |
if (pp->irq_trans) { /* Derived from Table 8-3, U2P User's Manual. This branch * is handling a PCI controller that lacks a proper set of * interrupt-map and interrupt-map-mask properties. The * Ultra-E450 is one example. * * The bit layout is BSSLL, where: * B: 0 on bus A, 1 on bus B * D: 2-bit slot number, derived from PCI device number as * (dev - 1) for bus A, or (dev - 2) for bus B * L: 2-bit line number |
bb4c18cbb
|
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
*/ if (bus & 0x80) { /* PBM-A */ bus = 0x00; slot = (slot - 1) << 2; } else { /* PBM-B */ bus = 0x10; slot = (slot - 2) << 2; } irq -= 1; ret = (bus | slot | irq); } else { /* Going through a PCI-PCI bridge that lacks a set of * interrupt-map and interrupt-map-mask properties. */ ret = ((irq - 1 + (slot & 3)) & 3) + 1; } |
2b1e59787
|
497 498 499 |
return ret; } |
a83f98231
|
500 |
static int of_irq_verbose; |
cd4cd7306
|
501 |
static unsigned int __init build_one_device_irq(struct platform_device *op, |
2b1e59787
|
502 503 504 |
struct device *parent, unsigned int irq) { |
61c7a080a
|
505 |
struct device_node *dp = op->dev.of_node; |
2b1e59787
|
506 507 |
struct device_node *pp, *ip; unsigned int orig_irq = irq; |
c1b1a5f1f
|
508 |
int nid; |
2b1e59787
|
509 510 511 512 513 514 515 |
if (irq == 0xffffffff) return irq; if (dp->irq_trans) { irq = dp->irq_trans->irq_build(dp, irq, dp->irq_trans->data); |
a83f98231
|
516 517 518 519 520 |
if (of_irq_verbose) printk("%s: direct translate %x --> %x ", dp->full_name, orig_irq, irq); |
c1b1a5f1f
|
521 |
goto out; |
2b1e59787
|
522 523 524 525 526 527 528 529 530 531 532 533 534 |
} /* Something more complicated. Walk up to the root, applying * interrupt-map or bus specific translations, until we hit * an IRQ translator. * * If we hit a bus type or situation we cannot handle, we * stop and assume that the original IRQ number was in a * format which has special meaning to it's immediate parent. */ pp = dp->parent; ip = NULL; while (pp) { |
6a23acf39
|
535 |
const void *imap, *imsk; |
2b1e59787
|
536 537 538 539 540 541 542 543 544 545 546 |
int imlen; imap = of_get_property(pp, "interrupt-map", &imlen); imsk = of_get_property(pp, "interrupt-map-mask", NULL); if (imap && imsk) { struct device_node *iret; int this_orig_irq = irq; iret = apply_interrupt_map(dp, pp, imap, imlen, imsk, &irq); |
a83f98231
|
547 548 549 550 |
if (of_irq_verbose) printk("%s: Apply [%s:%x] imap --> [%s:%x] ", |
61c7a080a
|
551 |
op->dev.of_node->full_name, |
a83f98231
|
552 553 |
pp->full_name, this_orig_irq, (iret ? iret->full_name : "NULL"), irq); |
2b1e59787
|
554 555 556 557 558 559 560 561 |
if (!iret) break; if (iret->irq_trans) { ip = iret; break; } } else { |
7ee766d8f
|
562 |
if (!strcmp(pp->name, "pci")) { |
2b1e59787
|
563 564 565 |
unsigned int this_orig_irq = irq; irq = pci_irq_swizzle(dp, pp, irq); |
a83f98231
|
566 567 568 569 |
if (of_irq_verbose) printk("%s: PCI swizzle [%s] " "%x --> %x ", |
61c7a080a
|
570 |
op->dev.of_node->full_name, |
a83f98231
|
571 572 |
pp->full_name, this_orig_irq, irq); |
2b1e59787
|
573 574 575 576 577 578 579 580 581 582 583 584 |
} if (pp->irq_trans) { ip = pp; break; } } dp = pp; pp = pp->parent; } if (!ip) return orig_irq; |
61c7a080a
|
585 |
irq = ip->irq_trans->irq_build(op->dev.of_node, irq, |
2b1e59787
|
586 |
ip->irq_trans->data); |
a83f98231
|
587 588 589 |
if (of_irq_verbose) printk("%s: Apply IRQ trans [%s] %x --> %x ", |
61c7a080a
|
590 |
op->dev.of_node->full_name, ip->full_name, orig_irq, irq); |
2b1e59787
|
591 |
|
c1b1a5f1f
|
592 593 594 |
out: nid = of_node_to_nid(dp); if (nid != -1) { |
fb1fece5d
|
595 |
cpumask_t numa_mask; |
c1b1a5f1f
|
596 |
|
fb1fece5d
|
597 |
cpumask_copy(&numa_mask, cpumask_of_node(nid)); |
0de26520c
|
598 |
irq_set_affinity(irq, &numa_mask); |
c1b1a5f1f
|
599 |
} |
2b1e59787
|
600 601 |
return irq; } |
cd4cd7306
|
602 |
static struct platform_device * __init scan_one_device(struct device_node *dp, |
cf44bbc26
|
603 604 |
struct device *parent) { |
cd4cd7306
|
605 |
struct platform_device *op = kzalloc(sizeof(*op), GFP_KERNEL); |
6a23acf39
|
606 |
const unsigned int *irq; |
3d6e47023
|
607 |
struct dev_archdata *sd; |
2b1e59787
|
608 |
int len, i; |
cf44bbc26
|
609 610 611 |
if (!op) return NULL; |
3d6e47023
|
612 |
sd = &op->dev.archdata; |
3d6e47023
|
613 |
sd->op = op; |
d706c1b05
|
614 |
op->dev.of_node = dp; |
cf44bbc26
|
615 |
|
cf44bbc26
|
616 |
irq = of_get_property(dp, "interrupts", &len); |
2b1e59787
|
617 |
if (irq) { |
1636f8ac2
|
618 |
op->archdata.num_irqs = len / 4; |
92d9091f3
|
619 620 |
/* Prevent overrunning the op->irqs[] array. */ |
1636f8ac2
|
621 |
if (op->archdata.num_irqs > PROMINTR_MAX) { |
92d9091f3
|
622 623 624 |
printk(KERN_WARNING "%s: Too many irqs (%d), " "limiting to %d. ", |
1636f8ac2
|
625 626 |
dp->full_name, op->archdata.num_irqs, PROMINTR_MAX); op->archdata.num_irqs = PROMINTR_MAX; |
92d9091f3
|
627 |
} |
1636f8ac2
|
628 |
memcpy(op->archdata.irqs, irq, op->archdata.num_irqs * 4); |
2b1e59787
|
629 |
} else { |
1636f8ac2
|
630 |
op->archdata.num_irqs = 0; |
2b1e59787
|
631 |
} |
cf44bbc26
|
632 633 |
build_device_resources(op, parent); |
1636f8ac2
|
634 635 |
for (i = 0; i < op->archdata.num_irqs; i++) op->archdata.irqs[i] = build_one_device_irq(op, parent, op->archdata.irqs[i]); |
cf44bbc26
|
636 637 |
op->dev.parent = parent; |
eca393016
|
638 |
op->dev.bus = &platform_bus_type; |
cf44bbc26
|
639 |
if (!parent) |
2222c313e
|
640 |
dev_set_name(&op->dev, "root"); |
cf44bbc26
|
641 |
else |
6016a363f
|
642 |
dev_set_name(&op->dev, "%08x", dp->phandle); |
cf44bbc26
|
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 |
if (of_device_register(op)) { printk("%s: Could not register of device. ", dp->full_name); kfree(op); op = NULL; } return op; } static void __init scan_tree(struct device_node *dp, struct device *parent) { while (dp) { |
cd4cd7306
|
658 |
struct platform_device *op = scan_one_device(dp, parent); |
cf44bbc26
|
659 660 661 662 663 664 665 |
if (op) scan_tree(dp->child, &op->dev); dp = dp->sibling; } } |
eca393016
|
666 |
static int __init scan_of_devices(void) |
cf44bbc26
|
667 668 |
{ struct device_node *root = of_find_node_by_path("/"); |
cd4cd7306
|
669 |
struct platform_device *parent; |
cf44bbc26
|
670 671 672 |
parent = scan_one_device(root, NULL); if (!parent) |
eca393016
|
673 |
return 0; |
cf44bbc26
|
674 675 |
scan_tree(root->child, &parent->dev); |
eca393016
|
676 |
return 0; |
cf44bbc26
|
677 |
} |
eca393016
|
678 |
postcore_initcall(scan_of_devices); |
a2bd4fd17
|
679 |
|
a83f98231
|
680 681 682 683 684 685 686 687 688 689 690 691 692 |
static int __init of_debug(char *str) { int val = 0; get_option(&str, &val); if (val & 1) of_resource_verbose = 1; if (val & 2) of_irq_verbose = 1; return 1; } __setup("of_debug=", of_debug); |