arch: don't memset(0) memory returned by memblock_alloc()
[muen/linux.git] / arch / sparc / kernel / prom_32.c
1 /*
2  * Procedures for creating, accessing and interpreting the device tree.
3  *
4  * Paul Mackerras       August 1996.
5  * Copyright (C) 1996-2005 Paul Mackerras.
6  * 
7  *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
8  *    {engebret|bergner}@us.ibm.com 
9  *
10  *  Adapted for sparc32 by David S. Miller davem@davemloft.net
11  *
12  *      This program is free software; you can redistribute it and/or
13  *      modify it under the terms of the GNU General Public License
14  *      as published by the Free Software Foundation; either version
15  *      2 of the License, or (at your option) any later version.
16  */
17
18 #include <linux/kernel.h>
19 #include <linux/types.h>
20 #include <linux/string.h>
21 #include <linux/mm.h>
22 #include <linux/memblock.h>
23
24 #include <asm/prom.h>
25 #include <asm/oplib.h>
26 #include <asm/leon.h>
27 #include <asm/leon_amba.h>
28
29 #include "prom.h"
30
31 void * __init prom_early_alloc(unsigned long size)
32 {
33         void *ret;
34
35         ret = memblock_alloc(size, SMP_CACHE_BYTES);
36
37         prom_early_allocated += size;
38
39         return ret;
40 }
41
42 /* The following routines deal with the black magic of fully naming a
43  * node.
44  *
45  * Certain well known named nodes are just the simple name string.
46  *
47  * Actual devices have an address specifier appended to the base name
48  * string, like this "foo@addr".  The "addr" can be in any number of
49  * formats, and the platform plus the type of the node determine the
50  * format and how it is constructed.
51  *
52  * For children of the ROOT node, the naming convention is fixed and
53  * determined by whether this is a sun4u or sun4v system.
54  *
55  * For children of other nodes, it is bus type specific.  So
56  * we walk up the tree until we discover a "device_type" property
57  * we recognize and we go from there.
58  */
59 static void __init sparc32_path_component(struct device_node *dp, char *tmp_buf)
60 {
61         const char *name = of_get_property(dp, "name", NULL);
62         struct linux_prom_registers *regs;
63         struct property *rprop;
64
65         rprop = of_find_property(dp, "reg", NULL);
66         if (!rprop)
67                 return;
68
69         regs = rprop->value;
70         sprintf(tmp_buf, "%s@%x,%x",
71                 name,
72                 regs->which_io, regs->phys_addr);
73 }
74
75 /* "name@slot,offset"  */
76 static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
77 {
78         const char *name = of_get_property(dp, "name", NULL);
79         struct linux_prom_registers *regs;
80         struct property *prop;
81
82         prop = of_find_property(dp, "reg", NULL);
83         if (!prop)
84                 return;
85
86         regs = prop->value;
87         sprintf(tmp_buf, "%s@%x,%x",
88                 name,
89                 regs->which_io,
90                 regs->phys_addr);
91 }
92
93 /* "name@devnum[,func]" */
94 static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
95 {
96         const char *name = of_get_property(dp, "name", NULL);
97         struct linux_prom_pci_registers *regs;
98         struct property *prop;
99         unsigned int devfn;
100
101         prop = of_find_property(dp, "reg", NULL);
102         if (!prop)
103                 return;
104
105         regs = prop->value;
106         devfn = (regs->phys_hi >> 8) & 0xff;
107         if (devfn & 0x07) {
108                 sprintf(tmp_buf, "%s@%x,%x",
109                         name,
110                         devfn >> 3,
111                         devfn & 0x07);
112         } else {
113                 sprintf(tmp_buf, "%s@%x",
114                         name,
115                         devfn >> 3);
116         }
117 }
118
119 /* "name@addrhi,addrlo" */
120 static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
121 {
122         const char *name = of_get_property(dp, "name", NULL);
123         struct linux_prom_registers *regs;
124         struct property *prop;
125
126         prop = of_find_property(dp, "reg", NULL);
127         if (!prop)
128                 return;
129
130         regs = prop->value;
131
132         sprintf(tmp_buf, "%s@%x,%x",
133                 name,
134                 regs->which_io, regs->phys_addr);
135 }
136
137 /* "name:vendor:device@irq,addrlo" */
138 static void __init ambapp_path_component(struct device_node *dp, char *tmp_buf)
139 {
140         const char *name = of_get_property(dp, "name", NULL);
141         struct amba_prom_registers *regs;
142         unsigned int *intr, *device, *vendor, reg0;
143         struct property *prop;
144         int interrupt = 0;
145
146         /* In order to get a unique ID in the device tree (multiple AMBA devices
147          * may have the same name) the node number is printed
148          */
149         prop = of_find_property(dp, "reg", NULL);
150         if (!prop) {
151                 reg0 = (unsigned int)dp->phandle;
152         } else {
153                 regs = prop->value;
154                 reg0 = regs->phys_addr;
155         }
156
157         /* Not all cores have Interrupt */
158         prop = of_find_property(dp, "interrupts", NULL);
159         if (!prop)
160                 intr = &interrupt; /* IRQ0 does not exist */
161         else
162                 intr = prop->value;
163
164         prop = of_find_property(dp, "vendor", NULL);
165         if (!prop)
166                 return;
167         vendor = prop->value;
168         prop = of_find_property(dp, "device", NULL);
169         if (!prop)
170                 return;
171         device = prop->value;
172
173         sprintf(tmp_buf, "%s:%d:%d@%x,%x",
174                 name, *vendor, *device,
175                 *intr, reg0);
176 }
177
178 static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
179 {
180         struct device_node *parent = dp->parent;
181
182         if (parent != NULL) {
183                 if (of_node_is_type(parent, "pci") ||
184                     of_node_is_type(parent, "pciex"))
185                         return pci_path_component(dp, tmp_buf);
186                 if (of_node_is_type(parent, "sbus"))
187                         return sbus_path_component(dp, tmp_buf);
188                 if (of_node_is_type(parent, "ebus"))
189                         return ebus_path_component(dp, tmp_buf);
190                 if (of_node_is_type(parent, "ambapp"))
191                         return ambapp_path_component(dp, tmp_buf);
192
193                 /* "isa" is handled with platform naming */
194         }
195
196         /* Use platform naming convention.  */
197         return sparc32_path_component(dp, tmp_buf);
198 }
199
200 char * __init build_path_component(struct device_node *dp)
201 {
202         const char *name = of_get_property(dp, "name", NULL);
203         char tmp_buf[64], *n;
204
205         tmp_buf[0] = '\0';
206         __build_path_component(dp, tmp_buf);
207         if (tmp_buf[0] == '\0')
208                 strcpy(tmp_buf, name);
209
210         n = prom_early_alloc(strlen(tmp_buf) + 1);
211         strcpy(n, tmp_buf);
212
213         return n;
214 }
215
216 extern void restore_current(void);
217
218 void __init of_console_init(void)
219 {
220         char *msg = "OF stdout device is: %s\n";
221         struct device_node *dp;
222         unsigned long flags;
223         const char *type;
224         phandle node;
225         int skip, tmp, fd;
226
227         of_console_path = prom_early_alloc(256);
228
229         switch (prom_vers) {
230         case PROM_V0:
231                 skip = 0;
232                 switch (*romvec->pv_stdout) {
233                 case PROMDEV_SCREEN:
234                         type = "display";
235                         break;
236
237                 case PROMDEV_TTYB:
238                         skip = 1;
239                         /* FALLTHRU */
240
241                 case PROMDEV_TTYA:
242                         type = "serial";
243                         break;
244
245                 default:
246                         prom_printf("Invalid PROM_V0 stdout value %u\n",
247                                     *romvec->pv_stdout);
248                         prom_halt();
249                 }
250
251                 tmp = skip;
252                 for_each_node_by_type(dp, type) {
253                         if (!tmp--)
254                                 break;
255                 }
256                 if (!dp) {
257                         prom_printf("Cannot find PROM_V0 console node.\n");
258                         prom_halt();
259                 }
260                 of_console_device = dp;
261
262                 sprintf(of_console_path, "%pOF", dp);
263                 if (!strcmp(type, "serial")) {
264                         strcat(of_console_path,
265                                (skip ? ":b" : ":a"));
266                 }
267                 break;
268
269         default:
270         case PROM_V2:
271         case PROM_V3:
272                 fd = *romvec->pv_v2bootargs.fd_stdout;
273
274                 spin_lock_irqsave(&prom_lock, flags);
275                 node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
276                 restore_current();
277                 spin_unlock_irqrestore(&prom_lock, flags);
278
279                 if (!node) {
280                         prom_printf("Cannot resolve stdout node from "
281                                     "instance %08x.\n", fd);
282                         prom_halt();
283                 }
284                 dp = of_find_node_by_phandle(node);
285
286                 if (!of_node_is_type(dp, "display") &&
287                     !of_node_is_type(dp, "serial")) {
288                         prom_printf("Console device_type is neither display "
289                                     "nor serial.\n");
290                         prom_halt();
291                 }
292
293                 of_console_device = dp;
294
295                 if (prom_vers == PROM_V2) {
296                         sprintf(of_console_path, "%pOF", dp);
297                         switch (*romvec->pv_stdout) {
298                         case PROMDEV_TTYA:
299                                 strcat(of_console_path, ":a");
300                                 break;
301                         case PROMDEV_TTYB:
302                                 strcat(of_console_path, ":b");
303                                 break;
304                         }
305                 } else {
306                         const char *path;
307
308                         dp = of_find_node_by_path("/");
309                         path = of_get_property(dp, "stdout-path", NULL);
310                         if (!path) {
311                                 prom_printf("No stdout-path in root node.\n");
312                                 prom_halt();
313                         }
314                         strcpy(of_console_path, path);
315                 }
316                 break;
317         }
318
319         of_console_options = strrchr(of_console_path, ':');
320         if (of_console_options) {
321                 of_console_options++;
322                 if (*of_console_options == '\0')
323                         of_console_options = NULL;
324         }
325
326         printk(msg, of_console_path);
327 }
328
329 void __init of_fill_in_cpu_data(void)
330 {
331 }
332
333 void __init irq_trans_init(struct device_node *dp)
334 {
335 }