OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [sparc/] [kernel/] [of_device.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
#include <linux/string.h>
2
#include <linux/kernel.h>
3
#include <linux/of.h>
4
#include <linux/init.h>
5
#include <linux/module.h>
6
#include <linux/mod_devicetable.h>
7
#include <linux/slab.h>
8
#include <linux/errno.h>
9
#include <linux/of_device.h>
10
#include <linux/of_platform.h>
11
 
12
static int node_match(struct device *dev, void *data)
13
{
14
        struct of_device *op = to_of_device(dev);
15
        struct device_node *dp = data;
16
 
17
        return (op->node == dp);
18
}
19
 
20
struct of_device *of_find_device_by_node(struct device_node *dp)
21
{
22
        struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
23
                                             dp, node_match);
24
 
25
        if (dev)
26
                return to_of_device(dev);
27
 
28
        return NULL;
29
}
30
EXPORT_SYMBOL(of_find_device_by_node);
31
 
32
#ifdef CONFIG_PCI
33
struct bus_type ebus_bus_type;
34
EXPORT_SYMBOL(ebus_bus_type);
35
#endif
36
 
37
#ifdef CONFIG_SBUS
38
struct bus_type sbus_bus_type;
39
EXPORT_SYMBOL(sbus_bus_type);
40
#endif
41
 
42
struct bus_type of_platform_bus_type;
43
EXPORT_SYMBOL(of_platform_bus_type);
44
 
45
static inline u64 of_read_addr(const u32 *cell, int size)
46
{
47
        u64 r = 0;
48
        while (size--)
49
                r = (r << 32) | *(cell++);
50
        return r;
51
}
52
 
53
static void __init get_cells(struct device_node *dp,
54
                             int *addrc, int *sizec)
55
{
56
        if (addrc)
57
                *addrc = of_n_addr_cells(dp);
58
        if (sizec)
59
                *sizec = of_n_size_cells(dp);
60
}
61
 
62
/* Max address size we deal with */
63
#define OF_MAX_ADDR_CELLS       4
64
 
65
struct of_bus {
66
        const char      *name;
67
        const char      *addr_prop_name;
68
        int             (*match)(struct device_node *parent);
69
        void            (*count_cells)(struct device_node *child,
70
                                       int *addrc, int *sizec);
71
        int             (*map)(u32 *addr, const u32 *range,
72
                               int na, int ns, int pna);
73
        unsigned int    (*get_flags)(const u32 *addr);
74
};
75
 
76
/*
77
 * Default translator (generic bus)
78
 */
79
 
80
static void of_bus_default_count_cells(struct device_node *dev,
81
                                       int *addrc, int *sizec)
82
{
83
        get_cells(dev, addrc, sizec);
84
}
85
 
86
/* Make sure the least significant 64-bits are in-range.  Even
87
 * for 3 or 4 cell values it is a good enough approximation.
88
 */
89
static int of_out_of_range(const u32 *addr, const u32 *base,
90
                           const u32 *size, int na, int ns)
91
{
92
        u64 a = of_read_addr(addr, na);
93
        u64 b = of_read_addr(base, na);
94
 
95
        if (a < b)
96
                return 1;
97
 
98
        b += of_read_addr(size, ns);
99
        if (a >= b)
100
                return 1;
101
 
102
        return 0;
103
}
104
 
105
static int of_bus_default_map(u32 *addr, const u32 *range,
106
                              int na, int ns, int pna)
107
{
108
        u32 result[OF_MAX_ADDR_CELLS];
109
        int i;
110
 
111
        if (ns > 2) {
112
                printk("of_device: Cannot handle size cells (%d) > 2.", ns);
113
                return -EINVAL;
114
        }
115
 
116
        if (of_out_of_range(addr, range, range + na + pna, na, ns))
117
                return -EINVAL;
118
 
119
        /* Start with the parent range base.  */
120
        memcpy(result, range + na, pna * 4);
121
 
122
        /* Add in the child address offset.  */
123
        for (i = 0; i < na; i++)
124
                result[pna - 1 - i] +=
125
                        (addr[na - 1 - i] -
126
                         range[na - 1 - i]);
127
 
128
        memcpy(addr, result, pna * 4);
129
 
130
        return 0;
131
}
132
 
133
static unsigned int of_bus_default_get_flags(const u32 *addr)
134
{
135
        return IORESOURCE_MEM;
136
}
137
 
138
/*
139
 * PCI bus specific translator
140
 */
141
 
142
static int of_bus_pci_match(struct device_node *np)
143
{
144
        if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
145
                /* Do not do PCI specific frobbing if the
146
                 * PCI bridge lacks a ranges property.  We
147
                 * want to pass it through up to the next
148
                 * parent as-is, not with the PCI translate
149
                 * method which chops off the top address cell.
150
                 */
151
                if (!of_find_property(np, "ranges", NULL))
152
                        return 0;
153
 
154
                return 1;
155
        }
156
 
157
        return 0;
158
}
159
 
160
static void of_bus_pci_count_cells(struct device_node *np,
161
                                   int *addrc, int *sizec)
162
{
163
        if (addrc)
164
                *addrc = 3;
165
        if (sizec)
166
                *sizec = 2;
167
}
168
 
169
static int of_bus_pci_map(u32 *addr, const u32 *range,
170
                          int na, int ns, int pna)
171
{
172
        u32 result[OF_MAX_ADDR_CELLS];
173
        int i;
174
 
175
        /* Check address type match */
176
        if ((addr[0] ^ range[0]) & 0x03000000)
177
                return -EINVAL;
178
 
179
        if (of_out_of_range(addr + 1, range + 1, range + na + pna,
180
                            na - 1, ns))
181
                return -EINVAL;
182
 
183
        /* Start with the parent range base.  */
184
        memcpy(result, range + na, pna * 4);
185
 
186
        /* Add in the child address offset, skipping high cell.  */
187
        for (i = 0; i < na - 1; i++)
188
                result[pna - 1 - i] +=
189
                        (addr[na - 1 - i] -
190
                         range[na - 1 - i]);
191
 
192
        memcpy(addr, result, pna * 4);
193
 
194
        return 0;
195
}
196
 
197
static unsigned int of_bus_pci_get_flags(const u32 *addr)
198
{
199
        unsigned int flags = 0;
200
        u32 w = addr[0];
201
 
202
        switch((w >> 24) & 0x03) {
203
        case 0x01:
204
                flags |= IORESOURCE_IO;
205
        case 0x02: /* 32 bits */
206
        case 0x03: /* 64 bits */
207
                flags |= IORESOURCE_MEM;
208
        }
209
        if (w & 0x40000000)
210
                flags |= IORESOURCE_PREFETCH;
211
        return flags;
212
}
213
 
214
/*
215
 * SBUS bus specific translator
216
 */
217
 
218
static int of_bus_sbus_match(struct device_node *np)
219
{
220
        return !strcmp(np->name, "sbus") ||
221
                !strcmp(np->name, "sbi");
222
}
223
 
224
static void of_bus_sbus_count_cells(struct device_node *child,
225
                                   int *addrc, int *sizec)
226
{
227
        if (addrc)
228
                *addrc = 2;
229
        if (sizec)
230
                *sizec = 1;
231
}
232
 
233
static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
234
{
235
        return of_bus_default_map(addr, range, na, ns, pna);
236
}
237
 
238
static unsigned int of_bus_sbus_get_flags(const u32 *addr)
239
{
240
        return IORESOURCE_MEM;
241
}
242
 
243
 
244
/*
245
 * Array of bus specific translators
246
 */
247
 
248
static struct of_bus of_busses[] = {
249
        /* PCI */
250
        {
251
                .name = "pci",
252
                .addr_prop_name = "assigned-addresses",
253
                .match = of_bus_pci_match,
254
                .count_cells = of_bus_pci_count_cells,
255
                .map = of_bus_pci_map,
256
                .get_flags = of_bus_pci_get_flags,
257
        },
258
        /* SBUS */
259
        {
260
                .name = "sbus",
261
                .addr_prop_name = "reg",
262
                .match = of_bus_sbus_match,
263
                .count_cells = of_bus_sbus_count_cells,
264
                .map = of_bus_sbus_map,
265
                .get_flags = of_bus_sbus_get_flags,
266
        },
267
        /* Default */
268
        {
269
                .name = "default",
270
                .addr_prop_name = "reg",
271
                .match = NULL,
272
                .count_cells = of_bus_default_count_cells,
273
                .map = of_bus_default_map,
274
                .get_flags = of_bus_default_get_flags,
275
        },
276
};
277
 
278
static struct of_bus *of_match_bus(struct device_node *np)
279
{
280
        int i;
281
 
282
        for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
283
                if (!of_busses[i].match || of_busses[i].match(np))
284
                        return &of_busses[i];
285
        BUG();
286
        return NULL;
287
}
288
 
289
static int __init build_one_resource(struct device_node *parent,
290
                                     struct of_bus *bus,
291
                                     struct of_bus *pbus,
292
                                     u32 *addr,
293
                                     int na, int ns, int pna)
294
{
295
        const u32 *ranges;
296
        unsigned int rlen;
297
        int rone;
298
 
299
        ranges = of_get_property(parent, "ranges", &rlen);
300
        if (ranges == NULL || rlen == 0) {
301
                u32 result[OF_MAX_ADDR_CELLS];
302
                int i;
303
 
304
                memset(result, 0, pna * 4);
305
                for (i = 0; i < na; i++)
306
                        result[pna - 1 - i] =
307
                                addr[na - 1 - i];
308
 
309
                memcpy(addr, result, pna * 4);
310
                return 0;
311
        }
312
 
313
        /* Now walk through the ranges */
314
        rlen /= 4;
315
        rone = na + pna + ns;
316
        for (; rlen >= rone; rlen -= rone, ranges += rone) {
317
                if (!bus->map(addr, ranges, na, ns, pna))
318
                        return 0;
319
        }
320
 
321
        return 1;
322
}
323
 
324
static int of_resource_verbose;
325
 
326
static void __init build_device_resources(struct of_device *op,
327
                                          struct device *parent)
328
{
329
        struct of_device *p_op;
330
        struct of_bus *bus;
331
        int na, ns;
332
        int index, num_reg;
333
        const void *preg;
334
 
335
        if (!parent)
336
                return;
337
 
338
        p_op = to_of_device(parent);
339
        bus = of_match_bus(p_op->node);
340
        bus->count_cells(op->node, &na, &ns);
341
 
342
        preg = of_get_property(op->node, bus->addr_prop_name, &num_reg);
343
        if (!preg || num_reg == 0)
344
                return;
345
 
346
        /* Convert to num-cells.  */
347
        num_reg /= 4;
348
 
349
        /* Conver to num-entries.  */
350
        num_reg /= na + ns;
351
 
352
        for (index = 0; index < num_reg; index++) {
353
                struct resource *r = &op->resource[index];
354
                u32 addr[OF_MAX_ADDR_CELLS];
355
                const u32 *reg = (preg + (index * ((na + ns) * 4)));
356
                struct device_node *dp = op->node;
357
                struct device_node *pp = p_op->node;
358
                struct of_bus *pbus, *dbus;
359
                u64 size, result = OF_BAD_ADDR;
360
                unsigned long flags;
361
                int dna, dns;
362
                int pna, pns;
363
 
364
                size = of_read_addr(reg + na, ns);
365
                flags = bus->get_flags(reg);
366
 
367
                memcpy(addr, reg, na * 4);
368
 
369
                /* If the immediate parent has no ranges property to apply,
370
                 * just use a 1<->1 mapping.
371
                 */
372
                if (of_find_property(pp, "ranges", NULL) == NULL) {
373
                        result = of_read_addr(addr, na);
374
                        goto build_res;
375
                }
376
 
377
                dna = na;
378
                dns = ns;
379
                dbus = bus;
380
 
381
                while (1) {
382
                        dp = pp;
383
                        pp = dp->parent;
384
                        if (!pp) {
385
                                result = of_read_addr(addr, dna);
386
                                break;
387
                        }
388
 
389
                        pbus = of_match_bus(pp);
390
                        pbus->count_cells(dp, &pna, &pns);
391
 
392
                        if (build_one_resource(dp, dbus, pbus, addr,
393
                                               dna, dns, pna))
394
                                break;
395
 
396
                        dna = pna;
397
                        dns = pns;
398
                        dbus = pbus;
399
                }
400
 
401
        build_res:
402
                memset(r, 0, sizeof(*r));
403
 
404
                if (of_resource_verbose)
405
                        printk("%s reg[%d] -> %llx\n",
406
                               op->node->full_name, index,
407
                               result);
408
 
409
                if (result != OF_BAD_ADDR) {
410
                        r->start = result & 0xffffffff;
411
                        r->end = result + size - 1;
412
                        r->flags = flags | ((result >> 32ULL) & 0xffUL);
413
                }
414
                r->name = op->node->name;
415
        }
416
}
417
 
418
static struct of_device * __init scan_one_device(struct device_node *dp,
419
                                                 struct device *parent)
420
{
421
        struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
422
        const struct linux_prom_irqs *intr;
423
        struct dev_archdata *sd;
424
        int len, i;
425
 
426
        if (!op)
427
                return NULL;
428
 
429
        sd = &op->dev.archdata;
430
        sd->prom_node = dp;
431
        sd->op = op;
432
 
433
        op->node = dp;
434
 
435
        op->clock_freq = of_getintprop_default(dp, "clock-frequency",
436
                                               (25*1000*1000));
437
        op->portid = of_getintprop_default(dp, "upa-portid", -1);
438
        if (op->portid == -1)
439
                op->portid = of_getintprop_default(dp, "portid", -1);
440
 
441
        intr = of_get_property(dp, "intr", &len);
442
        if (intr) {
443
                op->num_irqs = len / sizeof(struct linux_prom_irqs);
444
                for (i = 0; i < op->num_irqs; i++)
445
                        op->irqs[i] = intr[i].pri;
446
        } else {
447
                const unsigned int *irq =
448
                        of_get_property(dp, "interrupts", &len);
449
 
450
                if (irq) {
451
                        op->num_irqs = len / sizeof(unsigned int);
452
                        for (i = 0; i < op->num_irqs; i++)
453
                                op->irqs[i] = irq[i];
454
                } else {
455
                        op->num_irqs = 0;
456
                }
457
        }
458
        if (sparc_cpu_model == sun4d) {
459
                static int pil_to_sbus[] = {
460
                        0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0,
461
                };
462
                struct device_node *io_unit, *sbi = dp->parent;
463
                const struct linux_prom_registers *regs;
464
                int board, slot;
465
 
466
                while (sbi) {
467
                        if (!strcmp(sbi->name, "sbi"))
468
                                break;
469
 
470
                        sbi = sbi->parent;
471
                }
472
                if (!sbi)
473
                        goto build_resources;
474
 
475
                regs = of_get_property(dp, "reg", NULL);
476
                if (!regs)
477
                        goto build_resources;
478
 
479
                slot = regs->which_io;
480
 
481
                /* If SBI's parent is not io-unit or the io-unit lacks
482
                 * a "board#" property, something is very wrong.
483
                 */
484
                if (!sbi->parent || strcmp(sbi->parent->name, "io-unit")) {
485
                        printk("%s: Error, parent is not io-unit.\n",
486
                               sbi->full_name);
487
                        goto build_resources;
488
                }
489
                io_unit = sbi->parent;
490
                board = of_getintprop_default(io_unit, "board#", -1);
491
                if (board == -1) {
492
                        printk("%s: Error, lacks board# property.\n",
493
                               io_unit->full_name);
494
                        goto build_resources;
495
                }
496
 
497
                for (i = 0; i < op->num_irqs; i++) {
498
                        int this_irq = op->irqs[i];
499
                        int sbusl = pil_to_sbus[this_irq];
500
 
501
                        if (sbusl)
502
                                this_irq = (((board + 1) << 5) +
503
                                            (sbusl << 2) +
504
                                            slot);
505
 
506
                        op->irqs[i] = this_irq;
507
                }
508
        }
509
 
510
build_resources:
511
        build_device_resources(op, parent);
512
 
513
        op->dev.parent = parent;
514
        op->dev.bus = &of_platform_bus_type;
515
        if (!parent)
516
                strcpy(op->dev.bus_id, "root");
517
        else
518
                sprintf(op->dev.bus_id, "%08x", dp->node);
519
 
520
        if (of_device_register(op)) {
521
                printk("%s: Could not register of device.\n",
522
                       dp->full_name);
523
                kfree(op);
524
                op = NULL;
525
        }
526
 
527
        return op;
528
}
529
 
530
static void __init scan_tree(struct device_node *dp, struct device *parent)
531
{
532
        while (dp) {
533
                struct of_device *op = scan_one_device(dp, parent);
534
 
535
                if (op)
536
                        scan_tree(dp->child, &op->dev);
537
 
538
                dp = dp->sibling;
539
        }
540
}
541
 
542
static void __init scan_of_devices(void)
543
{
544
        struct device_node *root = of_find_node_by_path("/");
545
        struct of_device *parent;
546
 
547
        parent = scan_one_device(root, NULL);
548
        if (!parent)
549
                return;
550
 
551
        scan_tree(root->child, &parent->dev);
552
}
553
 
554
static int __init of_bus_driver_init(void)
555
{
556
        int err;
557
 
558
        err = of_bus_type_init(&of_platform_bus_type, "of");
559
#ifdef CONFIG_PCI
560
        if (!err)
561
                err = of_bus_type_init(&ebus_bus_type, "ebus");
562
#endif
563
#ifdef CONFIG_SBUS
564
        if (!err)
565
                err = of_bus_type_init(&sbus_bus_type, "sbus");
566
#endif
567
 
568
        if (!err)
569
                scan_of_devices();
570
 
571
        return err;
572
}
573
 
574
postcore_initcall(of_bus_driver_init);
575
 
576
static int __init of_debug(char *str)
577
{
578
        int val = 0;
579
 
580
        get_option(&str, &val);
581
        if (val & 1)
582
                of_resource_verbose = 1;
583
        return 1;
584
}
585
 
586
__setup("of_debug=", of_debug);
587
 
588
struct of_device* of_platform_device_create(struct device_node *np,
589
                                            const char *bus_id,
590
                                            struct device *parent,
591
                                            struct bus_type *bus)
592
{
593
        struct of_device *dev;
594
 
595
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
596
        if (!dev)
597
                return NULL;
598
 
599
        dev->dev.parent = parent;
600
        dev->dev.bus = bus;
601
        dev->dev.release = of_release_dev;
602
 
603
        strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
604
 
605
        if (of_device_register(dev) != 0) {
606
                kfree(dev);
607
                return NULL;
608
        }
609
 
610
        return dev;
611
}
612
 
613
EXPORT_SYMBOL(of_platform_device_create);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.