Manual merge with Linus.
[linux-2.6] / arch / sparc64 / prom / misc.c
1 /* $Id: misc.c,v 1.20 2001/09/21 03:17:07 kanoj Exp $
2  * misc.c:  Miscellaneous prom functions that don't belong
3  *          anywhere else.
4  *
5  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
6  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7  */
8
9 #include <linux/config.h>
10 #include <linux/types.h>
11 #include <linux/kernel.h>
12 #include <linux/sched.h>
13 #include <linux/interrupt.h>
14 #include <linux/delay.h>
15 #include <asm/openprom.h>
16 #include <asm/oplib.h>
17 #include <asm/system.h>
18
19 /* Reset and reboot the machine with the command 'bcommand'. */
20 void prom_reboot(const char *bcommand)
21 {
22         p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) |
23                   P1275_INOUT(1, 0), bcommand);
24 }
25
26 /* Forth evaluate the expression contained in 'fstring'. */
27 void prom_feval(const char *fstring)
28 {
29         if (!fstring || fstring[0] == 0)
30                 return;
31         p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) |
32                   P1275_INOUT(1, 1), fstring);
33 }
34
35 /* We want to do this more nicely some day. */
36 extern void (*prom_palette)(int);
37
38 #ifdef CONFIG_SMP
39 extern void smp_capture(void);
40 extern void smp_release(void);
41 #endif
42
43 /* Drop into the prom, with the chance to continue with the 'go'
44  * prom command.
45  */
46 void prom_cmdline(void)
47 {
48         unsigned long flags;
49
50         local_irq_save(flags);
51
52         if (!serial_console && prom_palette)
53                 prom_palette(1);
54
55 #ifdef CONFIG_SMP
56         smp_capture();
57 #endif
58
59         p1275_cmd("enter", P1275_INOUT(0, 0));
60
61 #ifdef CONFIG_SMP
62         smp_release();
63 #endif
64
65         if (!serial_console && prom_palette)
66                 prom_palette(0);
67
68         local_irq_restore(flags);
69 }
70
71 /* Drop into the prom, but completely terminate the program.
72  * No chance of continuing.
73  */
74 void prom_halt(void)
75 {
76 again:
77         p1275_cmd("exit", P1275_INOUT(0, 0));
78         goto again; /* PROM is out to get me -DaveM */
79 }
80
81 void prom_halt_power_off(void)
82 {
83         p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0));
84
85         /* if nothing else helps, we just halt */
86         prom_halt();
87 }
88
89 /* Set prom sync handler to call function 'funcp'. */
90 void prom_setcallback(callback_func_t funcp)
91 {
92         if (!funcp)
93                 return;
94         p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) |
95                   P1275_INOUT(1, 1), funcp);
96 }
97
98 /* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
99  * format type.  'num_bytes' is the number of bytes that your idbuf
100  * has space for.  Returns 0xff on error.
101  */
102 unsigned char prom_get_idprom(char *idbuf, int num_bytes)
103 {
104         int len;
105
106         len = prom_getproplen(prom_root_node, "idprom");
107         if ((len >num_bytes) || (len == -1))
108                 return 0xff;
109         if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
110                 return idbuf[0];
111
112         return 0xff;
113 }
114
115 /* Install Linux trap table so PROM uses that instead of its own. */
116 void prom_set_trap_table(unsigned long tba)
117 {
118         p1275_cmd("SUNW,set-trap-table",
119                   (P1275_ARG(0, P1275_ARG_IN_64B) |
120                    P1275_INOUT(1, 0)), tba);
121 }
122
123 void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa)
124 {
125         p1275_cmd("SUNW,set-trap-table",
126                   (P1275_ARG(0, P1275_ARG_IN_64B) |
127                    P1275_ARG(1, P1275_ARG_IN_64B) |
128                    P1275_INOUT(2, 0)), tba, mmfsa);
129 }
130
131 int prom_get_mmu_ihandle(void)
132 {
133         int node, ret;
134
135         if (prom_mmu_ihandle_cache != 0)
136                 return prom_mmu_ihandle_cache;
137
138         node = prom_finddevice(prom_chosen_path);
139         ret = prom_getint(node, prom_mmu_name);
140         if (ret == -1 || ret == 0)
141                 prom_mmu_ihandle_cache = -1;
142         else
143                 prom_mmu_ihandle_cache = ret;
144
145         return ret;
146 }
147
148 static int prom_get_memory_ihandle(void)
149 {
150         static int memory_ihandle_cache;
151         int node, ret;
152
153         if (memory_ihandle_cache != 0)
154                 return memory_ihandle_cache;
155
156         node = prom_finddevice("/chosen");
157         ret = prom_getint(node, "memory");
158         if (ret == -1 || ret == 0)
159                 memory_ihandle_cache = -1;
160         else
161                 memory_ihandle_cache = ret;
162
163         return ret;
164 }
165
166 /* Load explicit I/D TLB entries. */
167 long prom_itlb_load(unsigned long index,
168                     unsigned long tte_data,
169                     unsigned long vaddr)
170 {
171         return p1275_cmd(prom_callmethod_name,
172                          (P1275_ARG(0, P1275_ARG_IN_STRING) |
173                           P1275_ARG(2, P1275_ARG_IN_64B) |
174                           P1275_ARG(3, P1275_ARG_IN_64B) |
175                           P1275_INOUT(5, 1)),
176                          "SUNW,itlb-load",
177                          prom_get_mmu_ihandle(),
178                          /* And then our actual args are pushed backwards. */
179                          vaddr,
180                          tte_data,
181                          index);
182 }
183
184 long prom_dtlb_load(unsigned long index,
185                     unsigned long tte_data,
186                     unsigned long vaddr)
187 {
188         return p1275_cmd(prom_callmethod_name,
189                          (P1275_ARG(0, P1275_ARG_IN_STRING) |
190                           P1275_ARG(2, P1275_ARG_IN_64B) |
191                           P1275_ARG(3, P1275_ARG_IN_64B) |
192                           P1275_INOUT(5, 1)),
193                          "SUNW,dtlb-load",
194                          prom_get_mmu_ihandle(),
195                          /* And then our actual args are pushed backwards. */
196                          vaddr,
197                          tte_data,
198                          index);
199 }
200
201 int prom_map(int mode, unsigned long size,
202              unsigned long vaddr, unsigned long paddr)
203 {
204         int ret = p1275_cmd(prom_callmethod_name,
205                             (P1275_ARG(0, P1275_ARG_IN_STRING) |
206                              P1275_ARG(3, P1275_ARG_IN_64B) |
207                              P1275_ARG(4, P1275_ARG_IN_64B) |
208                              P1275_ARG(6, P1275_ARG_IN_64B) |
209                              P1275_INOUT(7, 1)),
210                             prom_map_name,
211                             prom_get_mmu_ihandle(),
212                             mode,
213                             size,
214                             vaddr,
215                             0,
216                             paddr);
217
218         if (ret == 0)
219                 ret = -1;
220         return ret;
221 }
222
223 void prom_unmap(unsigned long size, unsigned long vaddr)
224 {
225         p1275_cmd(prom_callmethod_name,
226                   (P1275_ARG(0, P1275_ARG_IN_STRING) |
227                    P1275_ARG(2, P1275_ARG_IN_64B) |
228                    P1275_ARG(3, P1275_ARG_IN_64B) |
229                    P1275_INOUT(4, 0)),
230                   prom_unmap_name,
231                   prom_get_mmu_ihandle(),
232                   size,
233                   vaddr);
234 }
235
236 /* Set aside physical memory which is not touched or modified
237  * across soft resets.
238  */
239 unsigned long prom_retain(const char *name,
240                           unsigned long pa_low, unsigned long pa_high,
241                           long size, long align)
242 {
243         /* XXX I don't think we return multiple values correctly.
244          * XXX OBP supposedly returns pa_low/pa_high here, how does
245          * XXX it work?
246          */
247
248         /* If align is zero, the pa_low/pa_high args are passed,
249          * else they are not.
250          */
251         if (align == 0)
252                 return p1275_cmd("SUNW,retain",
253                                  (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)),
254                                  name, pa_low, pa_high, size, align);
255         else
256                 return p1275_cmd("SUNW,retain",
257                                  (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)),
258                                  name, size, align);
259 }
260
261 /* Get "Unumber" string for the SIMM at the given
262  * memory address.  Usually this will be of the form
263  * "Uxxxx" where xxxx is a decimal number which is
264  * etched into the motherboard next to the SIMM slot
265  * in question.
266  */
267 int prom_getunumber(int syndrome_code,
268                     unsigned long phys_addr,
269                     char *buf, int buflen)
270 {
271         return p1275_cmd(prom_callmethod_name,
272                          (P1275_ARG(0, P1275_ARG_IN_STRING)     |
273                           P1275_ARG(3, P1275_ARG_OUT_BUF)       |
274                           P1275_ARG(6, P1275_ARG_IN_64B)        |
275                           P1275_INOUT(8, 2)),
276                          "SUNW,get-unumber", prom_get_memory_ihandle(),
277                          buflen, buf, P1275_SIZE(buflen),
278                          0, phys_addr, syndrome_code);
279 }
280
281 /* Power management extensions. */
282 void prom_sleepself(void)
283 {
284         p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0));
285 }
286
287 int prom_sleepsystem(void)
288 {
289         return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1));
290 }
291
292 int prom_wakeupsystem(void)
293 {
294         return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
295 }
296
297 #ifdef CONFIG_SMP
298 void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg)
299 {
300         p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg);
301 }
302
303 void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg)
304 {
305         p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0),
306                   cpuid, pc, arg);
307 }
308
309 void prom_stopcpu_cpuid(int cpuid)
310 {
311         p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0),
312                   cpuid);
313 }
314
315 void prom_stopself(void)
316 {
317         p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0));
318 }
319
320 void prom_idleself(void)
321 {
322         p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0));
323 }
324
325 void prom_resumecpu(int cpunode)
326 {
327         p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode);
328 }
329 #endif