diff options
Diffstat (limited to 'arch/sparc64/prom')
-rw-r--r-- | arch/sparc64/prom/Makefile | 10 | ||||
-rw-r--r-- | arch/sparc64/prom/bootstr.c | 40 | ||||
-rw-r--r-- | arch/sparc64/prom/cif.S | 225 | ||||
-rw-r--r-- | arch/sparc64/prom/console.c | 146 | ||||
-rw-r--r-- | arch/sparc64/prom/devops.c | 41 | ||||
-rw-r--r-- | arch/sparc64/prom/init.c | 101 | ||||
-rw-r--r-- | arch/sparc64/prom/map.S | 72 | ||||
-rw-r--r-- | arch/sparc64/prom/memory.c | 152 | ||||
-rw-r--r-- | arch/sparc64/prom/misc.c | 339 | ||||
-rw-r--r-- | arch/sparc64/prom/p1275.c | 161 | ||||
-rw-r--r-- | arch/sparc64/prom/printf.c | 47 | ||||
-rw-r--r-- | arch/sparc64/prom/tree.c | 377 |
12 files changed, 1711 insertions, 0 deletions
diff --git a/arch/sparc64/prom/Makefile b/arch/sparc64/prom/Makefile new file mode 100644 index 000000000000..8f2420d9e9e6 --- /dev/null +++ b/arch/sparc64/prom/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # $Id: Makefile,v 1.7 2000/12/14 22:57:25 davem Exp $ | ||
2 | # Makefile for the Sun Boot PROM interface library under | ||
3 | # Linux. | ||
4 | # | ||
5 | |||
6 | EXTRA_AFLAGS := -ansi | ||
7 | EXTRA_CFLAGS := -Werror | ||
8 | |||
9 | lib-y := bootstr.o devops.o init.o memory.o misc.o \ | ||
10 | tree.o console.o printf.o p1275.o map.o cif.o | ||
diff --git a/arch/sparc64/prom/bootstr.c b/arch/sparc64/prom/bootstr.c new file mode 100644 index 000000000000..a7278614e99d --- /dev/null +++ b/arch/sparc64/prom/bootstr.c | |||
@@ -0,0 +1,40 @@ | |||
1 | /* $Id: bootstr.c,v 1.6 1999/08/31 06:55:01 davem Exp $ | ||
2 | * bootstr.c: Boot string/argument acquisition from the PROM. | ||
3 | * | ||
4 | * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | * Copyright(C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
6 | */ | ||
7 | |||
8 | #include <linux/string.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <asm/oplib.h> | ||
11 | |||
12 | /* WARNING: The boot loader knows that these next three variables come one right | ||
13 | * after another in the .data section. Do not move this stuff into | ||
14 | * the .bss section or it will break things. | ||
15 | */ | ||
16 | |||
17 | #define BARG_LEN 256 | ||
18 | struct { | ||
19 | int bootstr_len; | ||
20 | int bootstr_valid; | ||
21 | char bootstr_buf[BARG_LEN]; | ||
22 | } bootstr_info = { | ||
23 | .bootstr_len = BARG_LEN, | ||
24 | #ifdef CONFIG_CMDLINE | ||
25 | .bootstr_valid = 1, | ||
26 | .bootstr_buf = CONFIG_CMDLINE, | ||
27 | #endif | ||
28 | }; | ||
29 | |||
30 | char * __init | ||
31 | prom_getbootargs(void) | ||
32 | { | ||
33 | /* This check saves us from a panic when bootfd patches args. */ | ||
34 | if (bootstr_info.bootstr_valid) | ||
35 | return bootstr_info.bootstr_buf; | ||
36 | prom_getstring(prom_chosen_node, "bootargs", | ||
37 | bootstr_info.bootstr_buf, BARG_LEN); | ||
38 | bootstr_info.bootstr_valid = 1; | ||
39 | return bootstr_info.bootstr_buf; | ||
40 | } | ||
diff --git a/arch/sparc64/prom/cif.S b/arch/sparc64/prom/cif.S new file mode 100644 index 000000000000..29d0ae74aed8 --- /dev/null +++ b/arch/sparc64/prom/cif.S | |||
@@ -0,0 +1,225 @@ | |||
1 | /* cif.S: PROM entry/exit assembler trampolines. | ||
2 | * | ||
3 | * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
4 | * Copyright (C) 2005 David S. Miller <davem@davemloft.net> | ||
5 | */ | ||
6 | |||
7 | #include <asm/pstate.h> | ||
8 | |||
9 | .text | ||
10 | .globl prom_cif_interface | ||
11 | prom_cif_interface: | ||
12 | sethi %hi(p1275buf), %o0 | ||
13 | or %o0, %lo(p1275buf), %o0 | ||
14 | ldx [%o0 + 0x010], %o1 ! prom_cif_stack | ||
15 | save %o1, -0x190, %sp | ||
16 | ldx [%i0 + 0x008], %l2 ! prom_cif_handler | ||
17 | rdpr %pstate, %l4 | ||
18 | wrpr %g0, 0x15, %pstate ! save alternate globals | ||
19 | stx %g1, [%sp + 2047 + 0x0b0] | ||
20 | stx %g2, [%sp + 2047 + 0x0b8] | ||
21 | stx %g3, [%sp + 2047 + 0x0c0] | ||
22 | stx %g4, [%sp + 2047 + 0x0c8] | ||
23 | stx %g5, [%sp + 2047 + 0x0d0] | ||
24 | stx %g6, [%sp + 2047 + 0x0d8] | ||
25 | stx %g7, [%sp + 2047 + 0x0e0] | ||
26 | wrpr %g0, 0x814, %pstate ! save interrupt globals | ||
27 | stx %g1, [%sp + 2047 + 0x0e8] | ||
28 | stx %g2, [%sp + 2047 + 0x0f0] | ||
29 | stx %g3, [%sp + 2047 + 0x0f8] | ||
30 | stx %g4, [%sp + 2047 + 0x100] | ||
31 | stx %g5, [%sp + 2047 + 0x108] | ||
32 | stx %g6, [%sp + 2047 + 0x110] | ||
33 | stx %g7, [%sp + 2047 + 0x118] | ||
34 | wrpr %g0, 0x14, %pstate ! save normal globals | ||
35 | stx %g1, [%sp + 2047 + 0x120] | ||
36 | stx %g2, [%sp + 2047 + 0x128] | ||
37 | stx %g3, [%sp + 2047 + 0x130] | ||
38 | stx %g4, [%sp + 2047 + 0x138] | ||
39 | stx %g5, [%sp + 2047 + 0x140] | ||
40 | stx %g6, [%sp + 2047 + 0x148] | ||
41 | stx %g7, [%sp + 2047 + 0x150] | ||
42 | wrpr %g0, 0x414, %pstate ! save mmu globals | ||
43 | stx %g1, [%sp + 2047 + 0x158] | ||
44 | stx %g2, [%sp + 2047 + 0x160] | ||
45 | stx %g3, [%sp + 2047 + 0x168] | ||
46 | stx %g4, [%sp + 2047 + 0x170] | ||
47 | stx %g5, [%sp + 2047 + 0x178] | ||
48 | stx %g6, [%sp + 2047 + 0x180] | ||
49 | stx %g7, [%sp + 2047 + 0x188] | ||
50 | mov %g1, %l0 ! also save to locals, so we can handle | ||
51 | mov %g2, %l1 ! tlb faults later on, when accessing | ||
52 | mov %g3, %l3 ! the stack. | ||
53 | mov %g7, %l5 | ||
54 | wrpr %l4, PSTATE_IE, %pstate ! turn off interrupts | ||
55 | call %l2 | ||
56 | add %i0, 0x018, %o0 ! prom_args | ||
57 | wrpr %g0, 0x414, %pstate ! restore mmu globals | ||
58 | mov %l0, %g1 | ||
59 | mov %l1, %g2 | ||
60 | mov %l3, %g3 | ||
61 | mov %l5, %g7 | ||
62 | wrpr %g0, 0x14, %pstate ! restore normal globals | ||
63 | ldx [%sp + 2047 + 0x120], %g1 | ||
64 | ldx [%sp + 2047 + 0x128], %g2 | ||
65 | ldx [%sp + 2047 + 0x130], %g3 | ||
66 | ldx [%sp + 2047 + 0x138], %g4 | ||
67 | ldx [%sp + 2047 + 0x140], %g5 | ||
68 | ldx [%sp + 2047 + 0x148], %g6 | ||
69 | ldx [%sp + 2047 + 0x150], %g7 | ||
70 | wrpr %g0, 0x814, %pstate ! restore interrupt globals | ||
71 | ldx [%sp + 2047 + 0x0e8], %g1 | ||
72 | ldx [%sp + 2047 + 0x0f0], %g2 | ||
73 | ldx [%sp + 2047 + 0x0f8], %g3 | ||
74 | ldx [%sp + 2047 + 0x100], %g4 | ||
75 | ldx [%sp + 2047 + 0x108], %g5 | ||
76 | ldx [%sp + 2047 + 0x110], %g6 | ||
77 | ldx [%sp + 2047 + 0x118], %g7 | ||
78 | wrpr %g0, 0x15, %pstate ! restore alternate globals | ||
79 | ldx [%sp + 2047 + 0x0b0], %g1 | ||
80 | ldx [%sp + 2047 + 0x0b8], %g2 | ||
81 | ldx [%sp + 2047 + 0x0c0], %g3 | ||
82 | ldx [%sp + 2047 + 0x0c8], %g4 | ||
83 | ldx [%sp + 2047 + 0x0d0], %g5 | ||
84 | ldx [%sp + 2047 + 0x0d8], %g6 | ||
85 | ldx [%sp + 2047 + 0x0e0], %g7 | ||
86 | wrpr %l4, 0, %pstate ! restore original pstate | ||
87 | ret | ||
88 | restore | ||
89 | |||
90 | .globl prom_cif_callback | ||
91 | prom_cif_callback: | ||
92 | sethi %hi(p1275buf), %o1 | ||
93 | or %o1, %lo(p1275buf), %o1 | ||
94 | save %sp, -0x270, %sp | ||
95 | rdpr %pstate, %l4 | ||
96 | wrpr %g0, 0x15, %pstate ! save PROM alternate globals | ||
97 | stx %g1, [%sp + 2047 + 0x0b0] | ||
98 | stx %g2, [%sp + 2047 + 0x0b8] | ||
99 | stx %g3, [%sp + 2047 + 0x0c0] | ||
100 | stx %g4, [%sp + 2047 + 0x0c8] | ||
101 | stx %g5, [%sp + 2047 + 0x0d0] | ||
102 | stx %g6, [%sp + 2047 + 0x0d8] | ||
103 | stx %g7, [%sp + 2047 + 0x0e0] | ||
104 | ! restore Linux alternate globals | ||
105 | ldx [%sp + 2047 + 0x190], %g1 | ||
106 | ldx [%sp + 2047 + 0x198], %g2 | ||
107 | ldx [%sp + 2047 + 0x1a0], %g3 | ||
108 | ldx [%sp + 2047 + 0x1a8], %g4 | ||
109 | ldx [%sp + 2047 + 0x1b0], %g5 | ||
110 | ldx [%sp + 2047 + 0x1b8], %g6 | ||
111 | ldx [%sp + 2047 + 0x1c0], %g7 | ||
112 | wrpr %g0, 0x814, %pstate ! save PROM interrupt globals | ||
113 | stx %g1, [%sp + 2047 + 0x0e8] | ||
114 | stx %g2, [%sp + 2047 + 0x0f0] | ||
115 | stx %g3, [%sp + 2047 + 0x0f8] | ||
116 | stx %g4, [%sp + 2047 + 0x100] | ||
117 | stx %g5, [%sp + 2047 + 0x108] | ||
118 | stx %g6, [%sp + 2047 + 0x110] | ||
119 | stx %g7, [%sp + 2047 + 0x118] | ||
120 | ! restore Linux interrupt globals | ||
121 | ldx [%sp + 2047 + 0x1c8], %g1 | ||
122 | ldx [%sp + 2047 + 0x1d0], %g2 | ||
123 | ldx [%sp + 2047 + 0x1d8], %g3 | ||
124 | ldx [%sp + 2047 + 0x1e0], %g4 | ||
125 | ldx [%sp + 2047 + 0x1e8], %g5 | ||
126 | ldx [%sp + 2047 + 0x1f0], %g6 | ||
127 | ldx [%sp + 2047 + 0x1f8], %g7 | ||
128 | wrpr %g0, 0x14, %pstate ! save PROM normal globals | ||
129 | stx %g1, [%sp + 2047 + 0x120] | ||
130 | stx %g2, [%sp + 2047 + 0x128] | ||
131 | stx %g3, [%sp + 2047 + 0x130] | ||
132 | stx %g4, [%sp + 2047 + 0x138] | ||
133 | stx %g5, [%sp + 2047 + 0x140] | ||
134 | stx %g6, [%sp + 2047 + 0x148] | ||
135 | stx %g7, [%sp + 2047 + 0x150] | ||
136 | ! restore Linux normal globals | ||
137 | ldx [%sp + 2047 + 0x200], %g1 | ||
138 | ldx [%sp + 2047 + 0x208], %g2 | ||
139 | ldx [%sp + 2047 + 0x210], %g3 | ||
140 | ldx [%sp + 2047 + 0x218], %g4 | ||
141 | ldx [%sp + 2047 + 0x220], %g5 | ||
142 | ldx [%sp + 2047 + 0x228], %g6 | ||
143 | ldx [%sp + 2047 + 0x230], %g7 | ||
144 | wrpr %g0, 0x414, %pstate ! save PROM mmu globals | ||
145 | stx %g1, [%sp + 2047 + 0x158] | ||
146 | stx %g2, [%sp + 2047 + 0x160] | ||
147 | stx %g3, [%sp + 2047 + 0x168] | ||
148 | stx %g4, [%sp + 2047 + 0x170] | ||
149 | stx %g5, [%sp + 2047 + 0x178] | ||
150 | stx %g6, [%sp + 2047 + 0x180] | ||
151 | stx %g7, [%sp + 2047 + 0x188] | ||
152 | ! restore Linux mmu globals | ||
153 | ldx [%sp + 2047 + 0x238], %o0 | ||
154 | ldx [%sp + 2047 + 0x240], %o1 | ||
155 | ldx [%sp + 2047 + 0x248], %l2 | ||
156 | ldx [%sp + 2047 + 0x250], %l3 | ||
157 | ldx [%sp + 2047 + 0x258], %l5 | ||
158 | ldx [%sp + 2047 + 0x260], %l6 | ||
159 | ldx [%sp + 2047 + 0x268], %l7 | ||
160 | ! switch to Linux tba | ||
161 | sethi %hi(sparc64_ttable_tl0), %l1 | ||
162 | rdpr %tba, %l0 ! save PROM tba | ||
163 | mov %o0, %g1 | ||
164 | mov %o1, %g2 | ||
165 | mov %l2, %g3 | ||
166 | mov %l3, %g4 | ||
167 | mov %l5, %g5 | ||
168 | mov %l6, %g6 | ||
169 | mov %l7, %g7 | ||
170 | wrpr %l1, %tba ! install Linux tba | ||
171 | wrpr %l4, 0, %pstate ! restore PSTATE | ||
172 | call prom_world | ||
173 | mov %g0, %o0 | ||
174 | ldx [%i1 + 0x000], %l2 | ||
175 | call %l2 | ||
176 | mov %i0, %o0 | ||
177 | mov %o0, %l1 | ||
178 | call prom_world | ||
179 | or %g0, 1, %o0 | ||
180 | wrpr %g0, 0x14, %pstate ! interrupts off | ||
181 | ! restore PROM mmu globals | ||
182 | ldx [%sp + 2047 + 0x158], %o0 | ||
183 | ldx [%sp + 2047 + 0x160], %o1 | ||
184 | ldx [%sp + 2047 + 0x168], %l2 | ||
185 | ldx [%sp + 2047 + 0x170], %l3 | ||
186 | ldx [%sp + 2047 + 0x178], %l5 | ||
187 | ldx [%sp + 2047 + 0x180], %l6 | ||
188 | ldx [%sp + 2047 + 0x188], %l7 | ||
189 | wrpr %g0, 0x414, %pstate ! restore PROM mmu globals | ||
190 | mov %o0, %g1 | ||
191 | mov %o1, %g2 | ||
192 | mov %l2, %g3 | ||
193 | mov %l3, %g4 | ||
194 | mov %l5, %g5 | ||
195 | mov %l6, %g6 | ||
196 | mov %l7, %g7 | ||
197 | wrpr %l0, %tba ! restore PROM tba | ||
198 | wrpr %g0, 0x14, %pstate ! restore PROM normal globals | ||
199 | ldx [%sp + 2047 + 0x120], %g1 | ||
200 | ldx [%sp + 2047 + 0x128], %g2 | ||
201 | ldx [%sp + 2047 + 0x130], %g3 | ||
202 | ldx [%sp + 2047 + 0x138], %g4 | ||
203 | ldx [%sp + 2047 + 0x140], %g5 | ||
204 | ldx [%sp + 2047 + 0x148], %g6 | ||
205 | ldx [%sp + 2047 + 0x150], %g7 | ||
206 | wrpr %g0, 0x814, %pstate ! restore PROM interrupt globals | ||
207 | ldx [%sp + 2047 + 0x0e8], %g1 | ||
208 | ldx [%sp + 2047 + 0x0f0], %g2 | ||
209 | ldx [%sp + 2047 + 0x0f8], %g3 | ||
210 | ldx [%sp + 2047 + 0x100], %g4 | ||
211 | ldx [%sp + 2047 + 0x108], %g5 | ||
212 | ldx [%sp + 2047 + 0x110], %g6 | ||
213 | ldx [%sp + 2047 + 0x118], %g7 | ||
214 | wrpr %g0, 0x15, %pstate ! restore PROM alternate globals | ||
215 | ldx [%sp + 2047 + 0x0b0], %g1 | ||
216 | ldx [%sp + 2047 + 0x0b8], %g2 | ||
217 | ldx [%sp + 2047 + 0x0c0], %g3 | ||
218 | ldx [%sp + 2047 + 0x0c8], %g4 | ||
219 | ldx [%sp + 2047 + 0x0d0], %g5 | ||
220 | ldx [%sp + 2047 + 0x0d8], %g6 | ||
221 | ldx [%sp + 2047 + 0x0e0], %g7 | ||
222 | wrpr %l4, 0, %pstate | ||
223 | ret | ||
224 | restore %l1, 0, %o0 | ||
225 | |||
diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c new file mode 100644 index 000000000000..028a53fcb1ec --- /dev/null +++ b/arch/sparc64/prom/console.c | |||
@@ -0,0 +1,146 @@ | |||
1 | /* $Id: console.c,v 1.9 1997/10/29 07:41:43 ecd Exp $ | ||
2 | * console.c: Routines that deal with sending and receiving IO | ||
3 | * to/from the current console device using the PROM. | ||
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 <asm/openprom.h> | ||
13 | #include <asm/oplib.h> | ||
14 | #include <asm/system.h> | ||
15 | #include <linux/string.h> | ||
16 | |||
17 | extern int prom_stdin, prom_stdout; | ||
18 | |||
19 | /* Non blocking get character from console input device, returns -1 | ||
20 | * if no input was taken. This can be used for polling. | ||
21 | */ | ||
22 | __inline__ int | ||
23 | prom_nbgetchar(void) | ||
24 | { | ||
25 | char inc; | ||
26 | |||
27 | if (p1275_cmd("read", P1275_ARG(1,P1275_ARG_OUT_BUF)| | ||
28 | P1275_INOUT(3,1), | ||
29 | prom_stdin, &inc, P1275_SIZE(1)) == 1) | ||
30 | return inc; | ||
31 | else | ||
32 | return -1; | ||
33 | } | ||
34 | |||
35 | /* Non blocking put character to console device, returns -1 if | ||
36 | * unsuccessful. | ||
37 | */ | ||
38 | __inline__ int | ||
39 | prom_nbputchar(char c) | ||
40 | { | ||
41 | char outc; | ||
42 | |||
43 | outc = c; | ||
44 | if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)| | ||
45 | P1275_INOUT(3,1), | ||
46 | prom_stdout, &outc, P1275_SIZE(1)) == 1) | ||
47 | return 0; | ||
48 | else | ||
49 | return -1; | ||
50 | } | ||
51 | |||
52 | /* Blocking version of get character routine above. */ | ||
53 | char | ||
54 | prom_getchar(void) | ||
55 | { | ||
56 | int character; | ||
57 | while((character = prom_nbgetchar()) == -1) ; | ||
58 | return (char) character; | ||
59 | } | ||
60 | |||
61 | /* Blocking version of put character routine above. */ | ||
62 | void | ||
63 | prom_putchar(char c) | ||
64 | { | ||
65 | prom_nbputchar(c); | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | void | ||
70 | prom_puts(char *s, int len) | ||
71 | { | ||
72 | p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)| | ||
73 | P1275_INOUT(3,1), | ||
74 | prom_stdout, s, P1275_SIZE(len)); | ||
75 | } | ||
76 | |||
77 | /* Query for input device type */ | ||
78 | enum prom_input_device | ||
79 | prom_query_input_device(void) | ||
80 | { | ||
81 | int st_p; | ||
82 | char propb[64]; | ||
83 | |||
84 | st_p = prom_inst2pkg(prom_stdin); | ||
85 | if(prom_node_has_property(st_p, "keyboard")) | ||
86 | return PROMDEV_IKBD; | ||
87 | prom_getproperty(st_p, "device_type", propb, sizeof(propb)); | ||
88 | if(strncmp(propb, "serial", 6)) | ||
89 | return PROMDEV_I_UNK; | ||
90 | /* FIXME: Is there any better way how to find out? */ | ||
91 | memset(propb, 0, sizeof(propb)); | ||
92 | st_p = prom_finddevice ("/options"); | ||
93 | prom_getproperty(st_p, "input-device", propb, sizeof(propb)); | ||
94 | |||
95 | /* | ||
96 | * If we get here with propb == 'keyboard', we are on ttya, as | ||
97 | * the PROM defaulted to this due to 'no input device'. | ||
98 | */ | ||
99 | if (!strncmp(propb, "keyboard", 8)) | ||
100 | return PROMDEV_ITTYA; | ||
101 | |||
102 | if (strncmp (propb, "tty", 3) || !propb[3]) | ||
103 | return PROMDEV_I_UNK; | ||
104 | switch (propb[3]) { | ||
105 | case 'a': return PROMDEV_ITTYA; | ||
106 | case 'b': return PROMDEV_ITTYB; | ||
107 | default: return PROMDEV_I_UNK; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /* Query for output device type */ | ||
112 | |||
113 | enum prom_output_device | ||
114 | prom_query_output_device(void) | ||
115 | { | ||
116 | int st_p; | ||
117 | char propb[64]; | ||
118 | int propl; | ||
119 | |||
120 | st_p = prom_inst2pkg(prom_stdout); | ||
121 | propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); | ||
122 | if (propl >= 0 && propl == sizeof("display") && | ||
123 | strncmp("display", propb, sizeof("display")) == 0) | ||
124 | return PROMDEV_OSCREEN; | ||
125 | if(strncmp("serial", propb, 6)) | ||
126 | return PROMDEV_O_UNK; | ||
127 | /* FIXME: Is there any better way how to find out? */ | ||
128 | memset(propb, 0, sizeof(propb)); | ||
129 | st_p = prom_finddevice ("/options"); | ||
130 | prom_getproperty(st_p, "output-device", propb, sizeof(propb)); | ||
131 | |||
132 | /* | ||
133 | * If we get here with propb == 'screen', we are on ttya, as | ||
134 | * the PROM defaulted to this due to 'no input device'. | ||
135 | */ | ||
136 | if (!strncmp(propb, "screen", 6)) | ||
137 | return PROMDEV_OTTYA; | ||
138 | |||
139 | if (strncmp (propb, "tty", 3) || !propb[3]) | ||
140 | return PROMDEV_O_UNK; | ||
141 | switch (propb[3]) { | ||
142 | case 'a': return PROMDEV_OTTYA; | ||
143 | case 'b': return PROMDEV_OTTYB; | ||
144 | default: return PROMDEV_O_UNK; | ||
145 | } | ||
146 | } | ||
diff --git a/arch/sparc64/prom/devops.c b/arch/sparc64/prom/devops.c new file mode 100644 index 000000000000..2c99b21b6981 --- /dev/null +++ b/arch/sparc64/prom/devops.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* $Id: devops.c,v 1.3 1997/10/29 07:43:28 ecd Exp $ | ||
2 | * devops.c: Device operations using the PROM. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
6 | */ | ||
7 | #include <linux/types.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/sched.h> | ||
10 | |||
11 | #include <asm/openprom.h> | ||
12 | #include <asm/oplib.h> | ||
13 | |||
14 | /* Open the device described by the string 'dstr'. Returns the handle | ||
15 | * to that device used for subsequent operations on that device. | ||
16 | * Returns 0 on failure. | ||
17 | */ | ||
18 | int | ||
19 | prom_devopen(char *dstr) | ||
20 | { | ||
21 | return p1275_cmd ("open", P1275_ARG(0,P1275_ARG_IN_STRING)| | ||
22 | P1275_INOUT(1,1), | ||
23 | dstr); | ||
24 | } | ||
25 | |||
26 | /* Close the device described by device handle 'dhandle'. */ | ||
27 | int | ||
28 | prom_devclose(int dhandle) | ||
29 | { | ||
30 | p1275_cmd ("close", P1275_INOUT(1,0), dhandle); | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | /* Seek to specified location described by 'seekhi' and 'seeklo' | ||
35 | * for device 'dhandle'. | ||
36 | */ | ||
37 | void | ||
38 | prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) | ||
39 | { | ||
40 | p1275_cmd ("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo); | ||
41 | } | ||
diff --git a/arch/sparc64/prom/init.c b/arch/sparc64/prom/init.c new file mode 100644 index 000000000000..817faae058cd --- /dev/null +++ b/arch/sparc64/prom/init.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* $Id: init.c,v 1.10 1999/09/21 14:35:59 davem Exp $ | ||
2 | * init.c: Initialize internal variables used by the PROM | ||
3 | * library functions. | ||
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/kernel.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/ctype.h> | ||
13 | |||
14 | #include <asm/openprom.h> | ||
15 | #include <asm/oplib.h> | ||
16 | |||
17 | enum prom_major_version prom_vers; | ||
18 | unsigned int prom_rev, prom_prev; | ||
19 | |||
20 | /* The root node of the prom device tree. */ | ||
21 | int prom_root_node; | ||
22 | int prom_stdin, prom_stdout; | ||
23 | int prom_chosen_node; | ||
24 | |||
25 | /* You must call prom_init() before you attempt to use any of the | ||
26 | * routines in the prom library. It returns 0 on success, 1 on | ||
27 | * failure. It gets passed the pointer to the PROM vector. | ||
28 | */ | ||
29 | |||
30 | extern void prom_meminit(void); | ||
31 | extern void prom_cif_init(void *, void *); | ||
32 | |||
33 | void __init prom_init(void *cif_handler, void *cif_stack) | ||
34 | { | ||
35 | char buffer[80], *p; | ||
36 | int ints[3]; | ||
37 | int node; | ||
38 | int i = 0; | ||
39 | int bufadjust; | ||
40 | |||
41 | prom_vers = PROM_P1275; | ||
42 | |||
43 | prom_cif_init(cif_handler, cif_stack); | ||
44 | |||
45 | prom_root_node = prom_getsibling(0); | ||
46 | if((prom_root_node == 0) || (prom_root_node == -1)) | ||
47 | prom_halt(); | ||
48 | |||
49 | prom_chosen_node = prom_finddevice("/chosen"); | ||
50 | if (!prom_chosen_node || prom_chosen_node == -1) | ||
51 | prom_halt(); | ||
52 | |||
53 | prom_stdin = prom_getint (prom_chosen_node, "stdin"); | ||
54 | prom_stdout = prom_getint (prom_chosen_node, "stdout"); | ||
55 | |||
56 | node = prom_finddevice("/openprom"); | ||
57 | if (!node || node == -1) | ||
58 | prom_halt(); | ||
59 | |||
60 | prom_getstring (node, "version", buffer, sizeof (buffer)); | ||
61 | |||
62 | prom_printf ("\n"); | ||
63 | |||
64 | if (strncmp (buffer, "OBP ", 4)) | ||
65 | goto strange_version; | ||
66 | |||
67 | /* | ||
68 | * Version field is expected to be 'OBP xx.yy.zz date...' | ||
69 | * However, Sun can't stick to this format very well, so | ||
70 | * we need to check for 'OBP xx.yy.zz date...' and adjust | ||
71 | * accordingly. -spot | ||
72 | */ | ||
73 | |||
74 | if (strncmp (buffer, "OBP ", 5)) | ||
75 | bufadjust = 4; | ||
76 | else | ||
77 | bufadjust = 5; | ||
78 | |||
79 | p = buffer + bufadjust; | ||
80 | while (p && isdigit(*p) && i < 3) { | ||
81 | ints[i++] = simple_strtoul(p, NULL, 0); | ||
82 | if ((p = strchr(p, '.')) != NULL) | ||
83 | p++; | ||
84 | } | ||
85 | if (i != 3) | ||
86 | goto strange_version; | ||
87 | |||
88 | prom_rev = ints[1]; | ||
89 | prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2]; | ||
90 | |||
91 | printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + bufadjust); | ||
92 | |||
93 | prom_meminit(); | ||
94 | |||
95 | /* Initialization successful. */ | ||
96 | return; | ||
97 | |||
98 | strange_version: | ||
99 | prom_printf ("Strange OBP version `%s'.\n", buffer); | ||
100 | prom_halt (); | ||
101 | } | ||
diff --git a/arch/sparc64/prom/map.S b/arch/sparc64/prom/map.S new file mode 100644 index 000000000000..21b3f9c99ea7 --- /dev/null +++ b/arch/sparc64/prom/map.S | |||
@@ -0,0 +1,72 @@ | |||
1 | /* $Id: map.S,v 1.2 1999/11/19 05:53:02 davem Exp $ | ||
2 | * map.S: Tricky coding required to fixup the kernel OBP maps | ||
3 | * properly. | ||
4 | * | ||
5 | * Copyright (C) 1999 David S. Miller (davem@redhat.com) | ||
6 | */ | ||
7 | |||
8 | .text | ||
9 | .align 8192 | ||
10 | .globl prom_boot_page | ||
11 | prom_boot_page: | ||
12 | call_method: | ||
13 | .asciz "call-method" | ||
14 | .align 8 | ||
15 | map: | ||
16 | .asciz "map" | ||
17 | .align 8 | ||
18 | |||
19 | /* When we are invoked, our caller has remapped us to | ||
20 | * page zero, therefore we must use PC relative addressing | ||
21 | * for everything after we begin performing the unmap/map | ||
22 | * calls. | ||
23 | */ | ||
24 | .globl prom_remap | ||
25 | prom_remap: /* %o0 = physpage, %o1 = virtpage, %o2 = mmu_ihandle */ | ||
26 | rd %pc, %g1 | ||
27 | srl %o2, 0, %o2 ! kill sign extension | ||
28 | sethi %hi(p1275buf), %g2 | ||
29 | or %g2, %lo(p1275buf), %g2 | ||
30 | ldx [%g2 + 0x10], %g3 ! prom_cif_stack | ||
31 | save %g3, -(192 + 128), %sp | ||
32 | ldx [%g2 + 0x08], %l0 ! prom_cif_handler | ||
33 | mov %g6, %i3 | ||
34 | mov %g4, %i4 | ||
35 | mov %g5, %i5 | ||
36 | flushw | ||
37 | |||
38 | sethi %hi(prom_remap - call_method), %g7 | ||
39 | or %g7, %lo(prom_remap - call_method), %g7 | ||
40 | sub %g1, %g7, %l2 ! call-method string | ||
41 | sethi %hi(prom_remap - map), %g7 | ||
42 | or %g7, %lo(prom_remap - map), %g7 | ||
43 | sub %g1, %g7, %l4 ! map string | ||
44 | |||
45 | /* OK, map the 4MB region we really live at. */ | ||
46 | stx %l2, [%sp + 2047 + 128 + 0x00] ! call-method | ||
47 | mov 7, %l5 | ||
48 | stx %l5, [%sp + 2047 + 128 + 0x08] ! num_args | ||
49 | mov 1, %l5 | ||
50 | stx %l5, [%sp + 2047 + 128 + 0x10] ! num_rets | ||
51 | stx %l4, [%sp + 2047 + 128 + 0x18] ! map | ||
52 | stx %i2, [%sp + 2047 + 128 + 0x20] ! mmu_ihandle | ||
53 | mov -1, %l5 | ||
54 | stx %l5, [%sp + 2047 + 128 + 0x28] ! mode == default | ||
55 | sethi %hi(4 * 1024 * 1024), %l5 | ||
56 | stx %l5, [%sp + 2047 + 128 + 0x30] ! size | ||
57 | stx %i1, [%sp + 2047 + 128 + 0x38] ! vaddr | ||
58 | stx %g0, [%sp + 2047 + 128 + 0x40] ! filler | ||
59 | stx %i0, [%sp + 2047 + 128 + 0x48] ! paddr | ||
60 | call %l0 | ||
61 | add %sp, (2047 + 128), %o0 ! argument array | ||
62 | |||
63 | /* Restore hard-coded globals. */ | ||
64 | mov %i3, %g6 | ||
65 | mov %i4, %g4 | ||
66 | mov %i5, %g5 | ||
67 | |||
68 | /* Wheee.... we are done. */ | ||
69 | ret | ||
70 | restore | ||
71 | |||
72 | .align 8192 | ||
diff --git a/arch/sparc64/prom/memory.c b/arch/sparc64/prom/memory.c new file mode 100644 index 000000000000..f4a8143e052c --- /dev/null +++ b/arch/sparc64/prom/memory.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* $Id: memory.c,v 1.5 1999/08/31 06:55:04 davem Exp $ | ||
2 | * memory.c: Prom routine for acquiring various bits of information | ||
3 | * about RAM on the machine, both virtual and physical. | ||
4 | * | ||
5 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
6 | * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/init.h> | ||
11 | |||
12 | #include <asm/openprom.h> | ||
13 | #include <asm/oplib.h> | ||
14 | |||
15 | /* This routine, for consistency, returns the ram parameters in the | ||
16 | * V0 prom memory descriptor format. I choose this format because I | ||
17 | * think it was the easiest to work with. I feel the religious | ||
18 | * arguments now... ;) Also, I return the linked lists sorted to | ||
19 | * prevent paging_init() upset stomach as I have not yet written | ||
20 | * the pepto-bismol kernel module yet. | ||
21 | */ | ||
22 | |||
23 | struct linux_prom64_registers prom_reg_memlist[64]; | ||
24 | struct linux_prom64_registers prom_reg_tmp[64]; | ||
25 | |||
26 | struct linux_mlist_p1275 prom_phys_total[64]; | ||
27 | struct linux_mlist_p1275 prom_prom_taken[64]; | ||
28 | struct linux_mlist_p1275 prom_phys_avail[64]; | ||
29 | |||
30 | struct linux_mlist_p1275 *prom_ptot_ptr = prom_phys_total; | ||
31 | struct linux_mlist_p1275 *prom_ptak_ptr = prom_prom_taken; | ||
32 | struct linux_mlist_p1275 *prom_pavl_ptr = prom_phys_avail; | ||
33 | |||
34 | struct linux_mem_p1275 prom_memlist; | ||
35 | |||
36 | |||
37 | /* Internal Prom library routine to sort a linux_mlist_p1275 memory | ||
38 | * list. Used below in initialization. | ||
39 | */ | ||
40 | static void __init | ||
41 | prom_sortmemlist(struct linux_mlist_p1275 *thislist) | ||
42 | { | ||
43 | int swapi = 0; | ||
44 | int i, mitr; | ||
45 | unsigned long tmpaddr, tmpsize; | ||
46 | unsigned long lowest; | ||
47 | |||
48 | for(i=0; thislist[i].theres_more; i++) { | ||
49 | lowest = thislist[i].start_adr; | ||
50 | for(mitr = i+1; thislist[mitr-1].theres_more; mitr++) | ||
51 | if(thislist[mitr].start_adr < lowest) { | ||
52 | lowest = thislist[mitr].start_adr; | ||
53 | swapi = mitr; | ||
54 | } | ||
55 | if(lowest == thislist[i].start_adr) continue; | ||
56 | tmpaddr = thislist[swapi].start_adr; | ||
57 | tmpsize = thislist[swapi].num_bytes; | ||
58 | for(mitr = swapi; mitr > i; mitr--) { | ||
59 | thislist[mitr].start_adr = thislist[mitr-1].start_adr; | ||
60 | thislist[mitr].num_bytes = thislist[mitr-1].num_bytes; | ||
61 | } | ||
62 | thislist[i].start_adr = tmpaddr; | ||
63 | thislist[i].num_bytes = tmpsize; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | /* Initialize the memory lists based upon the prom version. */ | ||
68 | void __init prom_meminit(void) | ||
69 | { | ||
70 | int node = 0; | ||
71 | unsigned int iter, num_regs; | ||
72 | |||
73 | node = prom_finddevice("/memory"); | ||
74 | num_regs = prom_getproperty(node, "available", | ||
75 | (char *) prom_reg_memlist, | ||
76 | sizeof(prom_reg_memlist)); | ||
77 | num_regs = (num_regs/sizeof(struct linux_prom64_registers)); | ||
78 | for(iter=0; iter<num_regs; iter++) { | ||
79 | prom_phys_avail[iter].start_adr = | ||
80 | prom_reg_memlist[iter].phys_addr; | ||
81 | prom_phys_avail[iter].num_bytes = | ||
82 | prom_reg_memlist[iter].reg_size; | ||
83 | prom_phys_avail[iter].theres_more = | ||
84 | &prom_phys_avail[iter+1]; | ||
85 | } | ||
86 | prom_phys_avail[iter-1].theres_more = NULL; | ||
87 | |||
88 | num_regs = prom_getproperty(node, "reg", | ||
89 | (char *) prom_reg_memlist, | ||
90 | sizeof(prom_reg_memlist)); | ||
91 | num_regs = (num_regs/sizeof(struct linux_prom64_registers)); | ||
92 | for(iter=0; iter<num_regs; iter++) { | ||
93 | prom_phys_total[iter].start_adr = | ||
94 | prom_reg_memlist[iter].phys_addr; | ||
95 | prom_phys_total[iter].num_bytes = | ||
96 | prom_reg_memlist[iter].reg_size; | ||
97 | prom_phys_total[iter].theres_more = | ||
98 | &prom_phys_total[iter+1]; | ||
99 | } | ||
100 | prom_phys_total[iter-1].theres_more = NULL; | ||
101 | |||
102 | node = prom_finddevice("/virtual-memory"); | ||
103 | num_regs = prom_getproperty(node, "available", | ||
104 | (char *) prom_reg_memlist, | ||
105 | sizeof(prom_reg_memlist)); | ||
106 | num_regs = (num_regs/sizeof(struct linux_prom64_registers)); | ||
107 | |||
108 | /* Convert available virtual areas to taken virtual | ||
109 | * areas. First sort, then convert. | ||
110 | */ | ||
111 | for(iter=0; iter<num_regs; iter++) { | ||
112 | prom_prom_taken[iter].start_adr = | ||
113 | prom_reg_memlist[iter].phys_addr; | ||
114 | prom_prom_taken[iter].num_bytes = | ||
115 | prom_reg_memlist[iter].reg_size; | ||
116 | prom_prom_taken[iter].theres_more = | ||
117 | &prom_prom_taken[iter+1]; | ||
118 | } | ||
119 | prom_prom_taken[iter-1].theres_more = NULL; | ||
120 | |||
121 | prom_sortmemlist(prom_prom_taken); | ||
122 | |||
123 | /* Finally, convert. */ | ||
124 | for(iter=0; iter<num_regs; iter++) { | ||
125 | prom_prom_taken[iter].start_adr = | ||
126 | prom_prom_taken[iter].start_adr + | ||
127 | prom_prom_taken[iter].num_bytes; | ||
128 | prom_prom_taken[iter].num_bytes = | ||
129 | prom_prom_taken[iter+1].start_adr - | ||
130 | prom_prom_taken[iter].start_adr; | ||
131 | } | ||
132 | prom_prom_taken[iter-1].num_bytes = | ||
133 | -1UL - prom_prom_taken[iter-1].start_adr; | ||
134 | |||
135 | /* Sort the other two lists. */ | ||
136 | prom_sortmemlist(prom_phys_total); | ||
137 | prom_sortmemlist(prom_phys_avail); | ||
138 | |||
139 | /* Link all the lists into the top-level descriptor. */ | ||
140 | prom_memlist.p1275_totphys=&prom_ptot_ptr; | ||
141 | prom_memlist.p1275_prommap=&prom_ptak_ptr; | ||
142 | prom_memlist.p1275_available=&prom_pavl_ptr; | ||
143 | } | ||
144 | |||
145 | /* This returns a pointer to our libraries internal p1275 format | ||
146 | * memory descriptor. | ||
147 | */ | ||
148 | struct linux_mem_p1275 * | ||
149 | prom_meminfo(void) | ||
150 | { | ||
151 | return &prom_memlist; | ||
152 | } | ||
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c new file mode 100644 index 000000000000..19c44e97e9ee --- /dev/null +++ b/arch/sparc64/prom/misc.c | |||
@@ -0,0 +1,339 @@ | |||
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'. */ | ||
20 | void 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 | { | ||
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 | |||
71 | #ifdef CONFIG_SMP | ||
72 | extern void smp_promstop_others(void); | ||
73 | #endif | ||
74 | |||
75 | /* Drop into the prom, but completely terminate the program. | ||
76 | * No chance of continuing. | ||
77 | */ | ||
78 | void prom_halt(void) | ||
79 | { | ||
80 | #ifdef CONFIG_SMP | ||
81 | smp_promstop_others(); | ||
82 | udelay(8000); | ||
83 | #endif | ||
84 | again: | ||
85 | p1275_cmd("exit", P1275_INOUT(0, 0)); | ||
86 | goto again; /* PROM is out to get me -DaveM */ | ||
87 | } | ||
88 | |||
89 | void prom_halt_power_off(void) | ||
90 | { | ||
91 | #ifdef CONFIG_SMP | ||
92 | smp_promstop_others(); | ||
93 | udelay(8000); | ||
94 | #endif | ||
95 | p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0)); | ||
96 | |||
97 | /* if nothing else helps, we just halt */ | ||
98 | prom_halt(); | ||
99 | } | ||
100 | |||
101 | /* Set prom sync handler to call function 'funcp'. */ | ||
102 | void prom_setcallback(callback_func_t funcp) | ||
103 | { | ||
104 | if (!funcp) | ||
105 | return; | ||
106 | p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) | | ||
107 | P1275_INOUT(1, 1), funcp); | ||
108 | } | ||
109 | |||
110 | /* Get the idprom and stuff it into buffer 'idbuf'. Returns the | ||
111 | * format type. 'num_bytes' is the number of bytes that your idbuf | ||
112 | * has space for. Returns 0xff on error. | ||
113 | */ | ||
114 | unsigned char prom_get_idprom(char *idbuf, int num_bytes) | ||
115 | { | ||
116 | int len; | ||
117 | |||
118 | len = prom_getproplen(prom_root_node, "idprom"); | ||
119 | if ((len >num_bytes) || (len == -1)) | ||
120 | return 0xff; | ||
121 | if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes)) | ||
122 | return idbuf[0]; | ||
123 | |||
124 | return 0xff; | ||
125 | } | ||
126 | |||
127 | /* Get the major prom version number. */ | ||
128 | int prom_version(void) | ||
129 | { | ||
130 | return PROM_P1275; | ||
131 | } | ||
132 | |||
133 | /* Get the prom plugin-revision. */ | ||
134 | int prom_getrev(void) | ||
135 | { | ||
136 | return prom_rev; | ||
137 | } | ||
138 | |||
139 | /* Get the prom firmware print revision. */ | ||
140 | int prom_getprev(void) | ||
141 | { | ||
142 | return prom_prev; | ||
143 | } | ||
144 | |||
145 | /* Install Linux trap table so PROM uses that instead of its own. */ | ||
146 | void prom_set_trap_table(unsigned long tba) | ||
147 | { | ||
148 | p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba); | ||
149 | } | ||
150 | |||
151 | int mmu_ihandle_cache = 0; | ||
152 | |||
153 | int prom_get_mmu_ihandle(void) | ||
154 | { | ||
155 | int node, ret; | ||
156 | |||
157 | if (mmu_ihandle_cache != 0) | ||
158 | return mmu_ihandle_cache; | ||
159 | |||
160 | node = prom_finddevice("/chosen"); | ||
161 | ret = prom_getint(node, "mmu"); | ||
162 | if (ret == -1 || ret == 0) | ||
163 | mmu_ihandle_cache = -1; | ||
164 | else | ||
165 | mmu_ihandle_cache = ret; | ||
166 | |||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | static int prom_get_memory_ihandle(void) | ||
171 | { | ||
172 | static int memory_ihandle_cache; | ||
173 | int node, ret; | ||
174 | |||
175 | if (memory_ihandle_cache != 0) | ||
176 | return memory_ihandle_cache; | ||
177 | |||
178 | node = prom_finddevice("/chosen"); | ||
179 | ret = prom_getint(node, "memory"); | ||
180 | if (ret == -1 || ret == 0) | ||
181 | memory_ihandle_cache = -1; | ||
182 | else | ||
183 | memory_ihandle_cache = ret; | ||
184 | |||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | /* Load explicit I/D TLB entries. */ | ||
189 | long prom_itlb_load(unsigned long index, | ||
190 | unsigned long tte_data, | ||
191 | unsigned long vaddr) | ||
192 | { | ||
193 | return p1275_cmd("call-method", | ||
194 | (P1275_ARG(0, P1275_ARG_IN_STRING) | | ||
195 | P1275_ARG(2, P1275_ARG_IN_64B) | | ||
196 | P1275_ARG(3, P1275_ARG_IN_64B) | | ||
197 | P1275_INOUT(5, 1)), | ||
198 | "SUNW,itlb-load", | ||
199 | prom_get_mmu_ihandle(), | ||
200 | /* And then our actual args are pushed backwards. */ | ||
201 | vaddr, | ||
202 | tte_data, | ||
203 | index); | ||
204 | } | ||
205 | |||
206 | long prom_dtlb_load(unsigned long index, | ||
207 | unsigned long tte_data, | ||
208 | unsigned long vaddr) | ||
209 | { | ||
210 | return p1275_cmd("call-method", | ||
211 | (P1275_ARG(0, P1275_ARG_IN_STRING) | | ||
212 | P1275_ARG(2, P1275_ARG_IN_64B) | | ||
213 | P1275_ARG(3, P1275_ARG_IN_64B) | | ||
214 | P1275_INOUT(5, 1)), | ||
215 | "SUNW,dtlb-load", | ||
216 | prom_get_mmu_ihandle(), | ||
217 | /* And then our actual args are pushed backwards. */ | ||
218 | vaddr, | ||
219 | tte_data, | ||
220 | index); | ||
221 | } | ||
222 | |||
223 | int prom_map(int mode, unsigned long size, | ||
224 | unsigned long vaddr, unsigned long paddr) | ||
225 | { | ||
226 | int ret = p1275_cmd("call-method", | ||
227 | (P1275_ARG(0, P1275_ARG_IN_STRING) | | ||
228 | P1275_ARG(3, P1275_ARG_IN_64B) | | ||
229 | P1275_ARG(4, P1275_ARG_IN_64B) | | ||
230 | P1275_ARG(6, P1275_ARG_IN_64B) | | ||
231 | P1275_INOUT(7, 1)), | ||
232 | "map", | ||
233 | prom_get_mmu_ihandle(), | ||
234 | mode, | ||
235 | size, | ||
236 | vaddr, | ||
237 | 0, | ||
238 | paddr); | ||
239 | |||
240 | if (ret == 0) | ||
241 | ret = -1; | ||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | void prom_unmap(unsigned long size, unsigned long vaddr) | ||
246 | { | ||
247 | p1275_cmd("call-method", | ||
248 | (P1275_ARG(0, P1275_ARG_IN_STRING) | | ||
249 | P1275_ARG(2, P1275_ARG_IN_64B) | | ||
250 | P1275_ARG(3, P1275_ARG_IN_64B) | | ||
251 | P1275_INOUT(4, 0)), | ||
252 | "unmap", | ||
253 | prom_get_mmu_ihandle(), | ||
254 | size, | ||
255 | vaddr); | ||
256 | } | ||
257 | |||
258 | /* Set aside physical memory which is not touched or modified | ||
259 | * across soft resets. | ||
260 | */ | ||
261 | unsigned long prom_retain(char *name, | ||
262 | unsigned long pa_low, unsigned long pa_high, | ||
263 | long size, long align) | ||
264 | { | ||
265 | /* XXX I don't think we return multiple values correctly. | ||
266 | * XXX OBP supposedly returns pa_low/pa_high here, how does | ||
267 | * XXX it work? | ||
268 | */ | ||
269 | |||
270 | /* If align is zero, the pa_low/pa_high args are passed, | ||
271 | * else they are not. | ||
272 | */ | ||
273 | if (align == 0) | ||
274 | return p1275_cmd("SUNW,retain", | ||
275 | (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)), | ||
276 | name, pa_low, pa_high, size, align); | ||
277 | else | ||
278 | return p1275_cmd("SUNW,retain", | ||
279 | (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)), | ||
280 | name, size, align); | ||
281 | } | ||
282 | |||
283 | /* Get "Unumber" string for the SIMM at the given | ||
284 | * memory address. Usually this will be of the form | ||
285 | * "Uxxxx" where xxxx is a decimal number which is | ||
286 | * etched into the motherboard next to the SIMM slot | ||
287 | * in question. | ||
288 | */ | ||
289 | int prom_getunumber(int syndrome_code, | ||
290 | unsigned long phys_addr, | ||
291 | char *buf, int buflen) | ||
292 | { | ||
293 | return p1275_cmd("call-method", | ||
294 | (P1275_ARG(0, P1275_ARG_IN_STRING) | | ||
295 | P1275_ARG(3, P1275_ARG_OUT_BUF) | | ||
296 | P1275_ARG(6, P1275_ARG_IN_64B) | | ||
297 | P1275_INOUT(8, 2)), | ||
298 | "SUNW,get-unumber", prom_get_memory_ihandle(), | ||
299 | buflen, buf, P1275_SIZE(buflen), | ||
300 | 0, phys_addr, syndrome_code); | ||
301 | } | ||
302 | |||
303 | /* Power management extensions. */ | ||
304 | void prom_sleepself(void) | ||
305 | { | ||
306 | p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0)); | ||
307 | } | ||
308 | |||
309 | int prom_sleepsystem(void) | ||
310 | { | ||
311 | return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1)); | ||
312 | } | ||
313 | |||
314 | int prom_wakeupsystem(void) | ||
315 | { | ||
316 | return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1)); | ||
317 | } | ||
318 | |||
319 | #ifdef CONFIG_SMP | ||
320 | void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0) | ||
321 | { | ||
322 | p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0); | ||
323 | } | ||
324 | |||
325 | void prom_stopself(void) | ||
326 | { | ||
327 | p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0)); | ||
328 | } | ||
329 | |||
330 | void prom_idleself(void) | ||
331 | { | ||
332 | p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0)); | ||
333 | } | ||
334 | |||
335 | void prom_resumecpu(int cpunode) | ||
336 | { | ||
337 | p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode); | ||
338 | } | ||
339 | #endif | ||
diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c new file mode 100644 index 000000000000..59fe38bba39e --- /dev/null +++ b/arch/sparc64/prom/p1275.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* $Id: p1275.c,v 1.22 2001/10/18 09:40:00 davem Exp $ | ||
2 | * p1275.c: Sun IEEE 1275 PROM low level interface routines | ||
3 | * | ||
4 | * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
5 | */ | ||
6 | |||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/sched.h> | ||
10 | #include <linux/smp.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/spinlock.h> | ||
13 | |||
14 | #include <asm/openprom.h> | ||
15 | #include <asm/oplib.h> | ||
16 | #include <asm/system.h> | ||
17 | #include <asm/spitfire.h> | ||
18 | #include <asm/pstate.h> | ||
19 | |||
20 | struct { | ||
21 | long prom_callback; /* 0x00 */ | ||
22 | void (*prom_cif_handler)(long *); /* 0x08 */ | ||
23 | unsigned long prom_cif_stack; /* 0x10 */ | ||
24 | unsigned long prom_args [23]; /* 0x18 */ | ||
25 | char prom_buffer [3000]; | ||
26 | } p1275buf; | ||
27 | |||
28 | extern void prom_world(int); | ||
29 | |||
30 | extern void prom_cif_interface(void); | ||
31 | extern void prom_cif_callback(void); | ||
32 | |||
33 | static inline unsigned long spitfire_get_primary_context(void) | ||
34 | { | ||
35 | unsigned long ctx; | ||
36 | |||
37 | __asm__ __volatile__("ldxa [%1] %2, %0" | ||
38 | : "=r" (ctx) | ||
39 | : "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
40 | return ctx; | ||
41 | } | ||
42 | |||
43 | /* | ||
44 | * This provides SMP safety on the p1275buf. prom_callback() drops this lock | ||
45 | * to allow recursuve acquisition. | ||
46 | */ | ||
47 | DEFINE_SPINLOCK(prom_entry_lock); | ||
48 | |||
49 | long p1275_cmd (char *service, long fmt, ...) | ||
50 | { | ||
51 | char *p, *q; | ||
52 | unsigned long flags; | ||
53 | int nargs, nrets, i; | ||
54 | va_list list; | ||
55 | long attrs, x; | ||
56 | |||
57 | p = p1275buf.prom_buffer; | ||
58 | BUG_ON((spitfire_get_primary_context() & CTX_NR_MASK) != 0); | ||
59 | |||
60 | spin_lock_irqsave(&prom_entry_lock, flags); | ||
61 | |||
62 | p1275buf.prom_args[0] = (unsigned long)p; /* service */ | ||
63 | strcpy (p, service); | ||
64 | p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); | ||
65 | p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ | ||
66 | p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */ | ||
67 | attrs = fmt >> 8; | ||
68 | va_start(list, fmt); | ||
69 | for (i = 0; i < nargs; i++, attrs >>= 3) { | ||
70 | switch (attrs & 0x7) { | ||
71 | case P1275_ARG_NUMBER: | ||
72 | p1275buf.prom_args[i + 3] = | ||
73 | (unsigned)va_arg(list, long); | ||
74 | break; | ||
75 | case P1275_ARG_IN_64B: | ||
76 | p1275buf.prom_args[i + 3] = | ||
77 | va_arg(list, unsigned long); | ||
78 | break; | ||
79 | case P1275_ARG_IN_STRING: | ||
80 | strcpy (p, va_arg(list, char *)); | ||
81 | p1275buf.prom_args[i + 3] = (unsigned long)p; | ||
82 | p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); | ||
83 | break; | ||
84 | case P1275_ARG_OUT_BUF: | ||
85 | (void) va_arg(list, char *); | ||
86 | p1275buf.prom_args[i + 3] = (unsigned long)p; | ||
87 | x = va_arg(list, long); | ||
88 | i++; attrs >>= 3; | ||
89 | p = (char *)(((long)(p + (int)x + 7)) & ~7); | ||
90 | p1275buf.prom_args[i + 3] = x; | ||
91 | break; | ||
92 | case P1275_ARG_IN_BUF: | ||
93 | q = va_arg(list, char *); | ||
94 | p1275buf.prom_args[i + 3] = (unsigned long)p; | ||
95 | x = va_arg(list, long); | ||
96 | i++; attrs >>= 3; | ||
97 | memcpy (p, q, (int)x); | ||
98 | p = (char *)(((long)(p + (int)x + 7)) & ~7); | ||
99 | p1275buf.prom_args[i + 3] = x; | ||
100 | break; | ||
101 | case P1275_ARG_OUT_32B: | ||
102 | (void) va_arg(list, char *); | ||
103 | p1275buf.prom_args[i + 3] = (unsigned long)p; | ||
104 | p += 32; | ||
105 | break; | ||
106 | case P1275_ARG_IN_FUNCTION: | ||
107 | p1275buf.prom_args[i + 3] = | ||
108 | (unsigned long)prom_cif_callback; | ||
109 | p1275buf.prom_callback = va_arg(list, long); | ||
110 | break; | ||
111 | } | ||
112 | } | ||
113 | va_end(list); | ||
114 | |||
115 | prom_world(1); | ||
116 | prom_cif_interface(); | ||
117 | prom_world(0); | ||
118 | |||
119 | attrs = fmt >> 8; | ||
120 | va_start(list, fmt); | ||
121 | for (i = 0; i < nargs; i++, attrs >>= 3) { | ||
122 | switch (attrs & 0x7) { | ||
123 | case P1275_ARG_NUMBER: | ||
124 | (void) va_arg(list, long); | ||
125 | break; | ||
126 | case P1275_ARG_IN_STRING: | ||
127 | (void) va_arg(list, char *); | ||
128 | break; | ||
129 | case P1275_ARG_IN_FUNCTION: | ||
130 | (void) va_arg(list, long); | ||
131 | break; | ||
132 | case P1275_ARG_IN_BUF: | ||
133 | (void) va_arg(list, char *); | ||
134 | (void) va_arg(list, long); | ||
135 | i++; attrs >>= 3; | ||
136 | break; | ||
137 | case P1275_ARG_OUT_BUF: | ||
138 | p = va_arg(list, char *); | ||
139 | x = va_arg(list, long); | ||
140 | memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x); | ||
141 | i++; attrs >>= 3; | ||
142 | break; | ||
143 | case P1275_ARG_OUT_32B: | ||
144 | p = va_arg(list, char *); | ||
145 | memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32); | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | va_end(list); | ||
150 | x = p1275buf.prom_args [nargs + 3]; | ||
151 | |||
152 | spin_unlock_irqrestore(&prom_entry_lock, flags); | ||
153 | |||
154 | return x; | ||
155 | } | ||
156 | |||
157 | void prom_cif_init(void *cif_handler, void *cif_stack) | ||
158 | { | ||
159 | p1275buf.prom_cif_handler = (void (*)(long *))cif_handler; | ||
160 | p1275buf.prom_cif_stack = (unsigned long)cif_stack; | ||
161 | } | ||
diff --git a/arch/sparc64/prom/printf.c b/arch/sparc64/prom/printf.c new file mode 100644 index 000000000000..a6df82cafa0d --- /dev/null +++ b/arch/sparc64/prom/printf.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * printf.c: Internal prom library printf facility. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
6 | * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com) | ||
7 | * | ||
8 | * We used to warn all over the code: DO NOT USE prom_printf(), | ||
9 | * and yet people do. Anton's banking code was outputting banks | ||
10 | * with prom_printf for most of the 2.4 lifetime. Since an effective | ||
11 | * stick is not available, we deployed a carrot: an early printk | ||
12 | * through PROM by means of -p boot option. This ought to fix it. | ||
13 | * USE printk; if you need, deploy -p. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | |||
18 | #include <asm/openprom.h> | ||
19 | #include <asm/oplib.h> | ||
20 | |||
21 | static char ppbuf[1024]; | ||
22 | |||
23 | void | ||
24 | prom_write(const char *buf, unsigned int n) | ||
25 | { | ||
26 | char ch; | ||
27 | |||
28 | while (n != 0) { | ||
29 | --n; | ||
30 | if ((ch = *buf++) == '\n') | ||
31 | prom_putchar('\r'); | ||
32 | prom_putchar(ch); | ||
33 | } | ||
34 | } | ||
35 | |||
36 | void | ||
37 | prom_printf(char *fmt, ...) | ||
38 | { | ||
39 | va_list args; | ||
40 | int i; | ||
41 | |||
42 | va_start(args, fmt); | ||
43 | i = vscnprintf(ppbuf, sizeof(ppbuf), fmt, args); | ||
44 | va_end(args); | ||
45 | |||
46 | prom_write(ppbuf, i); | ||
47 | } | ||
diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c new file mode 100644 index 000000000000..ccf73258ebf7 --- /dev/null +++ b/arch/sparc64/prom/tree.c | |||
@@ -0,0 +1,377 @@ | |||
1 | /* $Id: tree.c,v 1.10 1998/01/10 22:39:00 ecd Exp $ | ||
2 | * tree.c: Basic device tree traversal/scanning for the Linux | ||
3 | * prom library. | ||
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/string.h> | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/sched.h> | ||
13 | |||
14 | #include <asm/openprom.h> | ||
15 | #include <asm/oplib.h> | ||
16 | |||
17 | /* Return the child of node 'node' or zero if no this node has no | ||
18 | * direct descendent. | ||
19 | */ | ||
20 | __inline__ int | ||
21 | __prom_getchild(int node) | ||
22 | { | ||
23 | return p1275_cmd ("child", P1275_INOUT(1, 1), node); | ||
24 | } | ||
25 | |||
26 | __inline__ int | ||
27 | prom_getchild(int node) | ||
28 | { | ||
29 | int cnode; | ||
30 | |||
31 | if(node == -1) return 0; | ||
32 | cnode = __prom_getchild(node); | ||
33 | if(cnode == -1) return 0; | ||
34 | return (int)cnode; | ||
35 | } | ||
36 | |||
37 | __inline__ int | ||
38 | prom_getparent(int node) | ||
39 | { | ||
40 | int cnode; | ||
41 | |||
42 | if(node == -1) return 0; | ||
43 | cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node); | ||
44 | if(cnode == -1) return 0; | ||
45 | return (int)cnode; | ||
46 | } | ||
47 | |||
48 | /* Return the next sibling of node 'node' or zero if no more siblings | ||
49 | * at this level of depth in the tree. | ||
50 | */ | ||
51 | __inline__ int | ||
52 | __prom_getsibling(int node) | ||
53 | { | ||
54 | return p1275_cmd ("peer", P1275_INOUT(1, 1), node); | ||
55 | } | ||
56 | |||
57 | __inline__ int | ||
58 | prom_getsibling(int node) | ||
59 | { | ||
60 | int sibnode; | ||
61 | |||
62 | if(node == -1) return 0; | ||
63 | sibnode = __prom_getsibling(node); | ||
64 | if(sibnode == -1) return 0; | ||
65 | return sibnode; | ||
66 | } | ||
67 | |||
68 | /* Return the length in bytes of property 'prop' at node 'node'. | ||
69 | * Return -1 on error. | ||
70 | */ | ||
71 | __inline__ int | ||
72 | prom_getproplen(int node, char *prop) | ||
73 | { | ||
74 | if((!node) || (!prop)) return -1; | ||
75 | return p1275_cmd ("getproplen", | ||
76 | P1275_ARG(1,P1275_ARG_IN_STRING)| | ||
77 | P1275_INOUT(2, 1), | ||
78 | node, prop); | ||
79 | } | ||
80 | |||
81 | /* Acquire a property 'prop' at node 'node' and place it in | ||
82 | * 'buffer' which has a size of 'bufsize'. If the acquisition | ||
83 | * was successful the length will be returned, else -1 is returned. | ||
84 | */ | ||
85 | __inline__ int | ||
86 | prom_getproperty(int node, char *prop, char *buffer, int bufsize) | ||
87 | { | ||
88 | int plen; | ||
89 | |||
90 | plen = prom_getproplen(node, prop); | ||
91 | if((plen > bufsize) || (plen == 0) || (plen == -1)) | ||
92 | return -1; | ||
93 | else { | ||
94 | /* Ok, things seem all right. */ | ||
95 | return p1275_cmd ("getprop", | ||
96 | P1275_ARG(1,P1275_ARG_IN_STRING)| | ||
97 | P1275_ARG(2,P1275_ARG_OUT_BUF)| | ||
98 | P1275_INOUT(4, 1), | ||
99 | node, prop, buffer, P1275_SIZE(plen)); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | /* Acquire an integer property and return its value. Returns -1 | ||
104 | * on failure. | ||
105 | */ | ||
106 | __inline__ int | ||
107 | prom_getint(int node, char *prop) | ||
108 | { | ||
109 | int intprop; | ||
110 | |||
111 | if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) | ||
112 | return intprop; | ||
113 | |||
114 | return -1; | ||
115 | } | ||
116 | |||
117 | /* Acquire an integer property, upon error return the passed default | ||
118 | * integer. | ||
119 | */ | ||
120 | |||
121 | int | ||
122 | prom_getintdefault(int node, char *property, int deflt) | ||
123 | { | ||
124 | int retval; | ||
125 | |||
126 | retval = prom_getint(node, property); | ||
127 | if(retval == -1) return deflt; | ||
128 | |||
129 | return retval; | ||
130 | } | ||
131 | |||
132 | /* Acquire a boolean property, 1=TRUE 0=FALSE. */ | ||
133 | int | ||
134 | prom_getbool(int node, char *prop) | ||
135 | { | ||
136 | int retval; | ||
137 | |||
138 | retval = prom_getproplen(node, prop); | ||
139 | if(retval == -1) return 0; | ||
140 | return 1; | ||
141 | } | ||
142 | |||
143 | /* Acquire a property whose value is a string, returns a null | ||
144 | * string on error. The char pointer is the user supplied string | ||
145 | * buffer. | ||
146 | */ | ||
147 | void | ||
148 | prom_getstring(int node, char *prop, char *user_buf, int ubuf_size) | ||
149 | { | ||
150 | int len; | ||
151 | |||
152 | len = prom_getproperty(node, prop, user_buf, ubuf_size); | ||
153 | if(len != -1) return; | ||
154 | user_buf[0] = 0; | ||
155 | return; | ||
156 | } | ||
157 | |||
158 | |||
159 | /* Does the device at node 'node' have name 'name'? | ||
160 | * YES = 1 NO = 0 | ||
161 | */ | ||
162 | int | ||
163 | prom_nodematch(int node, char *name) | ||
164 | { | ||
165 | char namebuf[128]; | ||
166 | prom_getproperty(node, "name", namebuf, sizeof(namebuf)); | ||
167 | if(strcmp(namebuf, name) == 0) return 1; | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | /* Search siblings at 'node_start' for a node with name | ||
172 | * 'nodename'. Return node if successful, zero if not. | ||
173 | */ | ||
174 | int | ||
175 | prom_searchsiblings(int node_start, char *nodename) | ||
176 | { | ||
177 | |||
178 | int thisnode, error; | ||
179 | char promlib_buf[128]; | ||
180 | |||
181 | for(thisnode = node_start; thisnode; | ||
182 | thisnode=prom_getsibling(thisnode)) { | ||
183 | error = prom_getproperty(thisnode, "name", promlib_buf, | ||
184 | sizeof(promlib_buf)); | ||
185 | /* Should this ever happen? */ | ||
186 | if(error == -1) continue; | ||
187 | if(strcmp(nodename, promlib_buf)==0) return thisnode; | ||
188 | } | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | /* Gets name in the {name@x,yyyyy|name (if no reg)} form */ | ||
194 | int | ||
195 | prom_getname (int node, char *buffer, int len) | ||
196 | { | ||
197 | int i, sbus = 0; | ||
198 | int pci = 0, ebus = 0, ide = 0; | ||
199 | struct linux_prom_registers *reg; | ||
200 | struct linux_prom64_registers reg64[PROMREG_MAX]; | ||
201 | |||
202 | for (sbus = prom_getparent (node); sbus; sbus = prom_getparent (sbus)) { | ||
203 | i = prom_getproperty (sbus, "name", buffer, len); | ||
204 | if (i > 0) { | ||
205 | buffer [i] = 0; | ||
206 | if (!strcmp (buffer, "sbus")) | ||
207 | goto getit; | ||
208 | } | ||
209 | } | ||
210 | if ((pci = prom_getparent (node))) { | ||
211 | i = prom_getproperty (pci, "name", buffer, len); | ||
212 | if (i > 0) { | ||
213 | buffer [i] = 0; | ||
214 | if (!strcmp (buffer, "pci")) | ||
215 | goto getit; | ||
216 | } | ||
217 | pci = 0; | ||
218 | } | ||
219 | if ((ebus = prom_getparent (node))) { | ||
220 | i = prom_getproperty (ebus, "name", buffer, len); | ||
221 | if (i > 0) { | ||
222 | buffer[i] = 0; | ||
223 | if (!strcmp (buffer, "ebus")) | ||
224 | goto getit; | ||
225 | } | ||
226 | ebus = 0; | ||
227 | } | ||
228 | if ((ide = prom_getparent (node))) { | ||
229 | i = prom_getproperty (ide, "name", buffer, len); | ||
230 | if (i > 0) { | ||
231 | buffer [i] = 0; | ||
232 | if (!strcmp (buffer, "ide")) | ||
233 | goto getit; | ||
234 | } | ||
235 | ide = 0; | ||
236 | } | ||
237 | getit: | ||
238 | i = prom_getproperty (node, "name", buffer, len); | ||
239 | if (i <= 0) { | ||
240 | buffer [0] = 0; | ||
241 | return -1; | ||
242 | } | ||
243 | buffer [i] = 0; | ||
244 | len -= i; | ||
245 | i = prom_getproperty (node, "reg", (char *)reg64, sizeof (reg64)); | ||
246 | if (i <= 0) return 0; | ||
247 | if (len < 16) return -1; | ||
248 | buffer = strchr (buffer, 0); | ||
249 | if (sbus) { | ||
250 | reg = (struct linux_prom_registers *)reg64; | ||
251 | sprintf (buffer, "@%x,%x", reg[0].which_io, (uint)reg[0].phys_addr); | ||
252 | } else if (pci) { | ||
253 | int dev, fn; | ||
254 | reg = (struct linux_prom_registers *)reg64; | ||
255 | fn = (reg[0].which_io >> 8) & 0x07; | ||
256 | dev = (reg[0].which_io >> 11) & 0x1f; | ||
257 | if (fn) | ||
258 | sprintf (buffer, "@%x,%x", dev, fn); | ||
259 | else | ||
260 | sprintf (buffer, "@%x", dev); | ||
261 | } else if (ebus) { | ||
262 | reg = (struct linux_prom_registers *)reg64; | ||
263 | sprintf (buffer, "@%x,%x", reg[0].which_io, reg[0].phys_addr); | ||
264 | } else if (ide) { | ||
265 | reg = (struct linux_prom_registers *)reg64; | ||
266 | sprintf (buffer, "@%x,%x", reg[0].which_io, reg[0].phys_addr); | ||
267 | } else if (i == 4) { /* Happens on 8042's children on Ultra/PCI. */ | ||
268 | reg = (struct linux_prom_registers *)reg64; | ||
269 | sprintf (buffer, "@%x", reg[0].which_io); | ||
270 | } else { | ||
271 | sprintf (buffer, "@%x,%x", | ||
272 | (unsigned int)(reg64[0].phys_addr >> 36), | ||
273 | (unsigned int)(reg64[0].phys_addr)); | ||
274 | } | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | /* Return the first property type for node 'node'. | ||
279 | * buffer should be at least 32B in length | ||
280 | */ | ||
281 | __inline__ char * | ||
282 | prom_firstprop(int node, char *buffer) | ||
283 | { | ||
284 | *buffer = 0; | ||
285 | if(node == -1) return buffer; | ||
286 | p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)| | ||
287 | P1275_INOUT(3, 0), | ||
288 | node, (char *) 0x0, buffer); | ||
289 | return buffer; | ||
290 | } | ||
291 | |||
292 | /* Return the property type string after property type 'oprop' | ||
293 | * at node 'node' . Returns NULL string if no more | ||
294 | * property types for this node. | ||
295 | */ | ||
296 | __inline__ char * | ||
297 | prom_nextprop(int node, char *oprop, char *buffer) | ||
298 | { | ||
299 | char buf[32]; | ||
300 | |||
301 | if(node == -1) { | ||
302 | *buffer = 0; | ||
303 | return buffer; | ||
304 | } | ||
305 | if (oprop == buffer) { | ||
306 | strcpy (buf, oprop); | ||
307 | oprop = buf; | ||
308 | } | ||
309 | p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)| | ||
310 | P1275_ARG(2,P1275_ARG_OUT_32B)| | ||
311 | P1275_INOUT(3, 0), | ||
312 | node, oprop, buffer); | ||
313 | return buffer; | ||
314 | } | ||
315 | |||
316 | int | ||
317 | prom_finddevice(char *name) | ||
318 | { | ||
319 | if(!name) return 0; | ||
320 | return p1275_cmd ("finddevice", P1275_ARG(0,P1275_ARG_IN_STRING)| | ||
321 | P1275_INOUT(1, 1), | ||
322 | name); | ||
323 | } | ||
324 | |||
325 | int prom_node_has_property(int node, char *prop) | ||
326 | { | ||
327 | char buf [32]; | ||
328 | |||
329 | *buf = 0; | ||
330 | do { | ||
331 | prom_nextprop(node, buf, buf); | ||
332 | if(!strcmp(buf, prop)) | ||
333 | return 1; | ||
334 | } while (*buf); | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | /* Set property 'pname' at node 'node' to value 'value' which has a length | ||
339 | * of 'size' bytes. Return the number of bytes the prom accepted. | ||
340 | */ | ||
341 | int | ||
342 | prom_setprop(int node, char *pname, char *value, int size) | ||
343 | { | ||
344 | if(size == 0) return 0; | ||
345 | if((pname == 0) || (value == 0)) return 0; | ||
346 | |||
347 | return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)| | ||
348 | P1275_ARG(2,P1275_ARG_IN_BUF)| | ||
349 | P1275_INOUT(4, 1), | ||
350 | node, pname, value, P1275_SIZE(size)); | ||
351 | } | ||
352 | |||
353 | __inline__ int | ||
354 | prom_inst2pkg(int inst) | ||
355 | { | ||
356 | int node; | ||
357 | |||
358 | node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst); | ||
359 | if (node == -1) return 0; | ||
360 | return node; | ||
361 | } | ||
362 | |||
363 | /* Return 'node' assigned to a particular prom 'path' | ||
364 | * FIXME: Should work for v0 as well | ||
365 | */ | ||
366 | int | ||
367 | prom_pathtoinode(char *path) | ||
368 | { | ||
369 | int node, inst; | ||
370 | |||
371 | inst = prom_devopen (path); | ||
372 | if (inst == 0) return 0; | ||
373 | node = prom_inst2pkg (inst); | ||
374 | prom_devclose (inst); | ||
375 | if (node == -1) return 0; | ||
376 | return node; | ||
377 | } | ||