aboutsummaryrefslogtreecommitdiff
path: root/arch/sparc64/prom
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/sparc64/prom
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
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 00000000000..8f2420d9e9e
--- /dev/null
+++ b/arch/sparc64/prom/Makefile
@@ -0,0 +1,10 @@
+# $Id: Makefile,v 1.7 2000/12/14 22:57:25 davem Exp $
+# Makefile for the Sun Boot PROM interface library under
+# Linux.
+#
+
+EXTRA_AFLAGS := -ansi
+EXTRA_CFLAGS := -Werror
+
+lib-y := bootstr.o devops.o init.o memory.o misc.o \
+ 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 00000000000..a7278614e99
--- /dev/null
+++ b/arch/sparc64/prom/bootstr.c
@@ -0,0 +1,40 @@
+/* $Id: bootstr.c,v 1.6 1999/08/31 06:55:01 davem Exp $
+ * bootstr.c: Boot string/argument acquisition from the PROM.
+ *
+ * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright(C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/oplib.h>
+
+/* WARNING: The boot loader knows that these next three variables come one right
+ * after another in the .data section. Do not move this stuff into
+ * the .bss section or it will break things.
+ */
+
+#define BARG_LEN 256
+struct {
+ int bootstr_len;
+ int bootstr_valid;
+ char bootstr_buf[BARG_LEN];
+} bootstr_info = {
+ .bootstr_len = BARG_LEN,
+#ifdef CONFIG_CMDLINE
+ .bootstr_valid = 1,
+ .bootstr_buf = CONFIG_CMDLINE,
+#endif
+};
+
+char * __init
+prom_getbootargs(void)
+{
+ /* This check saves us from a panic when bootfd patches args. */
+ if (bootstr_info.bootstr_valid)
+ return bootstr_info.bootstr_buf;
+ prom_getstring(prom_chosen_node, "bootargs",
+ bootstr_info.bootstr_buf, BARG_LEN);
+ bootstr_info.bootstr_valid = 1;
+ return bootstr_info.bootstr_buf;
+}
diff --git a/arch/sparc64/prom/cif.S b/arch/sparc64/prom/cif.S
new file mode 100644
index 00000000000..29d0ae74aed
--- /dev/null
+++ b/arch/sparc64/prom/cif.S
@@ -0,0 +1,225 @@
+/* cif.S: PROM entry/exit assembler trampolines.
+ *
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ */
+
+#include <asm/pstate.h>
+
+ .text
+ .globl prom_cif_interface
+prom_cif_interface:
+ sethi %hi(p1275buf), %o0
+ or %o0, %lo(p1275buf), %o0
+ ldx [%o0 + 0x010], %o1 ! prom_cif_stack
+ save %o1, -0x190, %sp
+ ldx [%i0 + 0x008], %l2 ! prom_cif_handler
+ rdpr %pstate, %l4
+ wrpr %g0, 0x15, %pstate ! save alternate globals
+ stx %g1, [%sp + 2047 + 0x0b0]
+ stx %g2, [%sp + 2047 + 0x0b8]
+ stx %g3, [%sp + 2047 + 0x0c0]
+ stx %g4, [%sp + 2047 + 0x0c8]
+ stx %g5, [%sp + 2047 + 0x0d0]
+ stx %g6, [%sp + 2047 + 0x0d8]
+ stx %g7, [%sp + 2047 + 0x0e0]
+ wrpr %g0, 0x814, %pstate ! save interrupt globals
+ stx %g1, [%sp + 2047 + 0x0e8]
+ stx %g2, [%sp + 2047 + 0x0f0]
+ stx %g3, [%sp + 2047 + 0x0f8]
+ stx %g4, [%sp + 2047 + 0x100]
+ stx %g5, [%sp + 2047 + 0x108]
+ stx %g6, [%sp + 2047 + 0x110]
+ stx %g7, [%sp + 2047 + 0x118]
+ wrpr %g0, 0x14, %pstate ! save normal globals
+ stx %g1, [%sp + 2047 + 0x120]
+ stx %g2, [%sp + 2047 + 0x128]
+ stx %g3, [%sp + 2047 + 0x130]
+ stx %g4, [%sp + 2047 + 0x138]
+ stx %g5, [%sp + 2047 + 0x140]
+ stx %g6, [%sp + 2047 + 0x148]
+ stx %g7, [%sp + 2047 + 0x150]
+ wrpr %g0, 0x414, %pstate ! save mmu globals
+ stx %g1, [%sp + 2047 + 0x158]
+ stx %g2, [%sp + 2047 + 0x160]
+ stx %g3, [%sp + 2047 + 0x168]
+ stx %g4, [%sp + 2047 + 0x170]
+ stx %g5, [%sp + 2047 + 0x178]
+ stx %g6, [%sp + 2047 + 0x180]
+ stx %g7, [%sp + 2047 + 0x188]
+ mov %g1, %l0 ! also save to locals, so we can handle
+ mov %g2, %l1 ! tlb faults later on, when accessing
+ mov %g3, %l3 ! the stack.
+ mov %g7, %l5
+ wrpr %l4, PSTATE_IE, %pstate ! turn off interrupts
+ call %l2
+ add %i0, 0x018, %o0 ! prom_args
+ wrpr %g0, 0x414, %pstate ! restore mmu globals
+ mov %l0, %g1
+ mov %l1, %g2
+ mov %l3, %g3
+ mov %l5, %g7
+ wrpr %g0, 0x14, %pstate ! restore normal globals
+ ldx [%sp + 2047 + 0x120], %g1
+ ldx [%sp + 2047 + 0x128], %g2
+ ldx [%sp + 2047 + 0x130], %g3
+ ldx [%sp + 2047 + 0x138], %g4
+ ldx [%sp + 2047 + 0x140], %g5
+ ldx [%sp + 2047 + 0x148], %g6
+ ldx [%sp + 2047 + 0x150], %g7
+ wrpr %g0, 0x814, %pstate ! restore interrupt globals
+ ldx [%sp + 2047 + 0x0e8], %g1
+ ldx [%sp + 2047 + 0x0f0], %g2
+ ldx [%sp + 2047 + 0x0f8], %g3
+ ldx [%sp + 2047 + 0x100], %g4
+ ldx [%sp + 2047 + 0x108], %g5
+ ldx [%sp + 2047 + 0x110], %g6
+ ldx [%sp + 2047 + 0x118], %g7
+ wrpr %g0, 0x15, %pstate ! restore alternate globals
+ ldx [%sp + 2047 + 0x0b0], %g1
+ ldx [%sp + 2047 + 0x0b8], %g2
+ ldx [%sp + 2047 + 0x0c0], %g3
+ ldx [%sp + 2047 + 0x0c8], %g4
+ ldx [%sp + 2047 + 0x0d0], %g5
+ ldx [%sp + 2047 + 0x0d8], %g6
+ ldx [%sp + 2047 + 0x0e0], %g7
+ wrpr %l4, 0, %pstate ! restore original pstate
+ ret
+ restore
+
+ .globl prom_cif_callback
+prom_cif_callback:
+ sethi %hi(p1275buf), %o1
+ or %o1, %lo(p1275buf), %o1
+ save %sp, -0x270, %sp
+ rdpr %pstate, %l4
+ wrpr %g0, 0x15, %pstate ! save PROM alternate globals
+ stx %g1, [%sp + 2047 + 0x0b0]
+ stx %g2, [%sp + 2047 + 0x0b8]
+ stx %g3, [%sp + 2047 + 0x0c0]
+ stx %g4, [%sp + 2047 + 0x0c8]
+ stx %g5, [%sp + 2047 + 0x0d0]
+ stx %g6, [%sp + 2047 + 0x0d8]
+ stx %g7, [%sp + 2047 + 0x0e0]
+ ! restore Linux alternate globals
+ ldx [%sp + 2047 + 0x190], %g1
+ ldx [%sp + 2047 + 0x198], %g2
+ ldx [%sp + 2047 + 0x1a0], %g3
+ ldx [%sp + 2047 + 0x1a8], %g4
+ ldx [%sp + 2047 + 0x1b0], %g5
+ ldx [%sp + 2047 + 0x1b8], %g6
+ ldx [%sp + 2047 + 0x1c0], %g7
+ wrpr %g0, 0x814, %pstate ! save PROM interrupt globals
+ stx %g1, [%sp + 2047 + 0x0e8]
+ stx %g2, [%sp + 2047 + 0x0f0]
+ stx %g3, [%sp + 2047 + 0x0f8]
+ stx %g4, [%sp + 2047 + 0x100]
+ stx %g5, [%sp + 2047 + 0x108]
+ stx %g6, [%sp + 2047 + 0x110]
+ stx %g7, [%sp + 2047 + 0x118]
+ ! restore Linux interrupt globals
+ ldx [%sp + 2047 + 0x1c8], %g1
+ ldx [%sp + 2047 + 0x1d0], %g2
+ ldx [%sp + 2047 + 0x1d8], %g3
+ ldx [%sp + 2047 + 0x1e0], %g4
+ ldx [%sp + 2047 + 0x1e8], %g5
+ ldx [%sp + 2047 + 0x1f0], %g6
+ ldx [%sp + 2047 + 0x1f8], %g7
+ wrpr %g0, 0x14, %pstate ! save PROM normal globals
+ stx %g1, [%sp + 2047 + 0x120]
+ stx %g2, [%sp + 2047 + 0x128]
+ stx %g3, [%sp + 2047 + 0x130]
+ stx %g4, [%sp + 2047 + 0x138]
+ stx %g5, [%sp + 2047 + 0x140]
+ stx %g6, [%sp + 2047 + 0x148]
+ stx %g7, [%sp + 2047 + 0x150]
+ ! restore Linux normal globals
+ ldx [%sp + 2047 + 0x200], %g1
+ ldx [%sp + 2047 + 0x208], %g2
+ ldx [%sp + 2047 + 0x210], %g3
+ ldx [%sp + 2047 + 0x218], %g4
+ ldx [%sp + 2047 + 0x220], %g5
+ ldx [%sp + 2047 + 0x228], %g6
+ ldx [%sp + 2047 + 0x230], %g7
+ wrpr %g0, 0x414, %pstate ! save PROM mmu globals
+ stx %g1, [%sp + 2047 + 0x158]
+ stx %g2, [%sp + 2047 + 0x160]
+ stx %g3, [%sp + 2047 + 0x168]
+ stx %g4, [%sp + 2047 + 0x170]
+ stx %g5, [%sp + 2047 + 0x178]
+ stx %g6, [%sp + 2047 + 0x180]
+ stx %g7, [%sp + 2047 + 0x188]
+ ! restore Linux mmu globals
+ ldx [%sp + 2047 + 0x238], %o0
+ ldx [%sp + 2047 + 0x240], %o1
+ ldx [%sp + 2047 + 0x248], %l2
+ ldx [%sp + 2047 + 0x250], %l3
+ ldx [%sp + 2047 + 0x258], %l5
+ ldx [%sp + 2047 + 0x260], %l6
+ ldx [%sp + 2047 + 0x268], %l7
+ ! switch to Linux tba
+ sethi %hi(sparc64_ttable_tl0), %l1
+ rdpr %tba, %l0 ! save PROM tba
+ mov %o0, %g1
+ mov %o1, %g2
+ mov %l2, %g3
+ mov %l3, %g4
+ mov %l5, %g5
+ mov %l6, %g6
+ mov %l7, %g7
+ wrpr %l1, %tba ! install Linux tba
+ wrpr %l4, 0, %pstate ! restore PSTATE
+ call prom_world
+ mov %g0, %o0
+ ldx [%i1 + 0x000], %l2
+ call %l2
+ mov %i0, %o0
+ mov %o0, %l1
+ call prom_world
+ or %g0, 1, %o0
+ wrpr %g0, 0x14, %pstate ! interrupts off
+ ! restore PROM mmu globals
+ ldx [%sp + 2047 + 0x158], %o0
+ ldx [%sp + 2047 + 0x160], %o1
+ ldx [%sp + 2047 + 0x168], %l2
+ ldx [%sp + 2047 + 0x170], %l3
+ ldx [%sp + 2047 + 0x178], %l5
+ ldx [%sp + 2047 + 0x180], %l6
+ ldx [%sp + 2047 + 0x188], %l7
+ wrpr %g0, 0x414, %pstate ! restore PROM mmu globals
+ mov %o0, %g1
+ mov %o1, %g2
+ mov %l2, %g3
+ mov %l3, %g4
+ mov %l5, %g5
+ mov %l6, %g6
+ mov %l7, %g7
+ wrpr %l0, %tba ! restore PROM tba
+ wrpr %g0, 0x14, %pstate ! restore PROM normal globals
+ ldx [%sp + 2047 + 0x120], %g1
+ ldx [%sp + 2047 + 0x128], %g2
+ ldx [%sp + 2047 + 0x130], %g3
+ ldx [%sp + 2047 + 0x138], %g4
+ ldx [%sp + 2047 + 0x140], %g5
+ ldx [%sp + 2047 + 0x148], %g6
+ ldx [%sp + 2047 + 0x150], %g7
+ wrpr %g0, 0x814, %pstate ! restore PROM interrupt globals
+ ldx [%sp + 2047 + 0x0e8], %g1
+ ldx [%sp + 2047 + 0x0f0], %g2
+ ldx [%sp + 2047 + 0x0f8], %g3
+ ldx [%sp + 2047 + 0x100], %g4
+ ldx [%sp + 2047 + 0x108], %g5
+ ldx [%sp + 2047 + 0x110], %g6
+ ldx [%sp + 2047 + 0x118], %g7
+ wrpr %g0, 0x15, %pstate ! restore PROM alternate globals
+ ldx [%sp + 2047 + 0x0b0], %g1
+ ldx [%sp + 2047 + 0x0b8], %g2
+ ldx [%sp + 2047 + 0x0c0], %g3
+ ldx [%sp + 2047 + 0x0c8], %g4
+ ldx [%sp + 2047 + 0x0d0], %g5
+ ldx [%sp + 2047 + 0x0d8], %g6
+ ldx [%sp + 2047 + 0x0e0], %g7
+ wrpr %l4, 0, %pstate
+ ret
+ restore %l1, 0, %o0
+
diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c
new file mode 100644
index 00000000000..028a53fcb1e
--- /dev/null
+++ b/arch/sparc64/prom/console.c
@@ -0,0 +1,146 @@
+/* $Id: console.c,v 1.9 1997/10/29 07:41:43 ecd Exp $
+ * console.c: Routines that deal with sending and receiving IO
+ * to/from the current console device using the PROM.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <linux/string.h>
+
+extern int prom_stdin, prom_stdout;
+
+/* Non blocking get character from console input device, returns -1
+ * if no input was taken. This can be used for polling.
+ */
+__inline__ int
+prom_nbgetchar(void)
+{
+ char inc;
+
+ if (p1275_cmd("read", P1275_ARG(1,P1275_ARG_OUT_BUF)|
+ P1275_INOUT(3,1),
+ prom_stdin, &inc, P1275_SIZE(1)) == 1)
+ return inc;
+ else
+ return -1;
+}
+
+/* Non blocking put character to console device, returns -1 if
+ * unsuccessful.
+ */
+__inline__ int
+prom_nbputchar(char c)
+{
+ char outc;
+
+ outc = c;
+ if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
+ P1275_INOUT(3,1),
+ prom_stdout, &outc, P1275_SIZE(1)) == 1)
+ return 0;
+ else
+ return -1;
+}
+
+/* Blocking version of get character routine above. */
+char
+prom_getchar(void)
+{
+ int character;
+ while((character = prom_nbgetchar()) == -1) ;
+ return (char) character;
+}
+
+/* Blocking version of put character routine above. */
+void
+prom_putchar(char c)
+{
+ prom_nbputchar(c);
+ return;
+}
+
+void
+prom_puts(char *s, int len)
+{
+ p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
+ P1275_INOUT(3,1),
+ prom_stdout, s, P1275_SIZE(len));
+}
+
+/* Query for input device type */
+enum prom_input_device
+prom_query_input_device(void)
+{
+ int st_p;
+ char propb[64];
+
+ st_p = prom_inst2pkg(prom_stdin);
+ if(prom_node_has_property(st_p, "keyboard"))
+ return PROMDEV_IKBD;
+ prom_getproperty(st_p, "device_type", propb, sizeof(propb));
+ if(strncmp(propb, "serial", 6))
+ return PROMDEV_I_UNK;
+ /* FIXME: Is there any better way how to find out? */
+ memset(propb, 0, sizeof(propb));
+ st_p = prom_finddevice ("/options");
+ prom_getproperty(st_p, "input-device", propb, sizeof(propb));
+
+ /*
+ * If we get here with propb == 'keyboard', we are on ttya, as
+ * the PROM defaulted to this due to 'no input device'.
+ */
+ if (!strncmp(propb, "keyboard", 8))
+ return PROMDEV_ITTYA;
+
+ if (strncmp (propb, "tty", 3) || !propb[3])
+ return PROMDEV_I_UNK;
+ switch (propb[3]) {
+ case 'a': return PROMDEV_ITTYA;
+ case 'b': return PROMDEV_ITTYB;
+ default: return PROMDEV_I_UNK;
+ }
+}
+
+/* Query for output device type */
+
+enum prom_output_device
+prom_query_output_device(void)
+{
+ int st_p;
+ char propb[64];
+ int propl;
+
+ st_p = prom_inst2pkg(prom_stdout);
+ propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
+ if (propl >= 0 && propl == sizeof("display") &&
+ strncmp("display", propb, sizeof("display")) == 0)
+ return PROMDEV_OSCREEN;
+ if(strncmp("serial", propb, 6))
+ return PROMDEV_O_UNK;
+ /* FIXME: Is there any better way how to find out? */
+ memset(propb, 0, sizeof(propb));
+ st_p = prom_finddevice ("/options");
+ prom_getproperty(st_p, "output-device", propb, sizeof(propb));
+
+ /*
+ * If we get here with propb == 'screen', we are on ttya, as
+ * the PROM defaulted to this due to 'no input device'.
+ */
+ if (!strncmp(propb, "screen", 6))
+ return PROMDEV_OTTYA;
+
+ if (strncmp (propb, "tty", 3) || !propb[3])
+ return PROMDEV_O_UNK;
+ switch (propb[3]) {
+ case 'a': return PROMDEV_OTTYA;
+ case 'b': return PROMDEV_OTTYB;
+ default: return PROMDEV_O_UNK;
+ }
+}
diff --git a/arch/sparc64/prom/devops.c b/arch/sparc64/prom/devops.c
new file mode 100644
index 00000000000..2c99b21b698
--- /dev/null
+++ b/arch/sparc64/prom/devops.c
@@ -0,0 +1,41 @@
+/* $Id: devops.c,v 1.3 1997/10/29 07:43:28 ecd Exp $
+ * devops.c: Device operations using the PROM.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Open the device described by the string 'dstr'. Returns the handle
+ * to that device used for subsequent operations on that device.
+ * Returns 0 on failure.
+ */
+int
+prom_devopen(char *dstr)
+{
+ return p1275_cmd ("open", P1275_ARG(0,P1275_ARG_IN_STRING)|
+ P1275_INOUT(1,1),
+ dstr);
+}
+
+/* Close the device described by device handle 'dhandle'. */
+int
+prom_devclose(int dhandle)
+{
+ p1275_cmd ("close", P1275_INOUT(1,0), dhandle);
+ return 0;
+}
+
+/* Seek to specified location described by 'seekhi' and 'seeklo'
+ * for device 'dhandle'.
+ */
+void
+prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
+{
+ p1275_cmd ("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo);
+}
diff --git a/arch/sparc64/prom/init.c b/arch/sparc64/prom/init.c
new file mode 100644
index 00000000000..817faae058c
--- /dev/null
+++ b/arch/sparc64/prom/init.c
@@ -0,0 +1,101 @@
+/* $Id: init.c,v 1.10 1999/09/21 14:35:59 davem Exp $
+ * init.c: Initialize internal variables used by the PROM
+ * library functions.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+enum prom_major_version prom_vers;
+unsigned int prom_rev, prom_prev;
+
+/* The root node of the prom device tree. */
+int prom_root_node;
+int prom_stdin, prom_stdout;
+int prom_chosen_node;
+
+/* You must call prom_init() before you attempt to use any of the
+ * routines in the prom library. It returns 0 on success, 1 on
+ * failure. It gets passed the pointer to the PROM vector.
+ */
+
+extern void prom_meminit(void);
+extern void prom_cif_init(void *, void *);
+
+void __init prom_init(void *cif_handler, void *cif_stack)
+{
+ char buffer[80], *p;
+ int ints[3];
+ int node;
+ int i = 0;
+ int bufadjust;
+
+ prom_vers = PROM_P1275;
+
+ prom_cif_init(cif_handler, cif_stack);
+
+ prom_root_node = prom_getsibling(0);
+ if((prom_root_node == 0) || (prom_root_node == -1))
+ prom_halt();
+
+ prom_chosen_node = prom_finddevice("/chosen");
+ if (!prom_chosen_node || prom_chosen_node == -1)
+ prom_halt();
+
+ prom_stdin = prom_getint (prom_chosen_node, "stdin");
+ prom_stdout = prom_getint (prom_chosen_node, "stdout");
+
+ node = prom_finddevice("/openprom");
+ if (!node || node == -1)
+ prom_halt();
+
+ prom_getstring (node, "version", buffer, sizeof (buffer));
+
+ prom_printf ("\n");
+
+ if (strncmp (buffer, "OBP ", 4))
+ goto strange_version;
+
+ /*
+ * Version field is expected to be 'OBP xx.yy.zz date...'
+ * However, Sun can't stick to this format very well, so
+ * we need to check for 'OBP xx.yy.zz date...' and adjust
+ * accordingly. -spot
+ */
+
+ if (strncmp (buffer, "OBP ", 5))
+ bufadjust = 4;
+ else
+ bufadjust = 5;
+
+ p = buffer + bufadjust;
+ while (p && isdigit(*p) && i < 3) {
+ ints[i++] = simple_strtoul(p, NULL, 0);
+ if ((p = strchr(p, '.')) != NULL)
+ p++;
+ }
+ if (i != 3)
+ goto strange_version;
+
+ prom_rev = ints[1];
+ prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2];
+
+ printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + bufadjust);
+
+ prom_meminit();
+
+ /* Initialization successful. */
+ return;
+
+strange_version:
+ prom_printf ("Strange OBP version `%s'.\n", buffer);
+ prom_halt ();
+}
diff --git a/arch/sparc64/prom/map.S b/arch/sparc64/prom/map.S
new file mode 100644
index 00000000000..21b3f9c99ea
--- /dev/null
+++ b/arch/sparc64/prom/map.S
@@ -0,0 +1,72 @@
+/* $Id: map.S,v 1.2 1999/11/19 05:53:02 davem Exp $
+ * map.S: Tricky coding required to fixup the kernel OBP maps
+ * properly.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+ .text
+ .align 8192
+ .globl prom_boot_page
+prom_boot_page:
+call_method:
+ .asciz "call-method"
+ .align 8
+map:
+ .asciz "map"
+ .align 8
+
+ /* When we are invoked, our caller has remapped us to
+ * page zero, therefore we must use PC relative addressing
+ * for everything after we begin performing the unmap/map
+ * calls.
+ */
+ .globl prom_remap
+prom_remap: /* %o0 = physpage, %o1 = virtpage, %o2 = mmu_ihandle */
+ rd %pc, %g1
+ srl %o2, 0, %o2 ! kill sign extension
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x10], %g3 ! prom_cif_stack
+ save %g3, -(192 + 128), %sp
+ ldx [%g2 + 0x08], %l0 ! prom_cif_handler
+ mov %g6, %i3
+ mov %g4, %i4
+ mov %g5, %i5
+ flushw
+
+ sethi %hi(prom_remap - call_method), %g7
+ or %g7, %lo(prom_remap - call_method), %g7
+ sub %g1, %g7, %l2 ! call-method string
+ sethi %hi(prom_remap - map), %g7
+ or %g7, %lo(prom_remap - map), %g7
+ sub %g1, %g7, %l4 ! map string
+
+ /* OK, map the 4MB region we really live at. */
+ stx %l2, [%sp + 2047 + 128 + 0x00] ! call-method
+ mov 7, %l5
+ stx %l5, [%sp + 2047 + 128 + 0x08] ! num_args
+ mov 1, %l5
+ stx %l5, [%sp + 2047 + 128 + 0x10] ! num_rets
+ stx %l4, [%sp + 2047 + 128 + 0x18] ! map
+ stx %i2, [%sp + 2047 + 128 + 0x20] ! mmu_ihandle
+ mov -1, %l5
+ stx %l5, [%sp + 2047 + 128 + 0x28] ! mode == default
+ sethi %hi(4 * 1024 * 1024), %l5
+ stx %l5, [%sp + 2047 + 128 + 0x30] ! size
+ stx %i1, [%sp + 2047 + 128 + 0x38] ! vaddr
+ stx %g0, [%sp + 2047 + 128 + 0x40] ! filler
+ stx %i0, [%sp + 2047 + 128 + 0x48] ! paddr
+ call %l0
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ /* Restore hard-coded globals. */
+ mov %i3, %g6
+ mov %i4, %g4
+ mov %i5, %g5
+
+ /* Wheee.... we are done. */
+ ret
+ restore
+
+ .align 8192
diff --git a/arch/sparc64/prom/memory.c b/arch/sparc64/prom/memory.c
new file mode 100644
index 00000000000..f4a8143e052
--- /dev/null
+++ b/arch/sparc64/prom/memory.c
@@ -0,0 +1,152 @@
+/* $Id: memory.c,v 1.5 1999/08/31 06:55:04 davem Exp $
+ * memory.c: Prom routine for acquiring various bits of information
+ * about RAM on the machine, both virtual and physical.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* This routine, for consistency, returns the ram parameters in the
+ * V0 prom memory descriptor format. I choose this format because I
+ * think it was the easiest to work with. I feel the religious
+ * arguments now... ;) Also, I return the linked lists sorted to
+ * prevent paging_init() upset stomach as I have not yet written
+ * the pepto-bismol kernel module yet.
+ */
+
+struct linux_prom64_registers prom_reg_memlist[64];
+struct linux_prom64_registers prom_reg_tmp[64];
+
+struct linux_mlist_p1275 prom_phys_total[64];
+struct linux_mlist_p1275 prom_prom_taken[64];
+struct linux_mlist_p1275 prom_phys_avail[64];
+
+struct linux_mlist_p1275 *prom_ptot_ptr = prom_phys_total;
+struct linux_mlist_p1275 *prom_ptak_ptr = prom_prom_taken;
+struct linux_mlist_p1275 *prom_pavl_ptr = prom_phys_avail;
+
+struct linux_mem_p1275 prom_memlist;
+
+
+/* Internal Prom library routine to sort a linux_mlist_p1275 memory
+ * list. Used below in initialization.
+ */
+static void __init
+prom_sortmemlist(struct linux_mlist_p1275 *thislist)
+{
+ int swapi = 0;
+ int i, mitr;
+ unsigned long tmpaddr, tmpsize;
+ unsigned long lowest;
+
+ for(i=0; thislist[i].theres_more; i++) {
+ lowest = thislist[i].start_adr;
+ for(mitr = i+1; thislist[mitr-1].theres_more; mitr++)
+ if(thislist[mitr].start_adr < lowest) {
+ lowest = thislist[mitr].start_adr;
+ swapi = mitr;
+ }
+ if(lowest == thislist[i].start_adr) continue;
+ tmpaddr = thislist[swapi].start_adr;
+ tmpsize = thislist[swapi].num_bytes;
+ for(mitr = swapi; mitr > i; mitr--) {
+ thislist[mitr].start_adr = thislist[mitr-1].start_adr;
+ thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;
+ }
+ thislist[i].start_adr = tmpaddr;
+ thislist[i].num_bytes = tmpsize;
+ }
+}
+
+/* Initialize the memory lists based upon the prom version. */
+void __init prom_meminit(void)
+{
+ int node = 0;
+ unsigned int iter, num_regs;
+
+ node = prom_finddevice("/memory");
+ num_regs = prom_getproperty(node, "available",
+ (char *) prom_reg_memlist,
+ sizeof(prom_reg_memlist));
+ num_regs = (num_regs/sizeof(struct linux_prom64_registers));
+ for(iter=0; iter<num_regs; iter++) {
+ prom_phys_avail[iter].start_adr =
+ prom_reg_memlist[iter].phys_addr;
+ prom_phys_avail[iter].num_bytes =
+ prom_reg_memlist[iter].reg_size;
+ prom_phys_avail[iter].theres_more =
+ &prom_phys_avail[iter+1];
+ }
+ prom_phys_avail[iter-1].theres_more = NULL;
+
+ num_regs = prom_getproperty(node, "reg",
+ (char *) prom_reg_memlist,
+ sizeof(prom_reg_memlist));
+ num_regs = (num_regs/sizeof(struct linux_prom64_registers));
+ for(iter=0; iter<num_regs; iter++) {
+ prom_phys_total[iter].start_adr =
+ prom_reg_memlist[iter].phys_addr;
+ prom_phys_total[iter].num_bytes =
+ prom_reg_memlist[iter].reg_size;
+ prom_phys_total[iter].theres_more =
+ &prom_phys_total[iter+1];
+ }
+ prom_phys_total[iter-1].theres_more = NULL;
+
+ node = prom_finddevice("/virtual-memory");
+ num_regs = prom_getproperty(node, "available",
+ (char *) prom_reg_memlist,
+ sizeof(prom_reg_memlist));
+ num_regs = (num_regs/sizeof(struct linux_prom64_registers));
+
+ /* Convert available virtual areas to taken virtual
+ * areas. First sort, then convert.
+ */
+ for(iter=0; iter<num_regs; iter++) {
+ prom_prom_taken[iter].start_adr =
+ prom_reg_memlist[iter].phys_addr;
+ prom_prom_taken[iter].num_bytes =
+ prom_reg_memlist[iter].reg_size;
+ prom_prom_taken[iter].theres_more =
+ &prom_prom_taken[iter+1];
+ }
+ prom_prom_taken[iter-1].theres_more = NULL;
+
+ prom_sortmemlist(prom_prom_taken);
+
+ /* Finally, convert. */
+ for(iter=0; iter<num_regs; iter++) {
+ prom_prom_taken[iter].start_adr =
+ prom_prom_taken[iter].start_adr +
+ prom_prom_taken[iter].num_bytes;
+ prom_prom_taken[iter].num_bytes =
+ prom_prom_taken[iter+1].start_adr -
+ prom_prom_taken[iter].start_adr;
+ }
+ prom_prom_taken[iter-1].num_bytes =
+ -1UL - prom_prom_taken[iter-1].start_adr;
+
+ /* Sort the other two lists. */
+ prom_sortmemlist(prom_phys_total);
+ prom_sortmemlist(prom_phys_avail);
+
+ /* Link all the lists into the top-level descriptor. */
+ prom_memlist.p1275_totphys=&prom_ptot_ptr;
+ prom_memlist.p1275_prommap=&prom_ptak_ptr;
+ prom_memlist.p1275_available=&prom_pavl_ptr;
+}
+
+/* This returns a pointer to our libraries internal p1275 format
+ * memory descriptor.
+ */
+struct linux_mem_p1275 *
+prom_meminfo(void)
+{
+ return &prom_memlist;
+}
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
new file mode 100644
index 00000000000..19c44e97e9e
--- /dev/null
+++ b/arch/sparc64/prom/misc.c
@@ -0,0 +1,339 @@
+/* $Id: misc.c,v 1.20 2001/09/21 03:17:07 kanoj Exp $
+ * misc.c: Miscellaneous prom functions that don't belong
+ * anywhere else.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+
+/* Reset and reboot the machine with the command 'bcommand'. */
+void prom_reboot(char *bcommand)
+{
+ p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) |
+ P1275_INOUT(1, 0), bcommand);
+}
+
+/* Forth evaluate the expression contained in 'fstring'. */
+void prom_feval(char *fstring)
+{
+ if (!fstring || fstring[0] == 0)
+ return;
+ p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) |
+ P1275_INOUT(1, 1), fstring);
+}
+
+/* We want to do this more nicely some day. */
+extern void (*prom_palette)(int);
+
+#ifdef CONFIG_SMP
+extern void smp_capture(void);
+extern void smp_release(void);
+#endif
+
+/* Drop into the prom, with the chance to continue with the 'go'
+ * prom command.
+ */
+void prom_cmdline(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (!serial_console && prom_palette)
+ prom_palette(1);
+
+#ifdef CONFIG_SMP
+ smp_capture();
+#endif
+
+ p1275_cmd("enter", P1275_INOUT(0, 0));
+
+#ifdef CONFIG_SMP
+ smp_release();
+#endif
+
+ if (!serial_console && prom_palette)
+ prom_palette(0);
+
+ local_irq_restore(flags);
+}
+
+#ifdef CONFIG_SMP
+extern void smp_promstop_others(void);
+#endif
+
+/* Drop into the prom, but completely terminate the program.
+ * No chance of continuing.
+ */
+void prom_halt(void)
+{
+#ifdef CONFIG_SMP
+ smp_promstop_others();
+ udelay(8000);
+#endif
+again:
+ p1275_cmd("exit", P1275_INOUT(0, 0));
+ goto again; /* PROM is out to get me -DaveM */
+}
+
+void prom_halt_power_off(void)
+{
+#ifdef CONFIG_SMP
+ smp_promstop_others();
+ udelay(8000);
+#endif
+ p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0));
+
+ /* if nothing else helps, we just halt */
+ prom_halt();
+}
+
+/* Set prom sync handler to call function 'funcp'. */
+void prom_setcallback(callback_func_t funcp)
+{
+ if (!funcp)
+ return;
+ p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) |
+ P1275_INOUT(1, 1), funcp);
+}
+
+/* Get the idprom and stuff it into buffer 'idbuf'. Returns the
+ * format type. 'num_bytes' is the number of bytes that your idbuf
+ * has space for. Returns 0xff on error.
+ */
+unsigned char prom_get_idprom(char *idbuf, int num_bytes)
+{
+ int len;
+
+ len = prom_getproplen(prom_root_node, "idprom");
+ if ((len >num_bytes) || (len == -1))
+ return 0xff;
+ if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
+ return idbuf[0];
+
+ return 0xff;
+}
+
+/* Get the major prom version number. */
+int prom_version(void)
+{
+ return PROM_P1275;
+}
+
+/* Get the prom plugin-revision. */
+int prom_getrev(void)
+{
+ return prom_rev;
+}
+
+/* Get the prom firmware print revision. */
+int prom_getprev(void)
+{
+ return prom_prev;
+}
+
+/* Install Linux trap table so PROM uses that instead of its own. */
+void prom_set_trap_table(unsigned long tba)
+{
+ p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
+}
+
+int mmu_ihandle_cache = 0;
+
+int prom_get_mmu_ihandle(void)
+{
+ int node, ret;
+
+ if (mmu_ihandle_cache != 0)
+ return mmu_ihandle_cache;
+
+ node = prom_finddevice("/chosen");
+ ret = prom_getint(node, "mmu");
+ if (ret == -1 || ret == 0)
+ mmu_ihandle_cache = -1;
+ else
+ mmu_ihandle_cache = ret;
+
+ return ret;
+}
+
+static int prom_get_memory_ihandle(void)
+{
+ static int memory_ihandle_cache;
+ int node, ret;
+
+ if (memory_ihandle_cache != 0)
+ return memory_ihandle_cache;
+
+ node = prom_finddevice("/chosen");
+ ret = prom_getint(node, "memory");
+ if (ret == -1 || ret == 0)
+ memory_ihandle_cache = -1;
+ else
+ memory_ihandle_cache = ret;
+
+ return ret;
+}
+
+/* Load explicit I/D TLB entries. */
+long prom_itlb_load(unsigned long index,
+ unsigned long tte_data,
+ unsigned long vaddr)
+{
+ return p1275_cmd("call-method",
+ (P1275_ARG(0, P1275_ARG_IN_STRING) |
+ P1275_ARG(2, P1275_ARG_IN_64B) |
+ P1275_ARG(3, P1275_ARG_IN_64B) |
+ P1275_INOUT(5, 1)),
+ "SUNW,itlb-load",
+ prom_get_mmu_ihandle(),
+ /* And then our actual args are pushed backwards. */
+ vaddr,
+ tte_data,
+ index);
+}
+
+long prom_dtlb_load(unsigned long index,
+ unsigned long tte_data,
+ unsigned long vaddr)
+{
+ return p1275_cmd("call-method",
+ (P1275_ARG(0, P1275_ARG_IN_STRING) |
+ P1275_ARG(2, P1275_ARG_IN_64B) |
+ P1275_ARG(3, P1275_ARG_IN_64B) |
+ P1275_INOUT(5, 1)),
+ "SUNW,dtlb-load",
+ prom_get_mmu_ihandle(),
+ /* And then our actual args are pushed backwards. */
+ vaddr,
+ tte_data,
+ index);
+}
+
+int prom_map(int mode, unsigned long size,
+ unsigned long vaddr, unsigned long paddr)
+{
+ int ret = p1275_cmd("call-method",
+ (P1275_ARG(0, P1275_ARG_IN_STRING) |
+ P1275_ARG(3, P1275_ARG_IN_64B) |
+ P1275_ARG(4, P1275_ARG_IN_64B) |
+ P1275_ARG(6, P1275_ARG_IN_64B) |
+ P1275_INOUT(7, 1)),
+ "map",
+ prom_get_mmu_ihandle(),
+ mode,
+ size,
+ vaddr,
+ 0,
+ paddr);
+
+ if (ret == 0)
+ ret = -1;
+ return ret;
+}
+
+void p