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