Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
[linux-2.6] / arch / sparc / prom / sun4prom.c
1 /*
2  * Copyright (C) 1996 The Australian National University.
3  * Copyright (C) 1996 Fujitsu Laboratories Limited
4  * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
5  * Copyright (C) 1997 Sun Weenie (ko@ko.reno.nv.us)
6  * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7  * 
8  * This software may be distributed under the terms of the Gnu
9  * Public License version 2 or later
10  *
11  * fake a really simple Sun prom for the SUN4
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/string.h>
16 #include <asm/oplib.h>
17 #include <asm/idprom.h> 
18 #include <asm/machines.h> 
19 #include <asm/sun4prom.h>
20 #include <asm/asi.h>
21 #include <asm/contregs.h>
22 #include <linux/init.h>
23
24 static struct linux_romvec sun4romvec;
25 static struct idprom sun4_idprom;
26
27 struct property {
28         char *name;
29         char *value;
30         int length;
31 };
32
33 struct node {
34         int level;
35         struct property *properties;
36 };
37
38 struct property null_properties = { NULL, NULL, -1 };
39
40 struct property root_properties[] = {
41         {"device_type", "cpu", 4},
42         {"idprom", (char *)&sun4_idprom, sizeof(struct idprom)},
43         {NULL, NULL, -1}
44 };
45
46 struct node nodes[] = {
47         { 0, &null_properties }, 
48         { 0, root_properties },
49         { -1,&null_properties }
50 };
51
52
53 static int no_nextnode(int node)
54 {
55         if (nodes[node].level == nodes[node+1].level)
56                 return node+1;
57         return -1;
58 }
59
60 static int no_child(int node)
61 {
62         if (nodes[node].level == nodes[node+1].level-1)
63                 return node+1;
64         return -1;
65 }
66
67 static struct property *find_property(int node,char *name)
68 {
69         struct property *prop = &nodes[node].properties[0];
70         while (prop && prop->name) {
71                 if (strcmp(prop->name,name) == 0) return prop;
72                 prop++;
73         }
74         return NULL;
75 }
76
77 static int no_proplen(int node,char *name)
78 {
79         struct property *prop = find_property(node,name);
80         if (prop) return prop->length;
81         return -1;
82 }
83
84 static int no_getprop(int node,char *name,char *value)
85 {
86         struct property *prop = find_property(node,name);
87         if (prop) {
88                 memcpy(value,prop->value,prop->length);
89                 return 1;
90         }
91         return -1;
92 }
93
94 static int no_setprop(int node,char *name,char *value,int len)
95 {
96         return -1;
97 }
98
99 static char *no_nextprop(int node,char *name)
100 {
101         struct property *prop = find_property(node,name);
102         if (prop) return prop[1].name;
103         return NULL;
104 }
105
106 static struct linux_nodeops sun4_nodeops = {
107         no_nextnode,
108         no_child,
109         no_proplen,
110         no_getprop,
111         no_setprop,
112         no_nextprop
113 };
114         
115 static int synch_hook;
116
117 struct linux_romvec * __init sun4_prom_init(void)
118 {
119         int i;
120         unsigned char x;
121         char *p;
122                                 
123         p = (char *)&sun4_idprom;
124         for (i = 0; i < sizeof(sun4_idprom); i++) {
125                 __asm__ __volatile__ ("lduba [%1] %2, %0" : "=r" (x) :
126                                       "r" (AC_IDPROM + i), "i" (ASI_CONTROL));
127                 *p++ = x;
128         }
129
130         memset(&sun4romvec,0,sizeof(sun4romvec));
131
132         sun4_romvec = (linux_sun4_romvec *) SUN4_PROM_VECTOR;
133
134         sun4romvec.pv_romvers = 40;
135         sun4romvec.pv_nodeops = &sun4_nodeops;
136         sun4romvec.pv_reboot = sun4_romvec->reboot;
137         sun4romvec.pv_abort = sun4_romvec->abortentry;
138         sun4romvec.pv_halt = sun4_romvec->exittomon;
139         sun4romvec.pv_synchook = (void (**)(void))&synch_hook;
140         sun4romvec.pv_setctxt = sun4_romvec->setcxsegmap;
141         sun4romvec.pv_v0bootargs = sun4_romvec->bootParam;
142         sun4romvec.pv_nbgetchar = sun4_romvec->mayget;
143         sun4romvec.pv_nbputchar = sun4_romvec->mayput;
144         sun4romvec.pv_stdin = sun4_romvec->insource;
145         sun4romvec.pv_stdout = sun4_romvec->outsink;
146         
147         /*
148          * We turn on the LEDs to let folks without monitors or
149          * terminals know we booted.   Nothing too fancy now.  They
150          * are all on, except for LED 5, which blinks.   When we
151          * have more time, we can teach the penguin to say "By your
152          * command" or "Activating turbo boost, Michael". :-)
153          */
154         sun4_romvec->setLEDs(NULL);
155         
156         printk("PROMLIB: Old Sun4 boot PROM monitor %s, romvec version %d\n",
157                 sun4_romvec->monid,
158                 sun4_romvec->romvecversion);
159
160         return &sun4romvec;
161 }