Blame view
arch/sparc/kernel/of_device_32.c
8.88 KB
fd5314311 [SPARC]: Port of_... |
1 2 |
#include <linux/string.h> #include <linux/kernel.h> |
f85ff3056 Begin to consolid... |
3 |
#include <linux/of.h> |
fd5314311 [SPARC]: Port of_... |
4 |
#include <linux/init.h> |
fd5314311 [SPARC]: Port of_... |
5 6 |
#include <linux/mod_devicetable.h> #include <linux/slab.h> |
3f23de10f Create drivers/of... |
7 |
#include <linux/errno.h> |
c9f5b7e77 sparc: move of_de... |
8 |
#include <linux/irq.h> |
3f23de10f Create drivers/of... |
9 10 |
#include <linux/of_device.h> #include <linux/of_platform.h> |
e63829de3 sparc,leon: Added... |
11 12 |
#include <asm/leon.h> #include <asm/leon_amba.h> |
fd5314311 [SPARC]: Port of_... |
13 |
|
c9f5b7e77 sparc: move of_de... |
14 |
#include "of_device_common.h" |
1d05995b0 sparc32: introduc... |
15 |
#include "irq.h" |
cf44bbc26 [SPARC]: Beginnin... |
16 |
|
cf44bbc26 [SPARC]: Beginnin... |
17 18 19 20 21 22 |
/* * PCI bus specific translator */ static int of_bus_pci_match(struct device_node *np) { |
a83f98231 [SPARC]: Fix OF r... |
23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { /* 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 [SPARC]: Beginnin... |
37 38 39 40 41 42 43 44 45 46 |
} static void of_bus_pci_count_cells(struct device_node *np, int *addrc, int *sizec) { if (addrc) *addrc = 3; if (sizec) *sizec = 2; } |
a83f98231 [SPARC]: Fix OF r... |
47 48 |
static int of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna) |
cf44bbc26 [SPARC]: Beginnin... |
49 |
{ |
a83f98231 [SPARC]: Fix OF r... |
50 51 |
u32 result[OF_MAX_ADDR_CELLS]; int i; |
cf44bbc26 [SPARC]: Beginnin... |
52 53 54 |
/* Check address type match */ if ((addr[0] ^ range[0]) & 0x03000000) |
a83f98231 [SPARC]: Fix OF r... |
55 |
return -EINVAL; |
cf44bbc26 [SPARC]: Beginnin... |
56 |
|
a83f98231 [SPARC]: Fix OF r... |
57 58 59 |
if (of_out_of_range(addr + 1, range + 1, range + na + pna, na - 1, ns)) return -EINVAL; |
cf44bbc26 [SPARC]: Beginnin... |
60 |
|
a83f98231 [SPARC]: Fix OF r... |
61 62 |
/* Start with the parent range base. */ memcpy(result, range + na, pna * 4); |
cf44bbc26 [SPARC]: Beginnin... |
63 |
|
a83f98231 [SPARC]: Fix OF r... |
64 65 66 67 68 69 70 71 72 |
/* 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 [SPARC]: Beginnin... |
73 |
} |
e3c71a329 sparc: Fix resour... |
74 |
static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags) |
cf44bbc26 [SPARC]: Beginnin... |
75 |
{ |
cf44bbc26 [SPARC]: Beginnin... |
76 |
u32 w = addr[0]; |
e3c71a329 sparc: Fix resour... |
77 78 |
/* For PCI, we override whatever child busses may have used. */ flags = 0; |
cf44bbc26 [SPARC]: Beginnin... |
79 80 81 |
switch((w >> 24) & 0x03) { case 0x01: flags |= IORESOURCE_IO; |
e3c71a329 sparc: Fix resour... |
82 |
break; |
cf44bbc26 [SPARC]: Beginnin... |
83 84 85 |
case 0x02: /* 32 bits */ case 0x03: /* 64 bits */ flags |= IORESOURCE_MEM; |
e3c71a329 sparc: Fix resour... |
86 |
break; |
cf44bbc26 [SPARC]: Beginnin... |
87 88 89 90 91 |
} if (w & 0x40000000) flags |= IORESOURCE_PREFETCH; return flags; } |
bdba4d6b7 sparc32: Fix func... |
92 |
static unsigned long of_bus_sbus_get_flags(const u32 *addr, unsigned long flags) |
cf44bbc26 [SPARC]: Beginnin... |
93 94 95 |
{ return IORESOURCE_MEM; } |
e63829de3 sparc,leon: Added... |
96 97 98 99 100 101 |
/* * AMBAPP bus specific translator */ static int of_bus_ambapp_match(struct device_node *np) { |
d7ecfb3c2 sparc: Fix incorr... |
102 |
return !strcmp(np->type, "ambapp"); |
e63829de3 sparc,leon: Added... |
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
} static void of_bus_ambapp_count_cells(struct device_node *child, int *addrc, int *sizec) { if (addrc) *addrc = 1; if (sizec) *sizec = 1; } static int of_bus_ambapp_map(u32 *addr, const u32 *range, int na, int ns, int pna) { return of_bus_default_map(addr, range, na, ns, pna); } static unsigned long of_bus_ambapp_get_flags(const u32 *addr, unsigned long flags) { return IORESOURCE_MEM; } |
cf44bbc26 [SPARC]: Beginnin... |
125 126 127 128 129 130 131 132 133 134 135 136 137 |
/* * 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 [SPARC]: Beginnin... |
138 139 140 141 142 143 144 145 |
.get_flags = of_bus_pci_get_flags, }, /* SBUS */ { .name = "sbus", .addr_prop_name = "reg", .match = of_bus_sbus_match, .count_cells = of_bus_sbus_count_cells, |
c9f5b7e77 sparc: move of_de... |
146 |
.map = of_bus_default_map, |
cf44bbc26 [SPARC]: Beginnin... |
147 148 |
.get_flags = of_bus_sbus_get_flags, }, |
e63829de3 sparc,leon: Added... |
149 150 151 152 153 154 155 156 157 |
/* AMBA */ { .name = "ambapp", .addr_prop_name = "reg", .match = of_bus_ambapp_match, .count_cells = of_bus_ambapp_count_cells, .map = of_bus_ambapp_map, .get_flags = of_bus_ambapp_get_flags, }, |
cf44bbc26 [SPARC]: Beginnin... |
158 159 160 161 162 163 164 |
/* Default */ { .name = "default", .addr_prop_name = "reg", .match = NULL, .count_cells = of_bus_default_count_cells, .map = of_bus_default_map, |
cf44bbc26 [SPARC]: Beginnin... |
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
.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) { |
8271f0424 [SPARC]: constify... |
186 |
const u32 *ranges; |
cf44bbc26 [SPARC]: Beginnin... |
187 188 |
unsigned int rlen; int rone; |
cf44bbc26 [SPARC]: Beginnin... |
189 190 191 |
ranges = of_get_property(parent, "ranges", &rlen); if (ranges == NULL || rlen == 0) { |
a83f98231 [SPARC]: Fix OF r... |
192 193 194 195 196 197 198 199 200 201 |
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 [SPARC]: Beginnin... |
202 203 204 205 206 207 |
} /* Now walk through the ranges */ rlen /= 4; rone = na + pna + ns; for (; rlen >= rone; rlen -= rone, ranges += rone) { |
a83f98231 [SPARC]: Fix OF r... |
208 209 |
if (!bus->map(addr, ranges, na, ns, pna)) return 0; |
cf44bbc26 [SPARC]: Beginnin... |
210 |
} |
cf44bbc26 [SPARC]: Beginnin... |
211 |
|
a83f98231 [SPARC]: Fix OF r... |
212 |
return 1; |
cf44bbc26 [SPARC]: Beginnin... |
213 |
} |
5280267c1 sparc: Fix handli... |
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
static int __init use_1to1_mapping(struct device_node *pp) { /* If we have a ranges property in the parent, use it. */ if (of_find_property(pp, "ranges", NULL) != NULL) return 0; /* 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. */ if (!strcmp(pp->name, "dma") || !strcmp(pp->name, "espdma") || !strcmp(pp->name, "ledma") || !strcmp(pp->name, "lebuffer")) return 0; return 1; } |
a83f98231 [SPARC]: Fix OF r... |
234 |
static int of_resource_verbose; |
cd4cd7306 sparc: remove ref... |
235 |
static void __init build_device_resources(struct platform_device *op, |
cf44bbc26 [SPARC]: Beginnin... |
236 237 |
struct device *parent) { |
cd4cd7306 sparc: remove ref... |
238 |
struct platform_device *p_op; |
cf44bbc26 [SPARC]: Beginnin... |
239 240 241 |
struct of_bus *bus; int na, ns; int index, num_reg; |
8271f0424 [SPARC]: constify... |
242 |
const void *preg; |
cf44bbc26 [SPARC]: Beginnin... |
243 244 245 |
if (!parent) return; |
cd4cd7306 sparc: remove ref... |
246 |
p_op = to_platform_device(parent); |
61c7a080a of: Always use 's... |
247 248 |
bus = of_match_bus(p_op->dev.of_node); bus->count_cells(op->dev.of_node, &na, &ns); |
cf44bbc26 [SPARC]: Beginnin... |
249 |
|
61c7a080a of: Always use 's... |
250 |
preg = of_get_property(op->dev.of_node, bus->addr_prop_name, &num_reg); |
cf44bbc26 [SPARC]: Beginnin... |
251 252 253 254 255 256 257 258 |
if (!preg || num_reg == 0) return; /* Convert to num-cells. */ num_reg /= 4; /* Conver to num-entries. */ num_reg /= na + ns; |
1636f8ac2 sparc/of: Move of... |
259 260 |
op->resource = op->archdata.resource; op->num_resources = num_reg; |
cf44bbc26 [SPARC]: Beginnin... |
261 262 263 |
for (index = 0; index < num_reg; index++) { struct resource *r = &op->resource[index]; u32 addr[OF_MAX_ADDR_CELLS]; |
8271f0424 [SPARC]: constify... |
264 |
const u32 *reg = (preg + (index * ((na + ns) * 4))); |
61c7a080a of: Always use 's... |
265 266 |
struct device_node *dp = op->dev.of_node; struct device_node *pp = p_op->dev.of_node; |
b85cdd490 [SPARC]: Fix bus ... |
267 |
struct of_bus *pbus, *dbus; |
cf44bbc26 [SPARC]: Beginnin... |
268 269 270 271 272 273 |
u64 size, result = OF_BAD_ADDR; unsigned long flags; int dna, dns; int pna, pns; size = of_read_addr(reg + na, ns); |
cf44bbc26 [SPARC]: Beginnin... |
274 275 |
memcpy(addr, reg, na * 4); |
e3c71a329 sparc: Fix resour... |
276 |
flags = bus->get_flags(reg, 0); |
5280267c1 sparc: Fix handli... |
277 |
if (use_1to1_mapping(pp)) { |
cf44bbc26 [SPARC]: Beginnin... |
278 279 280 281 282 283 |
result = of_read_addr(addr, na); goto build_res; } dna = na; dns = ns; |
b85cdd490 [SPARC]: Fix bus ... |
284 |
dbus = bus; |
cf44bbc26 [SPARC]: Beginnin... |
285 286 287 288 289 290 291 292 293 294 295 |
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 [SPARC]: Fix bus ... |
296 |
if (build_one_resource(dp, dbus, pbus, addr, |
a83f98231 [SPARC]: Fix OF r... |
297 |
dna, dns, pna)) |
cf44bbc26 [SPARC]: Beginnin... |
298 |
break; |
e3c71a329 sparc: Fix resour... |
299 |
flags = pbus->get_flags(addr, flags); |
cf44bbc26 [SPARC]: Beginnin... |
300 301 |
dna = pna; dns = pns; |
b85cdd490 [SPARC]: Fix bus ... |
302 |
dbus = pbus; |
cf44bbc26 [SPARC]: Beginnin... |
303 304 305 306 |
} build_res: memset(r, 0, sizeof(*r)); |
a83f98231 [SPARC]: Fix OF r... |
307 308 309 310 |
if (of_resource_verbose) printk("%s reg[%d] -> %llx ", |
61c7a080a of: Always use 's... |
311 |
op->dev.of_node->full_name, index, |
a83f98231 [SPARC]: Fix OF r... |
312 |
result); |
cf44bbc26 [SPARC]: Beginnin... |
313 |
if (result != OF_BAD_ADDR) { |
95714e12d [SPARC]: Encode I... |
314 |
r->start = result & 0xffffffff; |
cf44bbc26 [SPARC]: Beginnin... |
315 |
r->end = result + size - 1; |
95714e12d [SPARC]: Encode I... |
316 |
r->flags = flags | ((result >> 32ULL) & 0xffUL); |
cf44bbc26 [SPARC]: Beginnin... |
317 |
} |
61c7a080a of: Always use 's... |
318 |
r->name = op->dev.of_node->name; |
cf44bbc26 [SPARC]: Beginnin... |
319 320 |
} } |
cd4cd7306 sparc: remove ref... |
321 |
static struct platform_device * __init scan_one_device(struct device_node *dp, |
cf44bbc26 [SPARC]: Beginnin... |
322 323 |
struct device *parent) { |
cd4cd7306 sparc: remove ref... |
324 |
struct platform_device *op = kzalloc(sizeof(*op), GFP_KERNEL); |
8271f0424 [SPARC]: constify... |
325 |
const struct linux_prom_irqs *intr; |
3d6e47023 [SPARC]: Make sur... |
326 |
struct dev_archdata *sd; |
8f96cd1a6 [SPARC]: sparc32 ... |
327 |
int len, i; |
cf44bbc26 [SPARC]: Beginnin... |
328 329 330 |
if (!op) return NULL; |
3d6e47023 [SPARC]: Make sur... |
331 |
sd = &op->dev.archdata; |
3d6e47023 [SPARC]: Make sur... |
332 |
sd->op = op; |
d706c1b05 driver-core: Add ... |
333 |
op->dev.of_node = dp; |
cf44bbc26 [SPARC]: Beginnin... |
334 |
|
8f96cd1a6 [SPARC]: sparc32 ... |
335 336 |
intr = of_get_property(dp, "intr", &len); if (intr) { |
1636f8ac2 sparc/of: Move of... |
337 338 |
op->archdata.num_irqs = len / sizeof(struct linux_prom_irqs); for (i = 0; i < op->archdata.num_irqs; i++) |
1d05995b0 sparc32: introduc... |
339 |
op->archdata.irqs[i] = |
472bc4f2a sparc32: rename s... |
340 |
sparc_config.build_device_irq(op, intr[i].pri); |
8f96cd1a6 [SPARC]: sparc32 ... |
341 |
} else { |
8271f0424 [SPARC]: constify... |
342 343 |
const unsigned int *irq = of_get_property(dp, "interrupts", &len); |
8f96cd1a6 [SPARC]: sparc32 ... |
344 345 |
if (irq) { |
1636f8ac2 sparc/of: Move of... |
346 347 |
op->archdata.num_irqs = len / sizeof(unsigned int); for (i = 0; i < op->archdata.num_irqs; i++) |
1d05995b0 sparc32: introduc... |
348 |
op->archdata.irqs[i] = |
472bc4f2a sparc32: rename s... |
349 |
sparc_config.build_device_irq(op, irq[i]); |
8f96cd1a6 [SPARC]: sparc32 ... |
350 |
} else { |
1636f8ac2 sparc/of: Move of... |
351 |
op->archdata.num_irqs = 0; |
8f96cd1a6 [SPARC]: sparc32 ... |
352 353 |
} } |
cf44bbc26 [SPARC]: Beginnin... |
354 355 356 357 |
build_device_resources(op, parent); op->dev.parent = parent; |
eca393016 of: Merge of_plat... |
358 |
op->dev.bus = &platform_bus_type; |
cf44bbc26 [SPARC]: Beginnin... |
359 |
if (!parent) |
5acdc1fa2 sparc: struct dev... |
360 |
dev_set_name(&op->dev, "root"); |
cf44bbc26 [SPARC]: Beginnin... |
361 |
else |
6016a363f of: unify phandle... |
362 |
dev_set_name(&op->dev, "%08x", dp->phandle); |
cf44bbc26 [SPARC]: Beginnin... |
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
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 sparc: remove ref... |
378 |
struct platform_device *op = scan_one_device(dp, parent); |
cf44bbc26 [SPARC]: Beginnin... |
379 380 381 382 383 384 385 |
if (op) scan_tree(dp->child, &op->dev); dp = dp->sibling; } } |
eca393016 of: Merge of_plat... |
386 |
static int __init scan_of_devices(void) |
cf44bbc26 [SPARC]: Beginnin... |
387 388 |
{ struct device_node *root = of_find_node_by_path("/"); |
cd4cd7306 sparc: remove ref... |
389 |
struct platform_device *parent; |
cf44bbc26 [SPARC]: Beginnin... |
390 391 392 |
parent = scan_one_device(root, NULL); if (!parent) |
eca393016 of: Merge of_plat... |
393 |
return 0; |
cf44bbc26 [SPARC]: Beginnin... |
394 395 |
scan_tree(root->child, &parent->dev); |
eca393016 of: Merge of_plat... |
396 |
return 0; |
cf44bbc26 [SPARC]: Beginnin... |
397 |
} |
eca393016 of: Merge of_plat... |
398 |
postcore_initcall(scan_of_devices); |
fd5314311 [SPARC]: Port of_... |
399 |
|
a83f98231 [SPARC]: Fix OF r... |
400 401 402 403 404 405 406 407 408 409 410 |
static int __init of_debug(char *str) { int val = 0; get_option(&str, &val); if (val & 1) of_resource_verbose = 1; return 1; } __setup("of_debug=", of_debug); |