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