diff options
-rw-r--r-- | arch/sparc/kernel/of_device.c | 422 | ||||
-rw-r--r-- | arch/sparc64/kernel/of_device.c | 490 | ||||
-rw-r--r-- | include/asm-sparc/of_device.h | 14 | ||||
-rw-r--r-- | include/asm-sparc/prom.h | 2 | ||||
-rw-r--r-- | include/asm-sparc64/of_device.h | 14 | ||||
-rw-r--r-- | include/asm-sparc64/prom.h | 2 |
6 files changed, 936 insertions, 8 deletions
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c index 80a809478781..13a70bd87817 100644 --- a/arch/sparc/kernel/of_device.c +++ b/arch/sparc/kernel/of_device.c | |||
@@ -153,10 +153,424 @@ struct bus_type sbus_bus_type = { | |||
153 | EXPORT_SYMBOL(sbus_bus_type); | 153 | EXPORT_SYMBOL(sbus_bus_type); |
154 | #endif | 154 | #endif |
155 | 155 | ||
156 | struct bus_type of_bus_type = { | ||
157 | .name = "of", | ||
158 | .match = of_platform_bus_match, | ||
159 | .probe = of_device_probe, | ||
160 | .remove = of_device_remove, | ||
161 | .suspend = of_device_suspend, | ||
162 | .resume = of_device_resume, | ||
163 | }; | ||
164 | EXPORT_SYMBOL(of_bus_type); | ||
165 | |||
166 | static inline u64 of_read_addr(u32 *cell, int size) | ||
167 | { | ||
168 | u64 r = 0; | ||
169 | while (size--) | ||
170 | r = (r << 32) | *(cell++); | ||
171 | return r; | ||
172 | } | ||
173 | |||
174 | static void __init get_cells(struct device_node *dp, | ||
175 | int *addrc, int *sizec) | ||
176 | { | ||
177 | if (addrc) | ||
178 | *addrc = of_n_addr_cells(dp); | ||
179 | if (sizec) | ||
180 | *sizec = of_n_size_cells(dp); | ||
181 | } | ||
182 | |||
183 | /* Max address size we deal with */ | ||
184 | #define OF_MAX_ADDR_CELLS 4 | ||
185 | |||
186 | struct of_bus { | ||
187 | const char *name; | ||
188 | const char *addr_prop_name; | ||
189 | int (*match)(struct device_node *parent); | ||
190 | void (*count_cells)(struct device_node *child, | ||
191 | int *addrc, int *sizec); | ||
192 | u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); | ||
193 | int (*translate)(u32 *addr, u64 offset, int na); | ||
194 | unsigned int (*get_flags)(u32 *addr); | ||
195 | }; | ||
196 | |||
197 | /* | ||
198 | * Default translator (generic bus) | ||
199 | */ | ||
200 | |||
201 | static void of_bus_default_count_cells(struct device_node *dev, | ||
202 | int *addrc, int *sizec) | ||
203 | { | ||
204 | get_cells(dev, addrc, sizec); | ||
205 | } | ||
206 | |||
207 | static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
208 | { | ||
209 | u64 cp, s, da; | ||
210 | |||
211 | cp = of_read_addr(range, na); | ||
212 | s = of_read_addr(range + na + pna, ns); | ||
213 | da = of_read_addr(addr, na); | ||
214 | |||
215 | if (da < cp || da >= (cp + s)) | ||
216 | return OF_BAD_ADDR; | ||
217 | return da - cp; | ||
218 | } | ||
219 | |||
220 | static int of_bus_default_translate(u32 *addr, u64 offset, int na) | ||
221 | { | ||
222 | u64 a = of_read_addr(addr, na); | ||
223 | memset(addr, 0, na * 4); | ||
224 | a += offset; | ||
225 | if (na > 1) | ||
226 | addr[na - 2] = a >> 32; | ||
227 | addr[na - 1] = a & 0xffffffffu; | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static unsigned int of_bus_default_get_flags(u32 *addr) | ||
233 | { | ||
234 | return IORESOURCE_MEM; | ||
235 | } | ||
236 | |||
237 | |||
238 | /* | ||
239 | * PCI bus specific translator | ||
240 | */ | ||
241 | |||
242 | static int of_bus_pci_match(struct device_node *np) | ||
243 | { | ||
244 | return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); | ||
245 | } | ||
246 | |||
247 | static void of_bus_pci_count_cells(struct device_node *np, | ||
248 | int *addrc, int *sizec) | ||
249 | { | ||
250 | if (addrc) | ||
251 | *addrc = 3; | ||
252 | if (sizec) | ||
253 | *sizec = 2; | ||
254 | } | ||
255 | |||
256 | static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
257 | { | ||
258 | u64 cp, s, da; | ||
259 | |||
260 | /* Check address type match */ | ||
261 | if ((addr[0] ^ range[0]) & 0x03000000) | ||
262 | return OF_BAD_ADDR; | ||
263 | |||
264 | /* Read address values, skipping high cell */ | ||
265 | cp = of_read_addr(range + 1, na - 1); | ||
266 | s = of_read_addr(range + na + pna, ns); | ||
267 | da = of_read_addr(addr + 1, na - 1); | ||
268 | |||
269 | if (da < cp || da >= (cp + s)) | ||
270 | return OF_BAD_ADDR; | ||
271 | return da - cp; | ||
272 | } | ||
273 | |||
274 | static int of_bus_pci_translate(u32 *addr, u64 offset, int na) | ||
275 | { | ||
276 | return of_bus_default_translate(addr + 1, offset, na - 1); | ||
277 | } | ||
278 | |||
279 | static unsigned int of_bus_pci_get_flags(u32 *addr) | ||
280 | { | ||
281 | unsigned int flags = 0; | ||
282 | u32 w = addr[0]; | ||
283 | |||
284 | switch((w >> 24) & 0x03) { | ||
285 | case 0x01: | ||
286 | flags |= IORESOURCE_IO; | ||
287 | case 0x02: /* 32 bits */ | ||
288 | case 0x03: /* 64 bits */ | ||
289 | flags |= IORESOURCE_MEM; | ||
290 | } | ||
291 | if (w & 0x40000000) | ||
292 | flags |= IORESOURCE_PREFETCH; | ||
293 | return flags; | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * SBUS bus specific translator | ||
298 | */ | ||
299 | |||
300 | static int of_bus_sbus_match(struct device_node *np) | ||
301 | { | ||
302 | return !strcmp(np->name, "sbus") || | ||
303 | !strcmp(np->name, "sbi"); | ||
304 | } | ||
305 | |||
306 | static void of_bus_sbus_count_cells(struct device_node *child, | ||
307 | int *addrc, int *sizec) | ||
308 | { | ||
309 | if (addrc) | ||
310 | *addrc = 2; | ||
311 | if (sizec) | ||
312 | *sizec = 1; | ||
313 | } | ||
314 | |||
315 | static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
316 | { | ||
317 | return of_bus_default_map(addr, range, na, ns, pna); | ||
318 | } | ||
319 | |||
320 | static int of_bus_sbus_translate(u32 *addr, u64 offset, int na) | ||
321 | { | ||
322 | return of_bus_default_translate(addr, offset, na); | ||
323 | } | ||
324 | |||
325 | static unsigned int of_bus_sbus_get_flags(u32 *addr) | ||
326 | { | ||
327 | return IORESOURCE_MEM; | ||
328 | } | ||
329 | |||
330 | |||
331 | /* | ||
332 | * Array of bus specific translators | ||
333 | */ | ||
334 | |||
335 | static struct of_bus of_busses[] = { | ||
336 | /* PCI */ | ||
337 | { | ||
338 | .name = "pci", | ||
339 | .addr_prop_name = "assigned-addresses", | ||
340 | .match = of_bus_pci_match, | ||
341 | .count_cells = of_bus_pci_count_cells, | ||
342 | .map = of_bus_pci_map, | ||
343 | .translate = of_bus_pci_translate, | ||
344 | .get_flags = of_bus_pci_get_flags, | ||
345 | }, | ||
346 | /* SBUS */ | ||
347 | { | ||
348 | .name = "sbus", | ||
349 | .addr_prop_name = "reg", | ||
350 | .match = of_bus_sbus_match, | ||
351 | .count_cells = of_bus_sbus_count_cells, | ||
352 | .map = of_bus_sbus_map, | ||
353 | .translate = of_bus_sbus_translate, | ||
354 | .get_flags = of_bus_sbus_get_flags, | ||
355 | }, | ||
356 | /* Default */ | ||
357 | { | ||
358 | .name = "default", | ||
359 | .addr_prop_name = "reg", | ||
360 | .match = NULL, | ||
361 | .count_cells = of_bus_default_count_cells, | ||
362 | .map = of_bus_default_map, | ||
363 | .translate = of_bus_default_translate, | ||
364 | .get_flags = of_bus_default_get_flags, | ||
365 | }, | ||
366 | }; | ||
367 | |||
368 | static struct of_bus *of_match_bus(struct device_node *np) | ||
369 | { | ||
370 | int i; | ||
371 | |||
372 | for (i = 0; i < ARRAY_SIZE(of_busses); i ++) | ||
373 | if (!of_busses[i].match || of_busses[i].match(np)) | ||
374 | return &of_busses[i]; | ||
375 | BUG(); | ||
376 | return NULL; | ||
377 | } | ||
378 | |||
379 | static int __init build_one_resource(struct device_node *parent, | ||
380 | struct of_bus *bus, | ||
381 | struct of_bus *pbus, | ||
382 | u32 *addr, | ||
383 | int na, int ns, int pna) | ||
384 | { | ||
385 | u32 *ranges; | ||
386 | unsigned int rlen; | ||
387 | int rone; | ||
388 | u64 offset = OF_BAD_ADDR; | ||
389 | |||
390 | ranges = of_get_property(parent, "ranges", &rlen); | ||
391 | if (ranges == NULL || rlen == 0) { | ||
392 | offset = of_read_addr(addr, na); | ||
393 | memset(addr, 0, pna * 4); | ||
394 | goto finish; | ||
395 | } | ||
396 | |||
397 | /* Now walk through the ranges */ | ||
398 | rlen /= 4; | ||
399 | rone = na + pna + ns; | ||
400 | for (; rlen >= rone; rlen -= rone, ranges += rone) { | ||
401 | offset = bus->map(addr, ranges, na, ns, pna); | ||
402 | if (offset != OF_BAD_ADDR) | ||
403 | break; | ||
404 | } | ||
405 | if (offset == OF_BAD_ADDR) | ||
406 | return 1; | ||
407 | |||
408 | memcpy(addr, ranges + na, 4 * pna); | ||
409 | |||
410 | finish: | ||
411 | /* Translate it into parent bus space */ | ||
412 | return pbus->translate(addr, offset, pna); | ||
413 | } | ||
414 | |||
415 | static void __init build_device_resources(struct of_device *op, | ||
416 | struct device *parent) | ||
417 | { | ||
418 | struct of_device *p_op; | ||
419 | struct of_bus *bus; | ||
420 | int na, ns; | ||
421 | int index, num_reg; | ||
422 | void *preg; | ||
423 | |||
424 | if (!parent) | ||
425 | return; | ||
426 | |||
427 | p_op = to_of_device(parent); | ||
428 | bus = of_match_bus(p_op->node); | ||
429 | bus->count_cells(op->node, &na, &ns); | ||
430 | |||
431 | preg = of_get_property(op->node, bus->addr_prop_name, &num_reg); | ||
432 | if (!preg || num_reg == 0) | ||
433 | return; | ||
434 | |||
435 | /* Convert to num-cells. */ | ||
436 | num_reg /= 4; | ||
437 | |||
438 | /* Conver to num-entries. */ | ||
439 | num_reg /= na + ns; | ||
440 | |||
441 | for (index = 0; index < num_reg; index++) { | ||
442 | struct resource *r = &op->resource[index]; | ||
443 | u32 addr[OF_MAX_ADDR_CELLS]; | ||
444 | u32 *reg = (preg + (index * ((na + ns) * 4))); | ||
445 | struct device_node *dp = op->node; | ||
446 | struct device_node *pp = p_op->node; | ||
447 | struct of_bus *pbus; | ||
448 | u64 size, result = OF_BAD_ADDR; | ||
449 | unsigned long flags; | ||
450 | int dna, dns; | ||
451 | int pna, pns; | ||
452 | |||
453 | size = of_read_addr(reg + na, ns); | ||
454 | flags = bus->get_flags(reg); | ||
455 | |||
456 | memcpy(addr, reg, na * 4); | ||
457 | |||
458 | /* If the immediate parent has no ranges property to apply, | ||
459 | * just use a 1<->1 mapping. | ||
460 | */ | ||
461 | if (of_find_property(pp, "ranges", NULL) == NULL) { | ||
462 | result = of_read_addr(addr, na); | ||
463 | goto build_res; | ||
464 | } | ||
465 | |||
466 | dna = na; | ||
467 | dns = ns; | ||
468 | |||
469 | while (1) { | ||
470 | dp = pp; | ||
471 | pp = dp->parent; | ||
472 | if (!pp) { | ||
473 | result = of_read_addr(addr, dna); | ||
474 | break; | ||
475 | } | ||
476 | |||
477 | pbus = of_match_bus(pp); | ||
478 | pbus->count_cells(dp, &pna, &pns); | ||
479 | |||
480 | if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) | ||
481 | break; | ||
482 | |||
483 | dna = pna; | ||
484 | dns = pns; | ||
485 | bus = pbus; | ||
486 | } | ||
487 | |||
488 | build_res: | ||
489 | memset(r, 0, sizeof(*r)); | ||
490 | if (result != OF_BAD_ADDR) { | ||
491 | r->start = result; | ||
492 | r->end = result + size - 1; | ||
493 | r->flags = flags; | ||
494 | } else { | ||
495 | r->start = ~0UL; | ||
496 | r->end = ~0UL; | ||
497 | } | ||
498 | r->name = op->node->name; | ||
499 | } | ||
500 | } | ||
501 | |||
502 | static struct of_device * __init scan_one_device(struct device_node *dp, | ||
503 | struct device *parent) | ||
504 | { | ||
505 | struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); | ||
506 | unsigned int *irq; | ||
507 | int len; | ||
508 | |||
509 | if (!op) | ||
510 | return NULL; | ||
511 | |||
512 | op->node = dp; | ||
513 | |||
514 | op->clock_freq = of_getintprop_default(dp, "clock-frequency", | ||
515 | (25*1000*1000)); | ||
516 | op->portid = of_getintprop_default(dp, "upa-portid", -1); | ||
517 | if (op->portid == -1) | ||
518 | op->portid = of_getintprop_default(dp, "portid", -1); | ||
519 | |||
520 | irq = of_get_property(dp, "interrupts", &len); | ||
521 | if (irq) | ||
522 | op->irq = *irq; | ||
523 | else | ||
524 | op->irq = 0xffffffff; | ||
525 | |||
526 | build_device_resources(op, parent); | ||
527 | |||
528 | op->dev.parent = parent; | ||
529 | op->dev.bus = &of_bus_type; | ||
530 | if (!parent) | ||
531 | strcpy(op->dev.bus_id, "root"); | ||
532 | else | ||
533 | strcpy(op->dev.bus_id, dp->path_component_name); | ||
534 | |||
535 | if (of_device_register(op)) { | ||
536 | printk("%s: Could not register of device.\n", | ||
537 | dp->full_name); | ||
538 | kfree(op); | ||
539 | op = NULL; | ||
540 | } | ||
541 | |||
542 | return op; | ||
543 | } | ||
544 | |||
545 | static void __init scan_tree(struct device_node *dp, struct device *parent) | ||
546 | { | ||
547 | while (dp) { | ||
548 | struct of_device *op = scan_one_device(dp, parent); | ||
549 | |||
550 | if (op) | ||
551 | scan_tree(dp->child, &op->dev); | ||
552 | |||
553 | dp = dp->sibling; | ||
554 | } | ||
555 | } | ||
556 | |||
557 | static void __init scan_of_devices(void) | ||
558 | { | ||
559 | struct device_node *root = of_find_node_by_path("/"); | ||
560 | struct of_device *parent; | ||
561 | |||
562 | parent = scan_one_device(root, NULL); | ||
563 | if (!parent) | ||
564 | return; | ||
565 | |||
566 | scan_tree(root->child, &parent->dev); | ||
567 | } | ||
568 | |||
156 | static int __init of_bus_driver_init(void) | 569 | static int __init of_bus_driver_init(void) |
157 | { | 570 | { |
158 | int err = 0; | 571 | int err; |
159 | 572 | ||
573 | err = bus_register(&of_bus_type); | ||
160 | #ifdef CONFIG_PCI | 574 | #ifdef CONFIG_PCI |
161 | if (!err) | 575 | if (!err) |
162 | err = bus_register(&ebus_bus_type); | 576 | err = bus_register(&ebus_bus_type); |
@@ -165,7 +579,11 @@ static int __init of_bus_driver_init(void) | |||
165 | if (!err) | 579 | if (!err) |
166 | err = bus_register(&sbus_bus_type); | 580 | err = bus_register(&sbus_bus_type); |
167 | #endif | 581 | #endif |
168 | return 0; | 582 | |
583 | if (!err) | ||
584 | scan_of_devices(); | ||
585 | |||
586 | return err; | ||
169 | } | 587 | } |
170 | 588 | ||
171 | postcore_initcall(of_bus_driver_init); | 589 | postcore_initcall(of_bus_driver_init); |
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 768475bbce82..00502dc280ef 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c | |||
@@ -163,10 +163,492 @@ struct bus_type sbus_bus_type = { | |||
163 | EXPORT_SYMBOL(sbus_bus_type); | 163 | EXPORT_SYMBOL(sbus_bus_type); |
164 | #endif | 164 | #endif |
165 | 165 | ||
166 | struct bus_type of_bus_type = { | ||
167 | .name = "of", | ||
168 | .match = of_platform_bus_match, | ||
169 | .probe = of_device_probe, | ||
170 | .remove = of_device_remove, | ||
171 | .suspend = of_device_suspend, | ||
172 | .resume = of_device_resume, | ||
173 | }; | ||
174 | EXPORT_SYMBOL(of_bus_type); | ||
175 | |||
176 | static inline u64 of_read_addr(u32 *cell, int size) | ||
177 | { | ||
178 | u64 r = 0; | ||
179 | while (size--) | ||
180 | r = (r << 32) | *(cell++); | ||
181 | return r; | ||
182 | } | ||
183 | |||
184 | static void __init get_cells(struct device_node *dp, | ||
185 | int *addrc, int *sizec) | ||
186 | { | ||
187 | if (addrc) | ||
188 | *addrc = of_n_addr_cells(dp); | ||
189 | if (sizec) | ||
190 | *sizec = of_n_size_cells(dp); | ||
191 | } | ||
192 | |||
193 | /* Max address size we deal with */ | ||
194 | #define OF_MAX_ADDR_CELLS 4 | ||
195 | |||
196 | struct of_bus { | ||
197 | const char *name; | ||
198 | const char *addr_prop_name; | ||
199 | int (*match)(struct device_node *parent); | ||
200 | void (*count_cells)(struct device_node *child, | ||
201 | int *addrc, int *sizec); | ||
202 | u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); | ||
203 | int (*translate)(u32 *addr, u64 offset, int na); | ||
204 | unsigned int (*get_flags)(u32 *addr); | ||
205 | }; | ||
206 | |||
207 | /* | ||
208 | * Default translator (generic bus) | ||
209 | */ | ||
210 | |||
211 | static void of_bus_default_count_cells(struct device_node *dev, | ||
212 | int *addrc, int *sizec) | ||
213 | { | ||
214 | get_cells(dev, addrc, sizec); | ||
215 | } | ||
216 | |||
217 | static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
218 | { | ||
219 | u64 cp, s, da; | ||
220 | |||
221 | cp = of_read_addr(range, na); | ||
222 | s = of_read_addr(range + na + pna, ns); | ||
223 | da = of_read_addr(addr, na); | ||
224 | |||
225 | if (da < cp || da >= (cp + s)) | ||
226 | return OF_BAD_ADDR; | ||
227 | return da - cp; | ||
228 | } | ||
229 | |||
230 | static int of_bus_default_translate(u32 *addr, u64 offset, int na) | ||
231 | { | ||
232 | u64 a = of_read_addr(addr, na); | ||
233 | memset(addr, 0, na * 4); | ||
234 | a += offset; | ||
235 | if (na > 1) | ||
236 | addr[na - 2] = a >> 32; | ||
237 | addr[na - 1] = a & 0xffffffffu; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static unsigned int of_bus_default_get_flags(u32 *addr) | ||
243 | { | ||
244 | return IORESOURCE_MEM; | ||
245 | } | ||
246 | |||
247 | |||
248 | /* | ||
249 | * PCI bus specific translator | ||
250 | */ | ||
251 | |||
252 | static int of_bus_pci_match(struct device_node *np) | ||
253 | { | ||
254 | return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); | ||
255 | } | ||
256 | |||
257 | static void of_bus_pci_count_cells(struct device_node *np, | ||
258 | int *addrc, int *sizec) | ||
259 | { | ||
260 | if (addrc) | ||
261 | *addrc = 3; | ||
262 | if (sizec) | ||
263 | *sizec = 2; | ||
264 | } | ||
265 | |||
266 | static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
267 | { | ||
268 | u64 cp, s, da; | ||
269 | |||
270 | /* Check address type match */ | ||
271 | if ((addr[0] ^ range[0]) & 0x03000000) | ||
272 | return OF_BAD_ADDR; | ||
273 | |||
274 | /* Read address values, skipping high cell */ | ||
275 | cp = of_read_addr(range + 1, na - 1); | ||
276 | s = of_read_addr(range + na + pna, ns); | ||
277 | da = of_read_addr(addr + 1, na - 1); | ||
278 | |||
279 | if (da < cp || da >= (cp + s)) | ||
280 | return OF_BAD_ADDR; | ||
281 | return da - cp; | ||
282 | } | ||
283 | |||
284 | static int of_bus_pci_translate(u32 *addr, u64 offset, int na) | ||
285 | { | ||
286 | return of_bus_default_translate(addr + 1, offset, na - 1); | ||
287 | } | ||
288 | |||
289 | static unsigned int of_bus_pci_get_flags(u32 *addr) | ||
290 | { | ||
291 | unsigned int flags = 0; | ||
292 | u32 w = addr[0]; | ||
293 | |||
294 | switch((w >> 24) & 0x03) { | ||
295 | case 0x01: | ||
296 | flags |= IORESOURCE_IO; | ||
297 | case 0x02: /* 32 bits */ | ||
298 | case 0x03: /* 64 bits */ | ||
299 | flags |= IORESOURCE_MEM; | ||
300 | } | ||
301 | if (w & 0x40000000) | ||
302 | flags |= IORESOURCE_PREFETCH; | ||
303 | return flags; | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * ISA bus specific translator | ||
308 | */ | ||
309 | |||
310 | static int of_bus_isa_match(struct device_node *np) | ||
311 | { | ||
312 | return !strcmp(np->name, "isa"); | ||
313 | } | ||
314 | |||
315 | static void of_bus_isa_count_cells(struct device_node *child, | ||
316 | int *addrc, int *sizec) | ||
317 | { | ||
318 | if (addrc) | ||
319 | *addrc = 2; | ||
320 | if (sizec) | ||
321 | *sizec = 1; | ||
322 | } | ||
323 | |||
324 | static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
325 | { | ||
326 | u64 cp, s, da; | ||
327 | |||
328 | /* Check address type match */ | ||
329 | if ((addr[0] ^ range[0]) & 0x00000001) | ||
330 | return OF_BAD_ADDR; | ||
331 | |||
332 | /* Read address values, skipping high cell */ | ||
333 | cp = of_read_addr(range + 1, na - 1); | ||
334 | s = of_read_addr(range + na + pna, ns); | ||
335 | da = of_read_addr(addr + 1, na - 1); | ||
336 | |||
337 | if (da < cp || da >= (cp + s)) | ||
338 | return OF_BAD_ADDR; | ||
339 | return da - cp; | ||
340 | } | ||
341 | |||
342 | static int of_bus_isa_translate(u32 *addr, u64 offset, int na) | ||
343 | { | ||
344 | return of_bus_default_translate(addr + 1, offset, na - 1); | ||
345 | } | ||
346 | |||
347 | static unsigned int of_bus_isa_get_flags(u32 *addr) | ||
348 | { | ||
349 | unsigned int flags = 0; | ||
350 | u32 w = addr[0]; | ||
351 | |||
352 | if (w & 1) | ||
353 | flags |= IORESOURCE_IO; | ||
354 | else | ||
355 | flags |= IORESOURCE_MEM; | ||
356 | return flags; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * SBUS bus specific translator | ||
361 | */ | ||
362 | |||
363 | static int of_bus_sbus_match(struct device_node *np) | ||
364 | { | ||
365 | return !strcmp(np->name, "sbus") || | ||
366 | !strcmp(np->name, "sbi"); | ||
367 | } | ||
368 | |||
369 | static void of_bus_sbus_count_cells(struct device_node *child, | ||
370 | int *addrc, int *sizec) | ||
371 | { | ||
372 | if (addrc) | ||
373 | *addrc = 2; | ||
374 | if (sizec) | ||
375 | *sizec = 1; | ||
376 | } | ||
377 | |||
378 | static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
379 | { | ||
380 | return of_bus_default_map(addr, range, na, ns, pna); | ||
381 | } | ||
382 | |||
383 | static int of_bus_sbus_translate(u32 *addr, u64 offset, int na) | ||
384 | { | ||
385 | return of_bus_default_translate(addr, offset, na); | ||
386 | } | ||
387 | |||
388 | static unsigned int of_bus_sbus_get_flags(u32 *addr) | ||
389 | { | ||
390 | return IORESOURCE_MEM; | ||
391 | } | ||
392 | |||
393 | |||
394 | /* | ||
395 | * Array of bus specific translators | ||
396 | */ | ||
397 | |||
398 | static struct of_bus of_busses[] = { | ||
399 | /* PCI */ | ||
400 | { | ||
401 | .name = "pci", | ||
402 | .addr_prop_name = "assigned-addresses", | ||
403 | .match = of_bus_pci_match, | ||
404 | .count_cells = of_bus_pci_count_cells, | ||
405 | .map = of_bus_pci_map, | ||
406 | .translate = of_bus_pci_translate, | ||
407 | .get_flags = of_bus_pci_get_flags, | ||
408 | }, | ||
409 | /* ISA */ | ||
410 | { | ||
411 | .name = "isa", | ||
412 | .addr_prop_name = "reg", | ||
413 | .match = of_bus_isa_match, | ||
414 | .count_cells = of_bus_isa_count_cells, | ||
415 | .map = of_bus_isa_map, | ||
416 | .translate = of_bus_isa_translate, | ||
417 | .get_flags = of_bus_isa_get_flags, | ||
418 | }, | ||
419 | /* SBUS */ | ||
420 | { | ||
421 | .name = "sbus", | ||
422 | .addr_prop_name = "reg", | ||
423 | .match = of_bus_sbus_match, | ||
424 | .count_cells = of_bus_sbus_count_cells, | ||
425 | .map = of_bus_sbus_map, | ||
426 | .translate = of_bus_sbus_translate, | ||
427 | .get_flags = of_bus_sbus_get_flags, | ||
428 | }, | ||
429 | /* Default */ | ||
430 | { | ||
431 | .name = "default", | ||
432 | .addr_prop_name = "reg", | ||
433 | .match = NULL, | ||
434 | .count_cells = of_bus_default_count_cells, | ||
435 | .map = of_bus_default_map, | ||
436 | .translate = of_bus_default_translate, | ||
437 | .get_flags = of_bus_default_get_flags, | ||
438 | }, | ||
439 | }; | ||
440 | |||
441 | static struct of_bus *of_match_bus(struct device_node *np) | ||
442 | { | ||
443 | int i; | ||
444 | |||
445 | for (i = 0; i < ARRAY_SIZE(of_busses); i ++) | ||
446 | if (!of_busses[i].match || of_busses[i].match(np)) | ||
447 | return &of_busses[i]; | ||
448 | BUG(); | ||
449 | return NULL; | ||
450 | } | ||
451 | |||
452 | static int __init build_one_resource(struct device_node *parent, | ||
453 | struct of_bus *bus, | ||
454 | struct of_bus *pbus, | ||
455 | u32 *addr, | ||
456 | int na, int ns, int pna) | ||
457 | { | ||
458 | u32 *ranges; | ||
459 | unsigned int rlen; | ||
460 | int rone; | ||
461 | u64 offset = OF_BAD_ADDR; | ||
462 | |||
463 | ranges = of_get_property(parent, "ranges", &rlen); | ||
464 | if (ranges == NULL || rlen == 0) { | ||
465 | offset = of_read_addr(addr, na); | ||
466 | memset(addr, 0, pna * 4); | ||
467 | goto finish; | ||
468 | } | ||
469 | |||
470 | /* Now walk through the ranges */ | ||
471 | rlen /= 4; | ||
472 | rone = na + pna + ns; | ||
473 | for (; rlen >= rone; rlen -= rone, ranges += rone) { | ||
474 | offset = bus->map(addr, ranges, na, ns, pna); | ||
475 | if (offset != OF_BAD_ADDR) | ||
476 | break; | ||
477 | } | ||
478 | if (offset == OF_BAD_ADDR) | ||
479 | return 1; | ||
480 | |||
481 | memcpy(addr, ranges + na, 4 * pna); | ||
482 | |||
483 | finish: | ||
484 | /* Translate it into parent bus space */ | ||
485 | return pbus->translate(addr, offset, pna); | ||
486 | } | ||
487 | |||
488 | static void __init build_device_resources(struct of_device *op, | ||
489 | struct device *parent) | ||
490 | { | ||
491 | struct of_device *p_op; | ||
492 | struct of_bus *bus; | ||
493 | int na, ns; | ||
494 | int index, num_reg; | ||
495 | void *preg; | ||
496 | |||
497 | if (!parent) | ||
498 | return; | ||
499 | |||
500 | p_op = to_of_device(parent); | ||
501 | bus = of_match_bus(p_op->node); | ||
502 | bus->count_cells(op->node, &na, &ns); | ||
503 | |||
504 | preg = of_get_property(op->node, bus->addr_prop_name, &num_reg); | ||
505 | if (!preg || num_reg == 0) | ||
506 | return; | ||
507 | |||
508 | /* Convert to num-cells. */ | ||
509 | num_reg /= 4; | ||
510 | |||
511 | /* Conver to num-entries. */ | ||
512 | num_reg /= na + ns; | ||
513 | |||
514 | for (index = 0; index < num_reg; index++) { | ||
515 | struct resource *r = &op->resource[index]; | ||
516 | u32 addr[OF_MAX_ADDR_CELLS]; | ||
517 | u32 *reg = (preg + (index * ((na + ns) * 4))); | ||
518 | struct device_node *dp = op->node; | ||
519 | struct device_node *pp = p_op->node; | ||
520 | struct of_bus *pbus; | ||
521 | u64 size, result = OF_BAD_ADDR; | ||
522 | unsigned long flags; | ||
523 | int dna, dns; | ||
524 | int pna, pns; | ||
525 | |||
526 | size = of_read_addr(reg + na, ns); | ||
527 | flags = bus->get_flags(reg); | ||
528 | |||
529 | memcpy(addr, reg, na * 4); | ||
530 | |||
531 | /* If the immediate parent has no ranges property to apply, | ||
532 | * just use a 1<->1 mapping. Unless it is the 'dma' child | ||
533 | * of an isa bus, which must be passed up towards the root. | ||
534 | * | ||
535 | * Also, don't try to translate PMU bus device registers. | ||
536 | */ | ||
537 | if ((of_find_property(pp, "ranges", NULL) == NULL && | ||
538 | strcmp(pp->name, "dma") != 0) || | ||
539 | !strcmp(pp->name, "pmu")) { | ||
540 | result = of_read_addr(addr, na); | ||
541 | goto build_res; | ||
542 | } | ||
543 | |||
544 | dna = na; | ||
545 | dns = ns; | ||
546 | |||
547 | while (1) { | ||
548 | dp = pp; | ||
549 | pp = dp->parent; | ||
550 | if (!pp) { | ||
551 | result = of_read_addr(addr, dna); | ||
552 | break; | ||
553 | } | ||
554 | |||
555 | pbus = of_match_bus(pp); | ||
556 | pbus->count_cells(dp, &pna, &pns); | ||
557 | |||
558 | if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) | ||
559 | break; | ||
560 | |||
561 | dna = pna; | ||
562 | dns = pns; | ||
563 | bus = pbus; | ||
564 | } | ||
565 | |||
566 | build_res: | ||
567 | memset(r, 0, sizeof(*r)); | ||
568 | if (result != OF_BAD_ADDR) { | ||
569 | r->start = result; | ||
570 | r->end = result + size - 1; | ||
571 | r->flags = flags; | ||
572 | } else { | ||
573 | r->start = ~0UL; | ||
574 | r->end = ~0UL; | ||
575 | } | ||
576 | r->name = op->node->name; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | static struct of_device * __init scan_one_device(struct device_node *dp, | ||
581 | struct device *parent) | ||
582 | { | ||
583 | struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); | ||
584 | unsigned int *irq; | ||
585 | int len; | ||
586 | |||
587 | if (!op) | ||
588 | return NULL; | ||
589 | |||
590 | op->node = dp; | ||
591 | |||
592 | op->clock_freq = of_getintprop_default(dp, "clock-frequency", | ||
593 | (25*1000*1000)); | ||
594 | op->portid = of_getintprop_default(dp, "upa-portid", -1); | ||
595 | if (op->portid == -1) | ||
596 | op->portid = of_getintprop_default(dp, "portid", -1); | ||
597 | |||
598 | irq = of_get_property(dp, "interrupts", &len); | ||
599 | if (irq) | ||
600 | op->irq = *irq; | ||
601 | else | ||
602 | op->irq = 0xffffffff; | ||
603 | |||
604 | build_device_resources(op, parent); | ||
605 | |||
606 | op->dev.parent = parent; | ||
607 | op->dev.bus = &of_bus_type; | ||
608 | if (!parent) | ||
609 | strcpy(op->dev.bus_id, "root"); | ||
610 | else | ||
611 | strcpy(op->dev.bus_id, dp->path_component_name); | ||
612 | |||
613 | if (of_device_register(op)) { | ||
614 | printk("%s: Could not register of device.\n", | ||
615 | dp->full_name); | ||
616 | kfree(op); | ||
617 | op = NULL; | ||
618 | } | ||
619 | |||
620 | return op; | ||
621 | } | ||
622 | |||
623 | static void __init scan_tree(struct device_node *dp, struct device *parent) | ||
624 | { | ||
625 | while (dp) { | ||
626 | struct of_device *op = scan_one_device(dp, parent); | ||
627 | |||
628 | if (op) | ||
629 | scan_tree(dp->child, &op->dev); | ||
630 | |||
631 | dp = dp->sibling; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | static void __init scan_of_devices(void) | ||
636 | { | ||
637 | struct device_node *root = of_find_node_by_path("/"); | ||
638 | struct of_device *parent; | ||
639 | |||
640 | parent = scan_one_device(root, NULL); | ||
641 | if (!parent) | ||
642 | return; | ||
643 | |||
644 | scan_tree(root->child, &parent->dev); | ||
645 | } | ||
646 | |||
166 | static int __init of_bus_driver_init(void) | 647 | static int __init of_bus_driver_init(void) |
167 | { | 648 | { |
168 | int err = 0; | 649 | int err; |
169 | 650 | ||
651 | err = bus_register(&of_bus_type); | ||
170 | #ifdef CONFIG_PCI | 652 | #ifdef CONFIG_PCI |
171 | if (!err) | 653 | if (!err) |
172 | err = bus_register(&isa_bus_type); | 654 | err = bus_register(&isa_bus_type); |
@@ -177,7 +659,11 @@ static int __init of_bus_driver_init(void) | |||
177 | if (!err) | 659 | if (!err) |
178 | err = bus_register(&sbus_bus_type); | 660 | err = bus_register(&sbus_bus_type); |
179 | #endif | 661 | #endif |
180 | return 0; | 662 | |
663 | if (!err) | ||
664 | scan_of_devices(); | ||
665 | |||
666 | return err; | ||
181 | } | 667 | } |
182 | 668 | ||
183 | postcore_initcall(of_bus_driver_init); | 669 | postcore_initcall(of_bus_driver_init); |
diff --git a/include/asm-sparc/of_device.h b/include/asm-sparc/of_device.h index 4816d102f918..1b43ee5eb5e7 100644 --- a/include/asm-sparc/of_device.h +++ b/include/asm-sparc/of_device.h | |||
@@ -4,10 +4,12 @@ | |||
4 | 4 | ||
5 | #include <linux/device.h> | 5 | #include <linux/device.h> |
6 | #include <linux/mod_devicetable.h> | 6 | #include <linux/mod_devicetable.h> |
7 | #include <asm/openprom.h> | ||
7 | #include <asm/prom.h> | 8 | #include <asm/prom.h> |
8 | 9 | ||
9 | extern struct bus_type ebus_bus_type; | 10 | extern struct bus_type ebus_bus_type; |
10 | extern struct bus_type sbus_bus_type; | 11 | extern struct bus_type sbus_bus_type; |
12 | extern struct bus_type of_bus_type; | ||
11 | 13 | ||
12 | /* | 14 | /* |
13 | * The of_device is a kind of "base class" that is a superset of | 15 | * The of_device is a kind of "base class" that is a superset of |
@@ -16,8 +18,16 @@ extern struct bus_type sbus_bus_type; | |||
16 | */ | 18 | */ |
17 | struct of_device | 19 | struct of_device |
18 | { | 20 | { |
19 | struct device_node *node; /* OF device node */ | 21 | struct device_node *node; |
20 | struct device dev; /* Generic device interface */ | 22 | struct device dev; |
23 | struct resource resource[PROMREG_MAX]; | ||
24 | unsigned int irq; | ||
25 | |||
26 | void *sysdata; | ||
27 | |||
28 | int slot; | ||
29 | int portid; | ||
30 | int clock_freq; | ||
21 | }; | 31 | }; |
22 | #define to_of_device(d) container_of(d, struct of_device, dev) | 32 | #define to_of_device(d) container_of(d, struct of_device, dev) |
23 | 33 | ||
diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index 7032d02d3197..b4a061c5241d 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h | |||
@@ -69,6 +69,8 @@ struct device_node { | |||
69 | #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) | 69 | #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) |
70 | #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) | 70 | #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) |
71 | 71 | ||
72 | #define OF_BAD_ADDR ((u64)-1) | ||
73 | |||
72 | static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) | 74 | static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) |
73 | { | 75 | { |
74 | dn->pde = de; | 76 | dn->pde = de; |
diff --git a/include/asm-sparc64/of_device.h b/include/asm-sparc64/of_device.h index 024088ef9d27..27bc08671d68 100644 --- a/include/asm-sparc64/of_device.h +++ b/include/asm-sparc64/of_device.h | |||
@@ -4,11 +4,13 @@ | |||
4 | 4 | ||
5 | #include <linux/device.h> | 5 | #include <linux/device.h> |
6 | #include <linux/mod_devicetable.h> | 6 | #include <linux/mod_devicetable.h> |
7 | #include <asm/openprom.h> | ||
7 | #include <asm/prom.h> | 8 | #include <asm/prom.h> |
8 | 9 | ||
9 | extern struct bus_type isa_bus_type; | 10 | extern struct bus_type isa_bus_type; |
10 | extern struct bus_type ebus_bus_type; | 11 | extern struct bus_type ebus_bus_type; |
11 | extern struct bus_type sbus_bus_type; | 12 | extern struct bus_type sbus_bus_type; |
13 | extern struct bus_type of_bus_type; | ||
12 | 14 | ||
13 | /* | 15 | /* |
14 | * The of_device is a kind of "base class" that is a superset of | 16 | * The of_device is a kind of "base class" that is a superset of |
@@ -17,8 +19,16 @@ extern struct bus_type sbus_bus_type; | |||
17 | */ | 19 | */ |
18 | struct of_device | 20 | struct of_device |
19 | { | 21 | { |
20 | struct device_node *node; /* OF device node */ | 22 | struct device_node *node; |
21 | struct device dev; /* Generic device interface */ | 23 | struct device dev; |
24 | struct resource resource[PROMREG_MAX]; | ||
25 | unsigned int irq; | ||
26 | |||
27 | void *sysdata; | ||
28 | |||
29 | int slot; | ||
30 | int portid; | ||
31 | int clock_freq; | ||
22 | }; | 32 | }; |
23 | #define to_of_device(d) container_of(d, struct of_device, dev) | 33 | #define to_of_device(d) container_of(d, struct of_device, dev) |
24 | 34 | ||
diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 4cecfe6d135d..d2849312dea1 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h | |||
@@ -69,6 +69,8 @@ struct device_node { | |||
69 | #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) | 69 | #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) |
70 | #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) | 70 | #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) |
71 | 71 | ||
72 | #define OF_BAD_ADDR ((u64)-1) | ||
73 | |||
72 | static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) | 74 | static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) |
73 | { | 75 | { |
74 | dn->pde = de; | 76 | dn->pde = de; |