aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/prom
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/prom')
-rw-r--r--arch/sparc64/prom/Makefile10
-rw-r--r--arch/sparc64/prom/bootstr.c40
-rw-r--r--arch/sparc64/prom/cif.S225
-rw-r--r--arch/sparc64/prom/console.c146
-rw-r--r--arch/sparc64/prom/devops.c41
-rw-r--r--arch/sparc64/prom/init.c101
-rw-r--r--arch/sparc64/prom/map.S72
-rw-r--r--arch/sparc64/prom/memory.c152
-rw-r--r--arch/sparc64/prom/misc.c339
-rw-r--r--arch/sparc64/prom/p1275.c161
-rw-r--r--arch/sparc64/prom/printf.c47
-rw-r--r--arch/sparc64/prom/tree.c377
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
6EXTRA_AFLAGS := -ansi
7EXTRA_CFLAGS := -Werror
8
9lib-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
18struct {
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
30char * __init
31prom_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
11prom_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
91prom_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
17extern 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
23prom_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
39prom_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. */
53char
54prom_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. */
62void
63prom_putchar(char c)
64{
65 prom_nbputchar(c);
66 return;
67}
68
69void
70prom_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 */
78enum prom_input_device
79prom_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
113enum prom_output_device
114prom_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 */
18int
19prom_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'. */
27int
28prom_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 */
37void
38prom_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
17enum prom_major_version prom_vers;
18unsigned int prom_rev, prom_prev;
19
20/* The root node of the prom device tree. */
21int prom_root_node;
22int prom_stdin, prom_stdout;
23int 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
30extern void prom_meminit(void);
31extern void prom_cif_init(void *, void *);
32
33void __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
98strange_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
11prom_boot_page:
12call_method:
13 .asciz "call-method"
14 .align 8
15map:
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
25prom_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
23struct linux_prom64_registers prom_reg_memlist[64];
24struct linux_prom64_registers prom_reg_tmp[64];
25
26struct linux_mlist_p1275 prom_phys_total[64];
27struct linux_mlist_p1275 prom_prom_taken[64];
28struct linux_mlist_p1275 prom_phys_avail[64];
29
30struct linux_mlist_p1275 *prom_ptot_ptr = prom_phys_total;
31struct linux_mlist_p1275 *prom_ptak_ptr = prom_prom_taken;
32struct linux_mlist_p1275 *prom_pavl_ptr = prom_phys_avail;
33
34struct 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 */
40static void __init
41prom_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. */
68void __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 */
148struct linux_mem_p1275 *
149prom_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'. */
20void 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'. */
27void 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. */
36extern void (*prom_palette)(int);
37
38#ifdef CONFIG_SMP
39extern void smp_capture(void);
40extern void smp_release(void);
41#endif
42
43/* Drop into the prom, with the chance to continue with the 'go'
44 * prom command.
45 */
46void 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
72extern void smp_promstop_others(void);
73#endif
74
75/* Drop into the prom, but completely terminate the program.
76 * No chance of continuing.
77 */
78void prom_halt(void)
79{
80#ifdef CONFIG_SMP
81 smp_promstop_others();
82 udelay(8000);
83#endif
84again:
85 p1275_cmd("exit", P1275_INOUT(0, 0));
86 goto again; /* PROM is out to get me -DaveM */
87}
88
89void 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'. */
102void 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 */
114unsigned 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. */
128int prom_version(void)
129{
130 return PROM_P1275;
131}
132
133/* Get the prom plugin-revision. */
134int prom_getrev(void)
135{
136 return prom_rev;
137}
138
139/* Get the prom firmware print revision. */
140int prom_getprev(void)
141{
142 return prom_prev;
143}
144
145/* Install Linux trap table so PROM uses that instead of its own. */
146void prom_set_trap_table(unsigned long tba)
147{
148 p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
149}
150
151int mmu_ihandle_cache = 0;
152
153int 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
170static 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. */
189long 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
206long 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
223int 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
245void 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 */
261unsigned 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 */
289int 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. */
304void prom_sleepself(void)
305{
306 p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0));
307}
308
309int prom_sleepsystem(void)
310{
311 return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1));
312}
313
314int prom_wakeupsystem(void)
315{
316 return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
317}
318
319#ifdef CONFIG_SMP
320void 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
325void prom_stopself(void)
326{
327 p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0));
328}
329
330void prom_idleself(void)
331{
332 p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0));
333}
334
335void 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
20struct {
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
28extern void prom_world(int);
29
30extern void prom_cif_interface(void);
31extern void prom_cif_callback(void);
32
33static 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 */
47DEFINE_SPINLOCK(prom_entry_lock);
48
49long 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
157void 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
21static char ppbuf[1024];
22
23void
24prom_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
36void
37prom_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
27prom_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
38prom_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
58prom_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
72prom_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
86prom_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
107prom_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
121int
122prom_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. */
133int
134prom_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 */
147void
148prom_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 */
162int
163prom_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 */
174int
175prom_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 */
194int
195prom_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 }
237getit:
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 *
282prom_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 *
297prom_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
316int
317prom_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
325int 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 */
341int
342prom_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
354prom_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 */
366int
367prom_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}