Commit | Line | Data |
---|---|---|
1da177e4 LT |
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'. */ | |
bff06d55 | 20 | void prom_reboot(const char *bcommand) |
1da177e4 LT |
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'. */ | |
bff06d55 | 27 | void prom_feval(const char *fstring) |
1da177e4 LT |
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 | ||
1da177e4 LT |
71 | /* Drop into the prom, but completely terminate the program. |
72 | * No chance of continuing. | |
73 | */ | |
74 | void prom_halt(void) | |
75 | { | |
1da177e4 LT |
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 | { | |
1da177e4 LT |
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 | /* Get the major prom version number. */ | |
116 | int prom_version(void) | |
117 | { | |
118 | return PROM_P1275; | |
119 | } | |
120 | ||
121 | /* Get the prom plugin-revision. */ | |
122 | int prom_getrev(void) | |
123 | { | |
124 | return prom_rev; | |
125 | } | |
126 | ||
127 | /* Get the prom firmware print revision. */ | |
128 | int prom_getprev(void) | |
129 | { | |
130 | return prom_prev; | |
131 | } | |
132 | ||
133 | /* Install Linux trap table so PROM uses that instead of its own. */ | |
134 | void prom_set_trap_table(unsigned long tba) | |
135 | { | |
136 | p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba); | |
137 | } | |
138 | ||
1da177e4 LT |
139 | int prom_get_mmu_ihandle(void) |
140 | { | |
141 | int node, ret; | |
142 | ||
bff06d55 DM |
143 | if (prom_mmu_ihandle_cache != 0) |
144 | return prom_mmu_ihandle_cache; | |
1da177e4 | 145 | |
bff06d55 DM |
146 | node = prom_finddevice(prom_chosen_path); |
147 | ret = prom_getint(node, prom_mmu_name); | |
1da177e4 | 148 | if (ret == -1 || ret == 0) |
bff06d55 | 149 | prom_mmu_ihandle_cache = -1; |
1da177e4 | 150 | else |
bff06d55 | 151 | prom_mmu_ihandle_cache = ret; |
1da177e4 LT |
152 | |
153 | return ret; | |
154 | } | |
155 | ||
156 | static int prom_get_memory_ihandle(void) | |
157 | { | |
158 | static int memory_ihandle_cache; | |
159 | int node, ret; | |
160 | ||
161 | if (memory_ihandle_cache != 0) | |
162 | return memory_ihandle_cache; | |
163 | ||
164 | node = prom_finddevice("/chosen"); | |
165 | ret = prom_getint(node, "memory"); | |
166 | if (ret == -1 || ret == 0) | |
167 | memory_ihandle_cache = -1; | |
168 | else | |
169 | memory_ihandle_cache = ret; | |
170 | ||
171 | return ret; | |
172 | } | |
173 | ||
174 | /* Load explicit I/D TLB entries. */ | |
175 | long prom_itlb_load(unsigned long index, | |
176 | unsigned long tte_data, | |
177 | unsigned long vaddr) | |
178 | { | |
bff06d55 | 179 | return p1275_cmd(prom_callmethod_name, |
1da177e4 LT |
180 | (P1275_ARG(0, P1275_ARG_IN_STRING) | |
181 | P1275_ARG(2, P1275_ARG_IN_64B) | | |
182 | P1275_ARG(3, P1275_ARG_IN_64B) | | |
183 | P1275_INOUT(5, 1)), | |
184 | "SUNW,itlb-load", | |
185 | prom_get_mmu_ihandle(), | |
186 | /* And then our actual args are pushed backwards. */ | |
187 | vaddr, | |
188 | tte_data, | |
189 | index); | |
190 | } | |
191 | ||
192 | long prom_dtlb_load(unsigned long index, | |
193 | unsigned long tte_data, | |
194 | unsigned long vaddr) | |
195 | { | |
bff06d55 | 196 | return p1275_cmd(prom_callmethod_name, |
1da177e4 LT |
197 | (P1275_ARG(0, P1275_ARG_IN_STRING) | |
198 | P1275_ARG(2, P1275_ARG_IN_64B) | | |
199 | P1275_ARG(3, P1275_ARG_IN_64B) | | |
200 | P1275_INOUT(5, 1)), | |
201 | "SUNW,dtlb-load", | |
202 | prom_get_mmu_ihandle(), | |
203 | /* And then our actual args are pushed backwards. */ | |
204 | vaddr, | |
205 | tte_data, | |
206 | index); | |
207 | } | |
208 | ||
209 | int prom_map(int mode, unsigned long size, | |
210 | unsigned long vaddr, unsigned long paddr) | |
211 | { | |
bff06d55 | 212 | int ret = p1275_cmd(prom_callmethod_name, |
1da177e4 LT |
213 | (P1275_ARG(0, P1275_ARG_IN_STRING) | |
214 | P1275_ARG(3, P1275_ARG_IN_64B) | | |
215 | P1275_ARG(4, P1275_ARG_IN_64B) | | |
216 | P1275_ARG(6, P1275_ARG_IN_64B) | | |
217 | P1275_INOUT(7, 1)), | |
bff06d55 | 218 | prom_map_name, |
1da177e4 LT |
219 | prom_get_mmu_ihandle(), |
220 | mode, | |
221 | size, | |
222 | vaddr, | |
223 | 0, | |
224 | paddr); | |
225 | ||
226 | if (ret == 0) | |
227 | ret = -1; | |
228 | return ret; | |
229 | } | |
230 | ||
231 | void prom_unmap(unsigned long size, unsigned long vaddr) | |
232 | { | |
bff06d55 | 233 | p1275_cmd(prom_callmethod_name, |
1da177e4 LT |
234 | (P1275_ARG(0, P1275_ARG_IN_STRING) | |
235 | P1275_ARG(2, P1275_ARG_IN_64B) | | |
236 | P1275_ARG(3, P1275_ARG_IN_64B) | | |
237 | P1275_INOUT(4, 0)), | |
bff06d55 | 238 | prom_unmap_name, |
1da177e4 LT |
239 | prom_get_mmu_ihandle(), |
240 | size, | |
241 | vaddr); | |
242 | } | |
243 | ||
244 | /* Set aside physical memory which is not touched or modified | |
245 | * across soft resets. | |
246 | */ | |
bff06d55 | 247 | unsigned long prom_retain(const char *name, |
1da177e4 LT |
248 | unsigned long pa_low, unsigned long pa_high, |
249 | long size, long align) | |
250 | { | |
251 | /* XXX I don't think we return multiple values correctly. | |
252 | * XXX OBP supposedly returns pa_low/pa_high here, how does | |
253 | * XXX it work? | |
254 | */ | |
255 | ||
256 | /* If align is zero, the pa_low/pa_high args are passed, | |
257 | * else they are not. | |
258 | */ | |
259 | if (align == 0) | |
260 | return p1275_cmd("SUNW,retain", | |
261 | (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)), | |
262 | name, pa_low, pa_high, size, align); | |
263 | else | |
264 | return p1275_cmd("SUNW,retain", | |
265 | (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)), | |
266 | name, size, align); | |
267 | } | |
268 | ||
269 | /* Get "Unumber" string for the SIMM at the given | |
270 | * memory address. Usually this will be of the form | |
271 | * "Uxxxx" where xxxx is a decimal number which is | |
272 | * etched into the motherboard next to the SIMM slot | |
273 | * in question. | |
274 | */ | |
275 | int prom_getunumber(int syndrome_code, | |
276 | unsigned long phys_addr, | |
277 | char *buf, int buflen) | |
278 | { | |
bff06d55 | 279 | return p1275_cmd(prom_callmethod_name, |
1da177e4 LT |
280 | (P1275_ARG(0, P1275_ARG_IN_STRING) | |
281 | P1275_ARG(3, P1275_ARG_OUT_BUF) | | |
282 | P1275_ARG(6, P1275_ARG_IN_64B) | | |
283 | P1275_INOUT(8, 2)), | |
284 | "SUNW,get-unumber", prom_get_memory_ihandle(), | |
285 | buflen, buf, P1275_SIZE(buflen), | |
286 | 0, phys_addr, syndrome_code); | |
287 | } | |
288 | ||
289 | /* Power management extensions. */ | |
290 | void prom_sleepself(void) | |
291 | { | |
292 | p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0)); | |
293 | } | |
294 | ||
295 | int prom_sleepsystem(void) | |
296 | { | |
297 | return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1)); | |
298 | } | |
299 | ||
300 | int prom_wakeupsystem(void) | |
301 | { | |
302 | return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1)); | |
303 | } | |
304 | ||
305 | #ifdef CONFIG_SMP | |
306 | void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0) | |
307 | { | |
308 | p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0); | |
309 | } | |
310 | ||
311 | void prom_stopself(void) | |
312 | { | |
313 | p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0)); | |
314 | } | |
315 | ||
316 | void prom_idleself(void) | |
317 | { | |
318 | p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0)); | |
319 | } | |
320 | ||
321 | void prom_resumecpu(int cpunode) | |
322 | { | |
323 | p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode); | |
324 | } | |
325 | #endif |