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