• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/sparc/prom/
1/*
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/types.h>
10#include <linux/kernel.h>
11#include <linux/sched.h>
12#include <linux/interrupt.h>
13#include <linux/delay.h>
14#include <linux/module.h>
15
16#include <asm/openprom.h>
17#include <asm/oplib.h>
18#include <asm/system.h>
19#include <asm/ldc.h>
20
21static int prom_service_exists(const char *service_name)
22{
23	unsigned long args[5];
24
25	args[0] = (unsigned long) "test";
26	args[1] = 1;
27	args[2] = 1;
28	args[3] = (unsigned long) service_name;
29	args[4] = (unsigned long) -1;
30
31	p1275_cmd_direct(args);
32
33	if (args[4])
34		return 0;
35	return 1;
36}
37
38void prom_sun4v_guest_soft_state(void)
39{
40	const char *svc = "SUNW,soft-state-supported";
41	unsigned long args[3];
42
43	if (!prom_service_exists(svc))
44		return;
45	args[0] = (unsigned long) svc;
46	args[1] = 0;
47	args[2] = 0;
48	p1275_cmd_direct(args);
49}
50
51/* Reset and reboot the machine with the command 'bcommand'. */
52void prom_reboot(const char *bcommand)
53{
54	unsigned long args[4];
55
56#ifdef CONFIG_SUN_LDOMS
57	if (ldom_domaining_enabled)
58		ldom_reboot(bcommand);
59#endif
60	args[0] = (unsigned long) "boot";
61	args[1] = 1;
62	args[2] = 0;
63	args[3] = (unsigned long) bcommand;
64
65	p1275_cmd_direct(args);
66}
67
68/* Forth evaluate the expression contained in 'fstring'. */
69void prom_feval(const char *fstring)
70{
71	unsigned long args[5];
72
73	if (!fstring || fstring[0] == 0)
74		return;
75	args[0] = (unsigned long) "interpret";
76	args[1] = 1;
77	args[2] = 1;
78	args[3] = (unsigned long) fstring;
79	args[4] = (unsigned long) -1;
80
81	p1275_cmd_direct(args);
82}
83EXPORT_SYMBOL(prom_feval);
84
85#ifdef CONFIG_SMP
86extern void smp_capture(void);
87extern void smp_release(void);
88#endif
89
90/* Drop into the prom, with the chance to continue with the 'go'
91 * prom command.
92 */
93void prom_cmdline(void)
94{
95	unsigned long args[3];
96	unsigned long flags;
97
98	local_irq_save(flags);
99
100#ifdef CONFIG_SMP
101	smp_capture();
102#endif
103
104	args[0] = (unsigned long) "enter";
105	args[1] = 0;
106	args[2] = 0;
107
108	p1275_cmd_direct(args);
109
110#ifdef CONFIG_SMP
111	smp_release();
112#endif
113
114	local_irq_restore(flags);
115}
116
117/* Drop into the prom, but completely terminate the program.
118 * No chance of continuing.
119 */
120void notrace prom_halt(void)
121{
122	unsigned long args[3];
123
124#ifdef CONFIG_SUN_LDOMS
125	if (ldom_domaining_enabled)
126		ldom_power_off();
127#endif
128again:
129	args[0] = (unsigned long) "exit";
130	args[1] = 0;
131	args[2] = 0;
132	p1275_cmd_direct(args);
133	goto again; /* PROM is out to get me -DaveM */
134}
135
136void prom_halt_power_off(void)
137{
138	unsigned long args[3];
139
140#ifdef CONFIG_SUN_LDOMS
141	if (ldom_domaining_enabled)
142		ldom_power_off();
143#endif
144	args[0] = (unsigned long) "SUNW,power-off";
145	args[1] = 0;
146	args[2] = 0;
147	p1275_cmd_direct(args);
148
149	/* if nothing else helps, we just halt */
150	prom_halt();
151}
152
153/* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
154 * format type.  'num_bytes' is the number of bytes that your idbuf
155 * has space for.  Returns 0xff on error.
156 */
157unsigned char prom_get_idprom(char *idbuf, int num_bytes)
158{
159	int len;
160
161	len = prom_getproplen(prom_root_node, "idprom");
162	if ((len >num_bytes) || (len == -1))
163		return 0xff;
164	if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
165		return idbuf[0];
166
167	return 0xff;
168}
169
170int prom_get_mmu_ihandle(void)
171{
172	int node, ret;
173
174	if (prom_mmu_ihandle_cache != 0)
175		return prom_mmu_ihandle_cache;
176
177	node = prom_finddevice(prom_chosen_path);
178	ret = prom_getint(node, prom_mmu_name);
179	if (ret == -1 || ret == 0)
180		prom_mmu_ihandle_cache = -1;
181	else
182		prom_mmu_ihandle_cache = ret;
183
184	return ret;
185}
186
187static int prom_get_memory_ihandle(void)
188{
189	static int memory_ihandle_cache;
190	int node, ret;
191
192	if (memory_ihandle_cache != 0)
193		return memory_ihandle_cache;
194
195	node = prom_finddevice("/chosen");
196	ret = prom_getint(node, "memory");
197	if (ret == -1 || ret == 0)
198		memory_ihandle_cache = -1;
199	else
200		memory_ihandle_cache = ret;
201
202	return ret;
203}
204
205/* Load explicit I/D TLB entries. */
206static long tlb_load(const char *type, unsigned long index,
207		     unsigned long tte_data, unsigned long vaddr)
208{
209	unsigned long args[9];
210
211	args[0] = (unsigned long) prom_callmethod_name;
212	args[1] = 5;
213	args[2] = 1;
214	args[3] = (unsigned long) type;
215	args[4] = (unsigned int) prom_get_mmu_ihandle();
216	args[5] = vaddr;
217	args[6] = tte_data;
218	args[7] = index;
219	args[8] = (unsigned long) -1;
220
221	p1275_cmd_direct(args);
222
223	return (long) args[8];
224}
225
226long prom_itlb_load(unsigned long index,
227		    unsigned long tte_data,
228		    unsigned long vaddr)
229{
230	return tlb_load("SUNW,itlb-load", index, tte_data, vaddr);
231}
232
233long prom_dtlb_load(unsigned long index,
234		    unsigned long tte_data,
235		    unsigned long vaddr)
236{
237	return tlb_load("SUNW,dtlb-load", index, tte_data, vaddr);
238}
239
240int prom_map(int mode, unsigned long size,
241	     unsigned long vaddr, unsigned long paddr)
242{
243	unsigned long args[11];
244	int ret;
245
246	args[0] = (unsigned long) prom_callmethod_name;
247	args[1] = 7;
248	args[2] = 1;
249	args[3] = (unsigned long) prom_map_name;
250	args[4] = (unsigned int) prom_get_mmu_ihandle();
251	args[5] = (unsigned int) mode;
252	args[6] = size;
253	args[7] = vaddr;
254	args[8] = 0;
255	args[9] = paddr;
256	args[10] = (unsigned long) -1;
257
258	p1275_cmd_direct(args);
259
260	ret = (int) args[10];
261	if (ret == 0)
262		ret = -1;
263	return ret;
264}
265
266void prom_unmap(unsigned long size, unsigned long vaddr)
267{
268	unsigned long args[7];
269
270	args[0] = (unsigned long) prom_callmethod_name;
271	args[1] = 4;
272	args[2] = 0;
273	args[3] = (unsigned long) prom_unmap_name;
274	args[4] = (unsigned int) prom_get_mmu_ihandle();
275	args[5] = size;
276	args[6] = vaddr;
277
278	p1275_cmd_direct(args);
279}
280
281/* Set aside physical memory which is not touched or modified
282 * across soft resets.
283 */
284int prom_retain(const char *name, unsigned long size,
285		unsigned long align, unsigned long *paddr)
286{
287	unsigned long args[11];
288
289	args[0] = (unsigned long) prom_callmethod_name;
290	args[1] = 5;
291	args[2] = 3;
292	args[3] = (unsigned long) "SUNW,retain";
293	args[4] = (unsigned int) prom_get_memory_ihandle();
294	args[5] = align;
295	args[6] = size;
296	args[7] = (unsigned long) name;
297	args[8] = (unsigned long) -1;
298	args[9] = (unsigned long) -1;
299	args[10] = (unsigned long) -1;
300
301	p1275_cmd_direct(args);
302
303	if (args[8])
304		return (int) args[8];
305
306	/* Next we get "phys_high" then "phys_low".  On 64-bit
307	 * the phys_high cell is don't care since the phys_low
308	 * cell has the full value.
309	 */
310	*paddr = args[10];
311
312	return 0;
313}
314
315int prom_getunumber(int syndrome_code,
316		    unsigned long phys_addr,
317		    char *buf, int buflen)
318{
319	unsigned long args[12];
320
321	args[0] = (unsigned long) prom_callmethod_name;
322	args[1] = 7;
323	args[2] = 2;
324	args[3] = (unsigned long) "SUNW,get-unumber";
325	args[4] = (unsigned int) prom_get_memory_ihandle();
326	args[5] = buflen;
327	args[6] = (unsigned long) buf;
328	args[7] = 0;
329	args[8] = phys_addr;
330	args[9] = (unsigned int) syndrome_code;
331	args[10] = (unsigned long) -1;
332	args[11] = (unsigned long) -1;
333
334	p1275_cmd_direct(args);
335
336	return (int) args[10];
337}
338
339/* Power management extensions. */
340void prom_sleepself(void)
341{
342	unsigned long args[3];
343
344	args[0] = (unsigned long) "SUNW,sleep-self";
345	args[1] = 0;
346	args[2] = 0;
347	p1275_cmd_direct(args);
348}
349
350int prom_sleepsystem(void)
351{
352	unsigned long args[4];
353
354	args[0] = (unsigned long) "SUNW,sleep-system";
355	args[1] = 0;
356	args[2] = 1;
357	args[3] = (unsigned long) -1;
358	p1275_cmd_direct(args);
359
360	return (int) args[3];
361}
362
363int prom_wakeupsystem(void)
364{
365	unsigned long args[4];
366
367	args[0] = (unsigned long) "SUNW,wakeup-system";
368	args[1] = 0;
369	args[2] = 1;
370	args[3] = (unsigned long) -1;
371	p1275_cmd_direct(args);
372
373	return (int) args[3];
374}
375
376#ifdef CONFIG_SMP
377void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg)
378{
379	unsigned long args[6];
380
381	args[0] = (unsigned long) "SUNW,start-cpu";
382	args[1] = 3;
383	args[2] = 0;
384	args[3] = (unsigned int) cpunode;
385	args[4] = pc;
386	args[5] = arg;
387	p1275_cmd_direct(args);
388}
389
390void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg)
391{
392	unsigned long args[6];
393
394	args[0] = (unsigned long) "SUNW,start-cpu-by-cpuid";
395	args[1] = 3;
396	args[2] = 0;
397	args[3] = (unsigned int) cpuid;
398	args[4] = pc;
399	args[5] = arg;
400	p1275_cmd_direct(args);
401}
402
403void prom_stopcpu_cpuid(int cpuid)
404{
405	unsigned long args[4];
406
407	args[0] = (unsigned long) "SUNW,stop-cpu-by-cpuid";
408	args[1] = 1;
409	args[2] = 0;
410	args[3] = (unsigned int) cpuid;
411	p1275_cmd_direct(args);
412}
413
414void prom_stopself(void)
415{
416	unsigned long args[3];
417
418	args[0] = (unsigned long) "SUNW,stop-self";
419	args[1] = 0;
420	args[2] = 0;
421	p1275_cmd_direct(args);
422}
423
424void prom_idleself(void)
425{
426	unsigned long args[3];
427
428	args[0] = (unsigned long) "SUNW,idle-self";
429	args[1] = 0;
430	args[2] = 0;
431	p1275_cmd_direct(args);
432}
433
434void prom_resumecpu(int cpunode)
435{
436	unsigned long args[4];
437
438	args[0] = (unsigned long) "SUNW,resume-cpu";
439	args[1] = 1;
440	args[2] = 0;
441	args[3] = (unsigned int) cpunode;
442	p1275_cmd_direct(args);
443}
444#endif
445