sparc: make proces_ver_nack a bit more readable
[linux-2.6] / 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/bootmem.h>
23 #include <linux/module.h>
24
25 #include <asm/prom.h>
26 #include <asm/oplib.h>
27
28 #include "prom.h"
29
30 void * __init prom_early_alloc(unsigned long size)
31 {
32         void *ret;
33
34         ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
35         if (ret != NULL)
36                 memset(ret, 0, size);
37
38         prom_early_allocated += size;
39
40         return ret;
41 }
42
43 /* The following routines deal with the black magic of fully naming a
44  * node.
45  *
46  * Certain well known named nodes are just the simple name string.
47  *
48  * Actual devices have an address specifier appended to the base name
49  * string, like this "foo@addr".  The "addr" can be in any number of
50  * formats, and the platform plus the type of the node determine the
51  * format and how it is constructed.
52  *
53  * For children of the ROOT node, the naming convention is fixed and
54  * determined by whether this is a sun4u or sun4v system.
55  *
56  * For children of other nodes, it is bus type specific.  So
57  * we walk up the tree until we discover a "device_type" property
58  * we recognize and we go from there.
59  */
60 static void __init sparc32_path_component(struct device_node *dp, char *tmp_buf)
61 {
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                 dp->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         struct linux_prom_registers *regs;
79         struct property *prop;
80
81         prop = of_find_property(dp, "reg", NULL);
82         if (!prop)
83                 return;
84
85         regs = prop->value;
86         sprintf(tmp_buf, "%s@%x,%x",
87                 dp->name,
88                 regs->which_io,
89                 regs->phys_addr);
90 }
91
92 /* "name@devnum[,func]" */
93 static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
94 {
95         struct linux_prom_pci_registers *regs;
96         struct property *prop;
97         unsigned int devfn;
98
99         prop = of_find_property(dp, "reg", NULL);
100         if (!prop)
101                 return;
102
103         regs = prop->value;
104         devfn = (regs->phys_hi >> 8) & 0xff;
105         if (devfn & 0x07) {
106                 sprintf(tmp_buf, "%s@%x,%x",
107                         dp->name,
108                         devfn >> 3,
109                         devfn & 0x07);
110         } else {
111                 sprintf(tmp_buf, "%s@%x",
112                         dp->name,
113                         devfn >> 3);
114         }
115 }
116
117 /* "name@addrhi,addrlo" */
118 static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
119 {
120         struct linux_prom_registers *regs;
121         struct property *prop;
122
123         prop = of_find_property(dp, "reg", NULL);
124         if (!prop)
125                 return;
126
127         regs = prop->value;
128
129         sprintf(tmp_buf, "%s@%x,%x",
130                 dp->name,
131                 regs->which_io, regs->phys_addr);
132 }
133
134 static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
135 {
136         struct device_node *parent = dp->parent;
137
138         if (parent != NULL) {
139                 if (!strcmp(parent->type, "pci") ||
140                     !strcmp(parent->type, "pciex"))
141                         return pci_path_component(dp, tmp_buf);
142                 if (!strcmp(parent->type, "sbus"))
143                         return sbus_path_component(dp, tmp_buf);
144                 if (!strcmp(parent->type, "ebus"))
145                         return ebus_path_component(dp, tmp_buf);
146
147                 /* "isa" is handled with platform naming */
148         }
149
150         /* Use platform naming convention.  */
151         return sparc32_path_component(dp, tmp_buf);
152 }
153
154 char * __init build_path_component(struct device_node *dp)
155 {
156         char tmp_buf[64], *n;
157
158         tmp_buf[0] = '\0';
159         __build_path_component(dp, tmp_buf);
160         if (tmp_buf[0] == '\0')
161                 strcpy(tmp_buf, dp->name);
162
163         n = prom_early_alloc(strlen(tmp_buf) + 1);
164         strcpy(n, tmp_buf);
165
166         return n;
167 }
168
169 extern void restore_current(void);
170
171 void __init of_console_init(void)
172 {
173         char *msg = "OF stdout device is: %s\n";
174         struct device_node *dp;
175         unsigned long flags;
176         const char *type;
177         phandle node;
178         int skip, tmp, fd;
179
180         of_console_path = prom_early_alloc(256);
181
182         switch (prom_vers) {
183         case PROM_V0:
184                 skip = 0;
185                 switch (*romvec->pv_stdout) {
186                 case PROMDEV_SCREEN:
187                         type = "display";
188                         break;
189
190                 case PROMDEV_TTYB:
191                         skip = 1;
192                         /* FALLTHRU */
193
194                 case PROMDEV_TTYA:
195                         type = "serial";
196                         break;
197
198                 default:
199                         prom_printf("Invalid PROM_V0 stdout value %u\n",
200                                     *romvec->pv_stdout);
201                         prom_halt();
202                 }
203
204                 tmp = skip;
205                 for_each_node_by_type(dp, type) {
206                         if (!tmp--)
207                                 break;
208                 }
209                 if (!dp) {
210                         prom_printf("Cannot find PROM_V0 console node.\n");
211                         prom_halt();
212                 }
213                 of_console_device = dp;
214
215                 strcpy(of_console_path, dp->full_name);
216                 if (!strcmp(type, "serial")) {
217                         strcat(of_console_path,
218                                (skip ? ":b" : ":a"));
219                 }
220                 break;
221
222         default:
223         case PROM_V2:
224         case PROM_V3:
225                 fd = *romvec->pv_v2bootargs.fd_stdout;
226
227                 spin_lock_irqsave(&prom_lock, flags);
228                 node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
229                 restore_current();
230                 spin_unlock_irqrestore(&prom_lock, flags);
231
232                 if (!node) {
233                         prom_printf("Cannot resolve stdout node from "
234                                     "instance %08x.\n", fd);
235                         prom_halt();
236                 }
237                 dp = of_find_node_by_phandle(node);
238                 type = of_get_property(dp, "device_type", NULL);
239
240                 if (!type) {
241                         prom_printf("Console stdout lacks "
242                                     "device_type property.\n");
243                         prom_halt();
244                 }
245
246                 if (strcmp(type, "display") && strcmp(type, "serial")) {
247                         prom_printf("Console device_type is neither display "
248                                     "nor serial.\n");
249                         prom_halt();
250                 }
251
252                 of_console_device = dp;
253
254                 if (prom_vers == PROM_V2) {
255                         strcpy(of_console_path, dp->full_name);
256                         switch (*romvec->pv_stdout) {
257                         case PROMDEV_TTYA:
258                                 strcat(of_console_path, ":a");
259                                 break;
260                         case PROMDEV_TTYB:
261                                 strcat(of_console_path, ":b");
262                                 break;
263                         }
264                 } else {
265                         const char *path;
266
267                         dp = of_find_node_by_path("/");
268                         path = of_get_property(dp, "stdout-path", NULL);
269                         if (!path) {
270                                 prom_printf("No stdout-path in root node.\n");
271                                 prom_halt();
272                         }
273                         strcpy(of_console_path, path);
274                 }
275                 break;
276         }
277
278         of_console_options = strrchr(of_console_path, ':');
279         if (of_console_options) {
280                 of_console_options++;
281                 if (*of_console_options == '\0')
282                         of_console_options = NULL;
283         }
284
285         prom_printf(msg, of_console_path);
286         printk(msg, of_console_path);
287 }
288
289 void __init of_fill_in_cpu_data(void)
290 {
291 }
292
293 void __init irq_trans_init(struct device_node *dp)
294 {
295 }