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
18 /* Reset and reboot the machine with the command 'bcommand'. */
19 void
prom_reboot(char * bcommand)20 prom_reboot(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(char * fstring)28 prom_feval(char *fstring)
29 {
30 if(!fstring || fstring[0] == 0)
31 return;
32 p1275_cmd ("interpret", P1275_ARG(0,P1275_ARG_IN_STRING)|
33 P1275_INOUT(1,1), fstring);
34 }
35
36 /* We want to do this more nicely some day. */
37 #ifdef CONFIG_SUN_CONSOLE
38 extern void (*prom_palette)(int);
39 extern int serial_console;
40 #endif
41
42 #ifdef CONFIG_SMP
43 extern void smp_capture(void);
44 extern void smp_release(void);
45 #endif
46
47 /* Drop into the prom, with the chance to continue with the 'go'
48 * prom command.
49 */
50 void
prom_cmdline(void)51 prom_cmdline(void)
52 {
53 unsigned long flags;
54
55 __save_and_cli(flags);
56
57 #ifdef CONFIG_SUN_CONSOLE
58 if(!serial_console && prom_palette)
59 prom_palette (1);
60 #endif
61
62 #ifdef CONFIG_SMP
63 smp_capture();
64 #endif
65
66 p1275_cmd ("enter", P1275_INOUT(0,0));
67
68 #ifdef CONFIG_SMP
69 smp_release();
70 spin_unlock_wait(&__br_write_locks[BR_GLOBALIRQ_LOCK].lock);
71 #endif
72
73 #ifdef CONFIG_SUN_CONSOLE
74 if(!serial_console && prom_palette)
75 prom_palette (0);
76 #endif
77
78 __restore_flags(flags);
79 }
80
81 #ifdef CONFIG_SMP
82 extern void smp_promstop_others(void);
83 #endif
84
85 /* Drop into the prom, but completely terminate the program.
86 * No chance of continuing.
87 */
88 void
prom_halt(void)89 prom_halt(void)
90 {
91 #ifdef CONFIG_SMP
92 smp_promstop_others();
93 udelay(8000);
94 #endif
95 again:
96 p1275_cmd ("exit", P1275_INOUT(0,0));
97 goto again; /* PROM is out to get me -DaveM */
98 }
99
100 void
prom_halt_power_off(void)101 prom_halt_power_off(void)
102 {
103 #ifdef CONFIG_SMP
104 smp_promstop_others();
105 udelay(8000);
106 #endif
107 p1275_cmd ("SUNW,power-off", P1275_INOUT(0,0));
108
109 /* if nothing else helps, we just halt */
110 prom_halt ();
111 }
112
113 /* Set prom sync handler to call function 'funcp'. */
114 void
prom_setcallback(callback_func_t funcp)115 prom_setcallback(callback_func_t funcp)
116 {
117 if(!funcp) return;
118 p1275_cmd ("set-callback", P1275_ARG(0,P1275_ARG_IN_FUNCTION)|
119 P1275_INOUT(1,1), funcp);
120 }
121
122 /* Get the idprom and stuff it into buffer 'idbuf'. Returns the
123 * format type. 'num_bytes' is the number of bytes that your idbuf
124 * has space for. Returns 0xff on error.
125 */
126 unsigned char
prom_get_idprom(char * idbuf,int num_bytes)127 prom_get_idprom(char *idbuf, int num_bytes)
128 {
129 int len;
130
131 len = prom_getproplen(prom_root_node, "idprom");
132 if((len>num_bytes) || (len==-1)) return 0xff;
133 if(!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
134 return idbuf[0];
135
136 return 0xff;
137 }
138
139 /* Get the major prom version number. */
140 int
prom_version(void)141 prom_version(void)
142 {
143 return PROM_P1275;
144 }
145
146 /* Get the prom plugin-revision. */
147 int
prom_getrev(void)148 prom_getrev(void)
149 {
150 return prom_rev;
151 }
152
153 /* Get the prom firmware print revision. */
154 int
prom_getprev(void)155 prom_getprev(void)
156 {
157 return prom_prev;
158 }
159
160 /* Install Linux trap table so PROM uses that instead of it's own. */
prom_set_trap_table(unsigned long tba)161 void prom_set_trap_table(unsigned long tba)
162 {
163 p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
164 }
165
166 int mmu_ihandle_cache = 0;
167
prom_get_mmu_ihandle(void)168 int prom_get_mmu_ihandle(void)
169 {
170 int node, ret;
171
172 if (mmu_ihandle_cache != 0)
173 return mmu_ihandle_cache;
174
175 node = prom_finddevice("/chosen");
176 ret = prom_getint(node, "mmu");
177 if(ret == -1 || ret == 0)
178 mmu_ihandle_cache = -1;
179 else
180 mmu_ihandle_cache = ret;
181
182 return ret;
183 }
184
prom_get_memory_ihandle(void)185 static int prom_get_memory_ihandle(void)
186 {
187 static int memory_ihandle_cache;
188 int node, ret;
189
190 if (memory_ihandle_cache != 0)
191 return memory_ihandle_cache;
192
193 node = prom_finddevice("/chosen");
194 ret = prom_getint(node, "memory");
195 if (ret == -1 || ret == 0)
196 memory_ihandle_cache = -1;
197 else
198 memory_ihandle_cache = ret;
199
200 return ret;
201 }
202
203 /* Load explicit I/D TLB entries. */
prom_itlb_load(unsigned long index,unsigned long tte_data,unsigned long vaddr)204 long prom_itlb_load(unsigned long index,
205 unsigned long tte_data,
206 unsigned long vaddr)
207 {
208 return p1275_cmd("call-method",
209 (P1275_ARG(0, P1275_ARG_IN_STRING) |
210 P1275_ARG(2, P1275_ARG_IN_64B) |
211 P1275_ARG(3, P1275_ARG_IN_64B) |
212 P1275_INOUT(5, 1)),
213 "SUNW,itlb-load",
214 prom_get_mmu_ihandle(),
215 /* And then our actual args are pushed backwards. */
216 vaddr,
217 tte_data,
218 index);
219 }
220
prom_dtlb_load(unsigned long index,unsigned long tte_data,unsigned long vaddr)221 long prom_dtlb_load(unsigned long index,
222 unsigned long tte_data,
223 unsigned long vaddr)
224 {
225 return p1275_cmd("call-method",
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(5, 1)),
230 "SUNW,dtlb-load",
231 prom_get_mmu_ihandle(),
232 /* And then our actual args are pushed backwards. */
233 vaddr,
234 tte_data,
235 index);
236 }
237
prom_map(int mode,unsigned long size,unsigned long vaddr,unsigned long paddr)238 int prom_map(int mode, unsigned long size,
239 unsigned long vaddr, unsigned long paddr)
240 {
241 int ret = p1275_cmd("call-method",
242 (P1275_ARG(0, P1275_ARG_IN_STRING) |
243 P1275_ARG(3, P1275_ARG_IN_64B) |
244 P1275_ARG(4, P1275_ARG_IN_64B) |
245 P1275_ARG(6, P1275_ARG_IN_64B) |
246 P1275_INOUT(7, 1)),
247 "map",
248 prom_get_mmu_ihandle(),
249 mode,
250 size,
251 vaddr,
252 0,
253 paddr);
254
255 if (ret == 0)
256 ret = -1;
257 return ret;
258 }
259
prom_unmap(unsigned long size,unsigned long vaddr)260 void prom_unmap(unsigned long size, unsigned long vaddr)
261 {
262 p1275_cmd("call-method",
263 (P1275_ARG(0, P1275_ARG_IN_STRING) |
264 P1275_ARG(2, P1275_ARG_IN_64B) |
265 P1275_ARG(3, P1275_ARG_IN_64B) |
266 P1275_INOUT(4, 0)),
267 "unmap",
268 prom_get_mmu_ihandle(),
269 size,
270 vaddr);
271 }
272
273 /* Set aside physical memory which is not touched or modified
274 * across soft resets.
275 */
prom_retain(char * name,unsigned long pa_low,unsigned long pa_high,long size,long align)276 unsigned long prom_retain(char *name,
277 unsigned long pa_low, unsigned long pa_high,
278 long size, long align)
279 {
280 /* XXX I don't think we return multiple values correctly.
281 * XXX OBP supposedly returns pa_low/pa_high here, how does
282 * XXX it work?
283 */
284
285 /* If align is zero, the pa_low/pa_high args are passed,
286 * else they are not.
287 */
288 if(align == 0)
289 return p1275_cmd("SUNW,retain",
290 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)),
291 name, pa_low, pa_high, size, align);
292 else
293 return p1275_cmd("SUNW,retain",
294 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)),
295 name, size, align);
296 }
297
298 /* Get "Unumber" string for the SIMM at the given
299 * memory address. Usually this will be of the form
300 * "Uxxxx" where xxxx is a decimal number which is
301 * etched into the motherboard next to the SIMM slot
302 * in question.
303 */
prom_getunumber(int syndrome_code,unsigned long phys_addr,char * buf,int buflen)304 int prom_getunumber(int syndrome_code,
305 unsigned long phys_addr,
306 char *buf, int buflen)
307 {
308 return p1275_cmd("call-method",
309 (P1275_ARG(0, P1275_ARG_IN_STRING) |
310 P1275_ARG(3, P1275_ARG_OUT_BUF) |
311 P1275_ARG(6, P1275_ARG_IN_64B) |
312 P1275_INOUT(8, 2)),
313 "SUNW,get-unumber", prom_get_memory_ihandle(),
314 buflen, buf, P1275_SIZE(buflen),
315 0, phys_addr, syndrome_code);
316 }
317
318 /* Power management extensions. */
prom_sleepself(void)319 void prom_sleepself(void)
320 {
321 p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0));
322 }
323
prom_sleepsystem(void)324 int prom_sleepsystem(void)
325 {
326 return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1));
327 }
328
prom_wakeupsystem(void)329 int prom_wakeupsystem(void)
330 {
331 return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
332 }
333
334 #ifdef CONFIG_SMP
prom_startcpu(int cpunode,unsigned long pc,unsigned long o0)335 void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0)
336 {
337 p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0);
338 }
339
prom_stopself(void)340 void prom_stopself(void)
341 {
342 p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0));
343 }
344
prom_idleself(void)345 void prom_idleself(void)
346 {
347 p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0));
348 }
349
prom_resumecpu(int cpunode)350 void prom_resumecpu(int cpunode)
351 {
352 p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode);
353 }
354 #endif
355