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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [sbus/] [sbus.c] - Blame information for rev 78

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/* sbus.c: SBus support routines.
2
 *
3
 * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net)
4
 */
5
 
6
#include <linux/kernel.h>
7
#include <linux/slab.h>
8
#include <linux/init.h>
9
#include <linux/device.h>
10
 
11
#include <asm/system.h>
12
#include <asm/sbus.h>
13
#include <asm/dma.h>
14
#include <asm/oplib.h>
15
#include <asm/prom.h>
16
#include <asm/of_device.h>
17
#include <asm/bpp.h>
18
#include <asm/irq.h>
19
 
20
static ssize_t
21
show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
22
{
23
        struct sbus_dev *sbus;
24
 
25
        sbus = to_sbus_device(dev);
26
 
27
        return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name);
28
}
29
 
30
static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL);
31
 
32
struct sbus_bus *sbus_root;
33
 
34
static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
35
{
36
        struct dev_archdata *sd;
37
        unsigned long base;
38
        const void *pval;
39
        int len, err;
40
 
41
        sdev->prom_node = dp->node;
42
        strcpy(sdev->prom_name, dp->name);
43
 
44
        pval = of_get_property(dp, "reg", &len);
45
        sdev->num_registers = 0;
46
        if (pval) {
47
                memcpy(sdev->reg_addrs, pval, len);
48
 
49
                sdev->num_registers =
50
                        len / sizeof(struct linux_prom_registers);
51
 
52
                base = (unsigned long) sdev->reg_addrs[0].phys_addr;
53
 
54
                /* Compute the slot number. */
55
                if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m)
56
                        sdev->slot = sbus_dev_slot(base);
57
                else
58
                        sdev->slot = sdev->reg_addrs[0].which_io;
59
        }
60
 
61
        pval = of_get_property(dp, "ranges", &len);
62
        sdev->num_device_ranges = 0;
63
        if (pval) {
64
                memcpy(sdev->device_ranges, pval, len);
65
                sdev->num_device_ranges =
66
                        len / sizeof(struct linux_prom_ranges);
67
        }
68
 
69
        sbus_fill_device_irq(sdev);
70
 
71
        sd = &sdev->ofdev.dev.archdata;
72
        sd->prom_node = dp;
73
        sd->op = &sdev->ofdev;
74
 
75
        sdev->ofdev.node = dp;
76
        if (sdev->parent)
77
                sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
78
        else
79
                sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev;
80
        sdev->ofdev.dev.bus = &sbus_bus_type;
81
        sprintf(sdev->ofdev.dev.bus_id, "sbus[%08x]", dp->node);
82
 
83
        if (of_device_register(&sdev->ofdev) != 0)
84
                printk(KERN_DEBUG "sbus: device registration error for %s!\n",
85
                       dp->path_component_name);
86
 
87
        /* WE HAVE BEEN INVADED BY ALIENS! */
88
        err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr);
89
}
90
 
91
static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
92
{
93
        const void *pval;
94
        int len;
95
 
96
        pval = of_get_property(dp, "ranges", &len);
97
        sbus->num_sbus_ranges = 0;
98
        if (pval) {
99
                memcpy(sbus->sbus_ranges, pval, len);
100
                sbus->num_sbus_ranges =
101
                        len / sizeof(struct linux_prom_ranges);
102
 
103
                sbus_arch_bus_ranges_init(dp->parent, sbus);
104
        }
105
}
106
 
107
static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges,
108
                                          int num_ranges,
109
                                          struct linux_prom_registers *regs,
110
                                          int num_regs)
111
{
112
        if (num_ranges) {
113
                int regnum;
114
 
115
                for (regnum = 0; regnum < num_regs; regnum++) {
116
                        int rngnum;
117
 
118
                        for (rngnum = 0; rngnum < num_ranges; rngnum++) {
119
                                if (regs[regnum].which_io == ranges[rngnum].ot_child_space)
120
                                        break;
121
                        }
122
                        if (rngnum == num_ranges) {
123
                                /* We used to flag this as an error.  Actually
124
                                 * some devices do not report the regs as we expect.
125
                                 * For example, see SUNW,pln device.  In that case
126
                                 * the reg property is in a format internal to that
127
                                 * node, ie. it is not in the SBUS register space
128
                                 * per se. -DaveM
129
                                 */
130
                                return;
131
                        }
132
                        regs[regnum].which_io = ranges[rngnum].ot_parent_space;
133
                        regs[regnum].phys_addr -= ranges[rngnum].ot_child_base;
134
                        regs[regnum].phys_addr += ranges[rngnum].ot_parent_base;
135
                }
136
        }
137
}
138
 
139
static void __init __fixup_regs_sdev(struct sbus_dev *sdev)
140
{
141
        if (sdev->num_registers != 0) {
142
                struct sbus_dev *parent = sdev->parent;
143
                int i;
144
 
145
                while (parent != NULL) {
146
                        __apply_ranges_to_regs(parent->device_ranges,
147
                                               parent->num_device_ranges,
148
                                               sdev->reg_addrs,
149
                                               sdev->num_registers);
150
 
151
                        parent = parent->parent;
152
                }
153
 
154
                __apply_ranges_to_regs(sdev->bus->sbus_ranges,
155
                                       sdev->bus->num_sbus_ranges,
156
                                       sdev->reg_addrs,
157
                                       sdev->num_registers);
158
 
159
                for (i = 0; i < sdev->num_registers; i++) {
160
                        struct resource *res = &sdev->resource[i];
161
 
162
                        res->start = sdev->reg_addrs[i].phys_addr;
163
                        res->end = (res->start +
164
                                    (unsigned long)sdev->reg_addrs[i].reg_size - 1UL);
165
                        res->flags = IORESOURCE_IO |
166
                                (sdev->reg_addrs[i].which_io & 0xff);
167
                }
168
        }
169
}
170
 
171
static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev)
172
{
173
        struct sbus_dev *sdev;
174
 
175
        for (sdev = first_sdev; sdev; sdev = sdev->next) {
176
                if (sdev->child)
177
                        sbus_fixup_all_regs(sdev->child);
178
                __fixup_regs_sdev(sdev);
179
        }
180
}
181
 
182
/* We preserve the "probe order" of these bus and device lists to give
183
 * the same ordering as the old code.
184
 */
185
static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root)
186
{
187
        while (*root)
188
                root = &(*root)->next;
189
        *root = sbus;
190
        sbus->next = NULL;
191
}
192
 
193
static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root)
194
{
195
        while (*root)
196
                root = &(*root)->next;
197
        *root = sdev;
198
        sdev->next = NULL;
199
}
200
 
201
static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus)
202
{
203
        dp = dp->child;
204
        while (dp) {
205
                struct sbus_dev *sdev;
206
 
207
                sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
208
                if (sdev) {
209
                        sdev_insert(sdev, &parent->child);
210
 
211
                        sdev->bus = sbus;
212
                        sdev->parent = parent;
213
                        sdev->ofdev.dev.archdata.iommu =
214
                                sbus->ofdev.dev.archdata.iommu;
215
                        sdev->ofdev.dev.archdata.stc =
216
                                sbus->ofdev.dev.archdata.stc;
217
 
218
                        fill_sbus_device(dp, sdev);
219
 
220
                        walk_children(dp, sdev, sbus);
221
                }
222
                dp = dp->sibling;
223
        }
224
}
225
 
226
static void __init build_one_sbus(struct device_node *dp, int num_sbus)
227
{
228
        struct sbus_bus *sbus;
229
        unsigned int sbus_clock;
230
        struct device_node *dev_dp;
231
 
232
        sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
233
        if (!sbus)
234
                return;
235
 
236
        sbus_insert(sbus, &sbus_root);
237
        sbus->prom_node = dp->node;
238
 
239
        sbus_setup_iommu(sbus, dp);
240
 
241
        printk("sbus%d: ", num_sbus);
242
 
243
        sbus_clock = of_getintprop_default(dp, "clock-frequency",
244
                                           (25*1000*1000));
245
        sbus->clock_freq = sbus_clock;
246
 
247
        printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
248
               (int) (((sbus_clock/1000)%1000 != 0) ?
249
                      (((sbus_clock/1000)%1000) + 1000) : 0));
250
 
251
        strcpy(sbus->prom_name, dp->name);
252
 
253
        sbus_setup_arch_props(sbus, dp);
254
 
255
        sbus_bus_ranges_init(dp, sbus);
256
 
257
        sbus->ofdev.node = dp;
258
        sbus->ofdev.dev.parent = NULL;
259
        sbus->ofdev.dev.bus = &sbus_bus_type;
260
        sprintf(sbus->ofdev.dev.bus_id, "sbus%d", num_sbus);
261
 
262
        if (of_device_register(&sbus->ofdev) != 0)
263
                printk(KERN_DEBUG "sbus: device registration error for %s!\n",
264
                       sbus->ofdev.dev.bus_id);
265
 
266
        dev_dp = dp->child;
267
        while (dev_dp) {
268
                struct sbus_dev *sdev;
269
 
270
                sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
271
                if (sdev) {
272
                        sdev_insert(sdev, &sbus->devices);
273
 
274
                        sdev->bus = sbus;
275
                        sdev->parent = NULL;
276
                        sdev->ofdev.dev.archdata.iommu =
277
                                sbus->ofdev.dev.archdata.iommu;
278
                        sdev->ofdev.dev.archdata.stc =
279
                                sbus->ofdev.dev.archdata.stc;
280
 
281
                        fill_sbus_device(dev_dp, sdev);
282
 
283
                        walk_children(dev_dp, sdev, sbus);
284
                }
285
                dev_dp = dev_dp->sibling;
286
        }
287
 
288
        sbus_fixup_all_regs(sbus->devices);
289
 
290
        dvma_init(sbus);
291
}
292
 
293
static int __init sbus_init(void)
294
{
295
        struct device_node *dp;
296
        const char *sbus_name = "sbus";
297
        int num_sbus = 0;
298
 
299
        if (sbus_arch_preinit())
300
                return 0;
301
 
302
        if (sparc_cpu_model == sun4d)
303
                sbus_name = "sbi";
304
 
305
        for_each_node_by_name(dp, sbus_name) {
306
                build_one_sbus(dp, num_sbus);
307
                num_sbus++;
308
 
309
        }
310
 
311
        sbus_arch_postinit();
312
 
313
        return 0;
314
}
315
 
316
subsys_initcall(sbus_init);

powered by: WebSVN 2.1.0

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