v4.19.13 snapshot.
diff --git a/arch/mips/fw/arc/Makefile b/arch/mips/fw/arc/Makefile
new file mode 100644
index 0000000..31dd730
--- /dev/null
+++ b/arch/mips/fw/arc/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the ARC prom monitor library routines under Linux.
+#
+
+lib-y				+= cmdline.o env.o file.o identify.o init.o \
+				   misc.o salone.o time.o tree.o
+
+lib-$(CONFIG_ARC_MEMORY)	+= memory.o
+lib-$(CONFIG_ARC_CONSOLE)	+= arc_con.o
+lib-$(CONFIG_ARC_PROMLIB)	+= promlib.o
diff --git a/arch/mips/fw/arc/arc_con.c b/arch/mips/fw/arc/arc_con.c
new file mode 100644
index 0000000..365e391
--- /dev/null
+++ b/arch/mips/fw/arc/arc_con.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wrap-around code for a console using the
+ * ARC io-routines.
+ *
+ * Copyright (c) 1998 Harald Koerfgen
+ * Copyright (c) 2001 Ralf Baechle
+ * Copyright (c) 2002 Thiemo Seufer
+ */
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/fs.h>
+#include <asm/setup.h>
+#include <asm/sgialib.h>
+
+static void prom_console_write(struct console *co, const char *s,
+			       unsigned count)
+{
+	/* Do each character */
+	while (count--) {
+		if (*s == '\n')
+			prom_putchar('\r');
+		prom_putchar(*s++);
+	}
+}
+
+static int prom_console_setup(struct console *co, char *options)
+{
+	return !(prom_flags & PROM_FLAG_USE_AS_CONSOLE);
+}
+
+static struct console arc_cons = {
+	.name		= "arc",
+	.write		= prom_console_write,
+	.setup		= prom_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+};
+
+/*
+ *    Register console.
+ */
+
+static int __init arc_console_init(void)
+{
+	register_console(&arc_cons);
+
+	return 0;
+}
+console_initcall(arc_console_init);
diff --git a/arch/mips/fw/arc/cmdline.c b/arch/mips/fw/arc/cmdline.c
new file mode 100644
index 0000000..c0122a1
--- /dev/null
+++ b/arch/mips/fw/arc/cmdline.c
@@ -0,0 +1,104 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * cmdline.c: Kernel command line creation using ARCS argc/argv.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
+ */
+#include <linux/bug.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/sgialib.h>
+#include <asm/bootinfo.h>
+
+#undef DEBUG_CMDLINE
+
+static char *ignored[] = {
+	"ConsoleIn=",
+	"ConsoleOut=",
+	"SystemPartition=",
+	"OSLoader=",
+	"OSLoadPartition=",
+	"OSLoadFilename=",
+	"OSLoadOptions="
+};
+
+static char *used_arc[][2] = {
+	{ "OSLoadPartition=", "root=" },
+	{ "OSLoadOptions=", "" }
+};
+
+static char * __init move_firmware_args(char* cp)
+{
+	char *s;
+	int actr, i;
+
+	actr = 1; /* Always ignore argv[0] */
+
+	while (actr < prom_argc) {
+		for(i = 0; i < ARRAY_SIZE(used_arc); i++) {
+			int len = strlen(used_arc[i][0]);
+
+			if (!strncmp(prom_argv(actr), used_arc[i][0], len)) {
+			/* Ok, we want it. First append the replacement... */
+				strcat(cp, used_arc[i][1]);
+				cp += strlen(used_arc[i][1]);
+				/* ... and now the argument */
+				s = strchr(prom_argv(actr), '=');
+				if (s) {
+					s++;
+					strcpy(cp, s);
+					cp += strlen(s);
+				}
+				*cp++ = ' ';
+				break;
+			}
+		}
+		actr++;
+	}
+
+	return cp;
+}
+
+void __init prom_init_cmdline(void)
+{
+	char *cp;
+	int actr, i;
+
+	actr = 1; /* Always ignore argv[0] */
+
+	cp = arcs_cmdline;
+	/*
+	 * Move ARC variables to the beginning to make sure they can be
+	 * overridden by later arguments.
+	 */
+	cp = move_firmware_args(cp);
+
+	while (actr < prom_argc) {
+		for (i = 0; i < ARRAY_SIZE(ignored); i++) {
+			int len = strlen(ignored[i]);
+
+			if (!strncmp(prom_argv(actr), ignored[i], len))
+				goto pic_cont;
+		}
+		/* Ok, we want it. */
+		strcpy(cp, prom_argv(actr));
+		cp += strlen(prom_argv(actr));
+		*cp++ = ' ';
+
+	pic_cont:
+		actr++;
+	}
+
+	if (cp != arcs_cmdline)		/* get rid of trailing space */
+		--cp;
+	*cp = '\0';
+
+#ifdef DEBUG_CMDLINE
+	printk(KERN_DEBUG "prom cmdline: %s\n", arcs_cmdline);
+#endif
+}
diff --git a/arch/mips/fw/arc/env.c b/arch/mips/fw/arc/env.c
new file mode 100644
index 0000000..1118a26
--- /dev/null
+++ b/arch/mips/fw/arc/env.c
@@ -0,0 +1,27 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * env.c: ARCS environment variable routines.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/fw/arc/types.h>
+#include <asm/sgialib.h>
+
+PCHAR __init
+ArcGetEnvironmentVariable(CHAR *name)
+{
+	return (CHAR *) ARC_CALL1(get_evar, name);
+}
+
+LONG __init
+ArcSetEnvironmentVariable(PCHAR name, PCHAR value)
+{
+	return ARC_CALL2(set_evar, name, value);
+}
diff --git a/arch/mips/fw/arc/file.c b/arch/mips/fw/arc/file.c
new file mode 100644
index 0000000..49fd3ff
--- /dev/null
+++ b/arch/mips/fw/arc/file.c
@@ -0,0 +1,74 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * ARC firmware interface.
+ *
+ * Copyright (C) 1994, 1995, 1996, 1999 Ralf Baechle
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ */
+
+#include <asm/fw/arc/types.h>
+#include <asm/sgialib.h>
+
+LONG
+ArcGetDirectoryEntry(ULONG FileID, struct linux_vdirent *Buffer,
+		     ULONG N, ULONG *Count)
+{
+	return ARC_CALL4(get_vdirent, FileID, Buffer, N, Count);
+}
+
+LONG
+ArcOpen(CHAR *Path, enum linux_omode OpenMode, ULONG *FileID)
+{
+	return ARC_CALL3(open, Path, OpenMode, FileID);
+}
+
+LONG
+ArcClose(ULONG FileID)
+{
+	return ARC_CALL1(close, FileID);
+}
+
+LONG
+ArcRead(ULONG FileID, VOID *Buffer, ULONG N, ULONG *Count)
+{
+	return ARC_CALL4(read, FileID, Buffer, N, Count);
+}
+
+LONG
+ArcGetReadStatus(ULONG FileID)
+{
+	return ARC_CALL1(get_rstatus, FileID);
+}
+
+LONG
+ArcWrite(ULONG FileID, PVOID Buffer, ULONG N, PULONG Count)
+{
+	return ARC_CALL4(write, FileID, Buffer, N, Count);
+}
+
+LONG
+ArcSeek(ULONG FileID, struct linux_bigint *Position, enum linux_seekmode SeekMode)
+{
+	return ARC_CALL3(seek, FileID, Position, SeekMode);
+}
+
+LONG
+ArcMount(char *name, enum linux_mountops op)
+{
+	return ARC_CALL2(mount, name, op);
+}
+
+LONG
+ArcGetFileInformation(ULONG FileID, struct linux_finfo *Information)
+{
+	return ARC_CALL2(get_finfo, FileID, Information);
+}
+
+LONG ArcSetFileInformation(ULONG FileID, ULONG AttributeFlags,
+			   ULONG AttributeMask)
+{
+	return ARC_CALL3(set_finfo, FileID, AttributeFlags, AttributeMask);
+}
diff --git a/arch/mips/fw/arc/identify.c b/arch/mips/fw/arc/identify.c
new file mode 100644
index 0000000..f90266c
--- /dev/null
+++ b/arch/mips/fw/arc/identify.c
@@ -0,0 +1,116 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * identify.c: identify machine by looking up system identifier
+ *
+ * Copyright (C) 1998 Thomas Bogendoerfer
+ *
+ * This code is based on arch/mips/sgi/kernel/system.c, which is
+ *
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
+ */
+#include <linux/bug.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/sgialib.h>
+#include <asm/bootinfo.h>
+
+struct smatch {
+	char *arcname;
+	char *liname;
+	int flags;
+};
+
+static struct smatch mach_table[] = {
+	{
+		.arcname	= "SGI-IP22",
+		.liname		= "SGI Indy",
+		.flags		= PROM_FLAG_ARCS,
+	}, {
+		.arcname	= "SGI-IP27",
+		.liname		= "SGI Origin",
+		.flags		= PROM_FLAG_ARCS,
+	}, {
+		.arcname	= "SGI-IP28",
+		.liname		= "SGI IP28",
+		.flags		= PROM_FLAG_ARCS,
+	}, {
+		.arcname	= "SGI-IP30",
+		.liname		= "SGI Octane",
+		.flags		= PROM_FLAG_ARCS,
+	}, {
+		.arcname	= "SGI-IP32",
+		.liname		= "SGI O2",
+		.flags		= PROM_FLAG_ARCS,
+	}, {
+		.arcname	= "Microsoft-Jazz",
+		.liname		= "Jazz MIPS_Magnum_4000",
+		.flags		= 0,
+	}, {
+		.arcname	= "PICA-61",
+		.liname		= "Jazz Acer_PICA_61",
+		.flags		= 0,
+	}, {
+		.arcname	= "RM200PCI",
+		.liname		= "SNI RM200_PCI",
+		.flags		= PROM_FLAG_DONT_FREE_TEMP,
+	}, {
+		.arcname	= "RM200PCI-R5K",
+		.liname		= "SNI RM200_PCI-R5K",
+		.flags		= PROM_FLAG_DONT_FREE_TEMP,
+	}
+};
+
+int prom_flags;
+
+static struct smatch * __init string_to_mach(const char *s)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mach_table); i++) {
+		if (!strcmp(s, mach_table[i].arcname))
+			return &mach_table[i];
+	}
+
+	panic("Yeee, could not determine architecture type <%s>", s);
+}
+
+char *system_type;
+
+const char *get_system_type(void)
+{
+	return system_type;
+}
+
+void __init prom_identify_arch(void)
+{
+	pcomponent *p;
+	struct smatch *mach;
+	const char *iname;
+
+	/*
+	 * The root component tells us what machine architecture we have here.
+	 */
+	p = ArcGetChild(PROM_NULL_COMPONENT);
+	if (p == NULL) {
+#ifdef CONFIG_SGI_IP27
+		/* IP27 PROM misbehaves, seems to not implement ARC
+		   GetChild().	So we just assume it's an IP27.	 */
+		iname = "SGI-IP27";
+#else
+		iname = "Unknown";
+#endif
+	} else
+		iname = (char *) (long) p->iname;
+
+	printk("ARCH: %s\n", iname);
+	mach = string_to_mach(iname);
+	system_type = mach->liname;
+
+	prom_flags = mach->flags;
+}
diff --git a/arch/mips/fw/arc/init.c b/arch/mips/fw/arc/init.c
new file mode 100644
index 0000000..0085559
--- /dev/null
+++ b/arch/mips/fw/arc/init.c
@@ -0,0 +1,59 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * PROM library initialisation code.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <asm/bootinfo.h>
+#include <asm/sgialib.h>
+#include <asm/smp-ops.h>
+
+#undef DEBUG_PROM_INIT
+
+/* Master romvec interface. */
+struct linux_romvec *romvec;
+int prom_argc;
+LONG *_prom_argv, *_prom_envp;
+
+void __init prom_init(void)
+{
+	PSYSTEM_PARAMETER_BLOCK pb = PROMBLOCK;
+
+	romvec = ROMVECTOR;
+
+	prom_argc = fw_arg0;
+	_prom_argv = (LONG *) fw_arg1;
+	_prom_envp = (LONG *) fw_arg2;
+
+	if (pb->magic != 0x53435241) {
+		printk(KERN_CRIT "Aieee, bad prom vector magic %08lx\n",
+		       (unsigned long) pb->magic);
+		while(1)
+			;
+	}
+
+	prom_init_cmdline();
+	prom_identify_arch();
+	printk(KERN_INFO "PROMLIB: ARC firmware Version %d Revision %d\n",
+	       pb->ver, pb->rev);
+	prom_meminit();
+
+#ifdef DEBUG_PROM_INIT
+	pr_info("Press a key to reboot\n");
+	ArcRead(0, &c, 1, &cnt);
+	ArcEnterInteractiveMode();
+#endif
+#ifdef CONFIG_SGI_IP27
+	{
+		extern const struct plat_smp_ops ip27_smp_ops;
+
+		register_smp_ops(&ip27_smp_ops);
+	}
+#endif
+}
diff --git a/arch/mips/fw/arc/memory.c b/arch/mips/fw/arc/memory.c
new file mode 100644
index 0000000..dd9496f
--- /dev/null
+++ b/arch/mips/fw/arc/memory.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * memory.c: PROM library functions for acquiring/using memory descriptors
+ *	     given to us from the ARCS firmware.
+ *
+ * Copyright (C) 1996 by David S. Miller
+ * Copyright (C) 1999, 2000, 2001 by Ralf Baechle
+ * Copyright (C) 1999, 2000 by Silicon Graphics, Inc.
+ *
+ * PROM library functions for acquiring/using memory descriptors given to us
+ * from the ARCS firmware.  This is only used when CONFIG_ARC_MEMORY is set
+ * because on some machines like SGI IP27 the ARC memory configuration data
+ * completely bogus and alternate easier to use mechanisms are available.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/swap.h>
+
+#include <asm/sgialib.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+
+#undef DEBUG
+
+/*
+ * For ARC firmware memory functions the unit of meassuring memory is always
+ * a 4k page of memory
+ */
+#define ARC_PAGE_SHIFT	12
+
+struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current)
+{
+	return (struct linux_mdesc *) ARC_CALL1(get_mdesc, Current);
+}
+
+#ifdef DEBUG /* convenient for debugging */
+static char *arcs_mtypes[8] = {
+	"Exception Block",
+	"ARCS Romvec Page",
+	"Free/Contig RAM",
+	"Generic Free RAM",
+	"Bad Memory",
+	"Standalone Program Pages",
+	"ARCS Temp Storage Area",
+	"ARCS Permanent Storage Area"
+};
+
+static char *arc_mtypes[8] = {
+	"Exception Block",
+	"SystemParameterBlock",
+	"FreeMemory",
+	"Bad Memory",
+	"LoadedProgram",
+	"FirmwareTemporary",
+	"FirmwarePermanent",
+	"FreeContiguous"
+};
+#define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] \
+						: arc_mtypes[a.arc]
+#endif
+
+static inline int memtype_classify_arcs(union linux_memtypes type)
+{
+	switch (type.arcs) {
+	case arcs_fcontig:
+	case arcs_free:
+		return BOOT_MEM_RAM;
+	case arcs_atmp:
+		return BOOT_MEM_ROM_DATA;
+	case arcs_eblock:
+	case arcs_rvpage:
+	case arcs_bmem:
+	case arcs_prog:
+	case arcs_aperm:
+		return BOOT_MEM_RESERVED;
+	default:
+		BUG();
+	}
+	while(1);				/* Nuke warning.  */
+}
+
+static inline int memtype_classify_arc(union linux_memtypes type)
+{
+	switch (type.arc) {
+	case arc_free:
+	case arc_fcontig:
+		return BOOT_MEM_RAM;
+	case arc_atmp:
+		return BOOT_MEM_ROM_DATA;
+	case arc_eblock:
+	case arc_rvpage:
+	case arc_bmem:
+	case arc_prog:
+	case arc_aperm:
+		return BOOT_MEM_RESERVED;
+	default:
+		BUG();
+	}
+	while(1);				/* Nuke warning.  */
+}
+
+static int __init prom_memtype_classify(union linux_memtypes type)
+{
+	if (prom_flags & PROM_FLAG_ARCS)	/* SGI is ``different'' ... */
+		return memtype_classify_arcs(type);
+
+	return memtype_classify_arc(type);
+}
+
+void __init prom_meminit(void)
+{
+	struct linux_mdesc *p;
+
+#ifdef DEBUG
+	int i = 0;
+
+	printk("ARCS MEMORY DESCRIPTOR dump:\n");
+	p = ArcGetMemoryDescriptor(PROM_NULL_MDESC);
+	while(p) {
+		printk("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n",
+		       i, p, p->base, p->pages, mtypes(p->type));
+		p = ArcGetMemoryDescriptor(p);
+		i++;
+	}
+#endif
+
+	p = PROM_NULL_MDESC;
+	while ((p = ArcGetMemoryDescriptor(p))) {
+		unsigned long base, size;
+		long type;
+
+		base = p->base << ARC_PAGE_SHIFT;
+		size = p->pages << ARC_PAGE_SHIFT;
+		type = prom_memtype_classify(p->type);
+
+		add_memory_region(base, size, type);
+	}
+}
+
+void __init prom_free_prom_memory(void)
+{
+	unsigned long addr;
+	int i;
+
+	if (prom_flags & PROM_FLAG_DONT_FREE_TEMP)
+		return;
+
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
+			continue;
+
+		addr = boot_mem_map.map[i].addr;
+		free_init_pages("prom memory",
+				addr, addr + boot_mem_map.map[i].size);
+	}
+}
diff --git a/arch/mips/fw/arc/misc.c b/arch/mips/fw/arc/misc.c
new file mode 100644
index 0000000..19f7101
--- /dev/null
+++ b/arch/mips/fw/arc/misc.c
@@ -0,0 +1,95 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Miscellaneous ARCS PROM routines.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ */
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/irqflags.h>
+
+#include <asm/bcache.h>
+
+#include <asm/fw/arc/types.h>
+#include <asm/sgialib.h>
+#include <asm/bootinfo.h>
+
+VOID __noreturn
+ArcHalt(VOID)
+{
+	bc_disable();
+	local_irq_disable();
+	ARC_CALL0(halt);
+
+	unreachable();
+}
+
+VOID __noreturn
+ArcPowerDown(VOID)
+{
+	bc_disable();
+	local_irq_disable();
+	ARC_CALL0(pdown);
+
+	unreachable();
+}
+
+/* XXX is this a soft reset basically? XXX */
+VOID __noreturn
+ArcRestart(VOID)
+{
+	bc_disable();
+	local_irq_disable();
+	ARC_CALL0(restart);
+
+	unreachable();
+}
+
+VOID __noreturn
+ArcReboot(VOID)
+{
+	bc_disable();
+	local_irq_disable();
+	ARC_CALL0(reboot);
+
+	unreachable();
+}
+
+VOID __noreturn
+ArcEnterInteractiveMode(VOID)
+{
+	bc_disable();
+	local_irq_disable();
+	ARC_CALL0(imode);
+
+	unreachable();
+}
+
+LONG
+ArcSaveConfiguration(VOID)
+{
+	return ARC_CALL0(cfg_save);
+}
+
+struct linux_sysid *
+ArcGetSystemId(VOID)
+{
+	return (struct linux_sysid *) ARC_CALL0(get_sysid);
+}
+
+VOID __init
+ArcFlushAllCaches(VOID)
+{
+	ARC_CALL0(cache_flush);
+}
+
+DISPLAY_STATUS * __init ArcGetDisplayStatus(ULONG FileID)
+{
+	return (DISPLAY_STATUS *) ARC_CALL1(GetDisplayStatus, FileID);
+}
diff --git a/arch/mips/fw/arc/promlib.c b/arch/mips/fw/arc/promlib.c
new file mode 100644
index 0000000..be38130
--- /dev/null
+++ b/arch/mips/fw/arc/promlib.c
@@ -0,0 +1,44 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@sgi.com)
+ * Compatibility with board caches, Ulf Carlsson
+ */
+#include <linux/kernel.h>
+#include <asm/sgialib.h>
+#include <asm/bcache.h>
+#include <asm/setup.h>
+
+/*
+ * IP22 boardcache is not compatible with board caches.	 Thus we disable it
+ * during romvec action.  Since r4xx0.c is always compiled and linked with your
+ * kernel, this shouldn't cause any harm regardless what MIPS processor you
+ * have.
+ *
+ * The ARC write and read functions seem to interfere with the serial lines
+ * in some way. You should be careful with them.
+ */
+
+void prom_putchar(char c)
+{
+	ULONG cnt;
+	CHAR it = c;
+
+	bc_disable();
+	ArcWrite(1, &it, 1, &cnt);
+	bc_enable();
+}
+
+char prom_getchar(void)
+{
+	ULONG cnt;
+	CHAR c;
+
+	bc_disable();
+	ArcRead(0, &c, 1, &cnt);
+	bc_enable();
+
+	return c;
+}
diff --git a/arch/mips/fw/arc/salone.c b/arch/mips/fw/arc/salone.c
new file mode 100644
index 0000000..2d99f44
--- /dev/null
+++ b/arch/mips/fw/arc/salone.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Routines to load into memory and execute stand-along program images using
+ * ARCS PROM firmware.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
+ */
+#include <linux/init.h>
+#include <asm/sgialib.h>
+
+LONG __init ArcLoad(CHAR *Path, ULONG TopAddr, ULONG *ExecAddr, ULONG *LowAddr)
+{
+	return ARC_CALL4(load, Path, TopAddr, ExecAddr, LowAddr);
+}
+
+LONG __init ArcInvoke(ULONG ExecAddr, ULONG StackAddr, ULONG Argc, CHAR *Argv[],
+	CHAR *Envp[])
+{
+	return ARC_CALL5(invoke, ExecAddr, StackAddr, Argc, Argv, Envp);
+}
+
+LONG __init ArcExecute(CHAR *Path, LONG Argc, CHAR *Argv[], CHAR *Envp[])
+{
+	return ARC_CALL4(exec, Path, Argc, Argv, Envp);
+}
diff --git a/arch/mips/fw/arc/time.c b/arch/mips/fw/arc/time.c
new file mode 100644
index 0000000..190cdb5
--- /dev/null
+++ b/arch/mips/fw/arc/time.c
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Extracting time information from ARCS prom.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
+ */
+#include <linux/init.h>
+
+#include <asm/fw/arc/types.h>
+#include <asm/sgialib.h>
+
+struct linux_tinfo * __init
+ArcGetTime(VOID)
+{
+	return (struct linux_tinfo *) ARC_CALL0(get_tinfo);
+}
+
+ULONG __init
+ArcGetRelativeTime(VOID)
+{
+	return ARC_CALL0(get_rtime);
+}
diff --git a/arch/mips/fw/arc/tree.c b/arch/mips/fw/arc/tree.c
new file mode 100644
index 0000000..924a37d
--- /dev/null
+++ b/arch/mips/fw/arc/tree.c
@@ -0,0 +1,127 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * PROM component device tree code.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ */
+#include <linux/init.h>
+#include <asm/fw/arc/types.h>
+#include <asm/sgialib.h>
+
+#undef DEBUG_PROM_TREE
+
+pcomponent * __init
+ArcGetPeer(pcomponent *Current)
+{
+	if (Current == PROM_NULL_COMPONENT)
+		return PROM_NULL_COMPONENT;
+
+	return (pcomponent *) ARC_CALL1(next_component, Current);
+}
+
+pcomponent * __init
+ArcGetChild(pcomponent *Current)
+{
+	return (pcomponent *) ARC_CALL1(child_component, Current);
+}
+
+pcomponent * __init
+ArcGetParent(pcomponent *Current)
+{
+	if (Current == PROM_NULL_COMPONENT)
+		return PROM_NULL_COMPONENT;
+
+	return (pcomponent *) ARC_CALL1(parent_component, Current);
+}
+
+LONG __init
+ArcGetConfigurationData(VOID *Buffer, pcomponent *Current)
+{
+	return ARC_CALL2(component_data, Buffer, Current);
+}
+
+pcomponent * __init
+ArcAddChild(pcomponent *Current, pcomponent *Template, VOID *ConfigurationData)
+{
+	return (pcomponent *)
+	       ARC_CALL3(child_add, Current, Template, ConfigurationData);
+}
+
+LONG __init
+ArcDeleteComponent(pcomponent *ComponentToDelete)
+{
+	return ARC_CALL1(comp_del, ComponentToDelete);
+}
+
+pcomponent * __init
+ArcGetComponent(CHAR *Path)
+{
+	return (pcomponent *)ARC_CALL1(component_by_path, Path);
+}
+
+#ifdef DEBUG_PROM_TREE
+
+static char *classes[] = {
+	"system", "processor", "cache", "adapter", "controller", "peripheral",
+	"memory"
+};
+
+static char *types[] = {
+	"arc", "cpu", "fpu", "picache", "pdcache", "sicache", "sdcache",
+	"sccache", "memdev", "eisa adapter", "tc adapter", "scsi adapter",
+	"dti adapter", "multi-func adapter", "disk controller",
+	"tp controller", "cdrom controller", "worm controller",
+	"serial controller", "net controller", "display controller",
+	"parallel controller", "pointer controller", "keyboard controller",
+	"audio controller", "misc controller", "disk peripheral",
+	"floppy peripheral", "tp peripheral", "modem peripheral",
+	"monitor peripheral", "printer peripheral", "pointer peripheral",
+	"keyboard peripheral", "terminal peripheral", "line peripheral",
+	"net peripheral", "misc peripheral", "anonymous"
+};
+
+static char *iflags[] = {
+	"bogus", "read only", "removable", "console in", "console out",
+	"input", "output"
+};
+
+static void __init
+dump_component(pcomponent *p)
+{
+	printk("[%p]:class<%s>type<%s>flags<%s>ver<%d>rev<%d>",
+	       p, classes[p->class], types[p->type],
+	       iflags[p->iflags], p->vers, p->rev);
+	printk("key<%08lx>\n\tamask<%08lx>cdsize<%d>ilen<%d>iname<%s>\n",
+	       p->key, p->amask, (int)p->cdsize, (int)p->ilen, p->iname);
+}
+
+static void __init
+traverse(pcomponent *p, int op)
+{
+	dump_component(p);
+	if(ArcGetChild(p))
+		traverse(ArcGetChild(p), 1);
+	if(ArcGetPeer(p) && op)
+		traverse(ArcGetPeer(p), 1);
+}
+
+void __init
+prom_testtree(void)
+{
+	pcomponent *p;
+
+	p = ArcGetChild(PROM_NULL_COMPONENT);
+	dump_component(p);
+	p = ArcGetChild(p);
+	while(p) {
+		dump_component(p);
+		p = ArcGetPeer(p);
+	}
+}
+
+#endif /* DEBUG_PROM_TREE  */
diff --git a/arch/mips/fw/cfe/Makefile b/arch/mips/fw/cfe/Makefile
new file mode 100644
index 0000000..8f20044
--- /dev/null
+++ b/arch/mips/fw/cfe/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Broadcom Common Firmware Environment support
+#
+
+lib-y += cfe_api.o
diff --git a/arch/mips/fw/cfe/cfe_api.c b/arch/mips/fw/cfe/cfe_api.c
new file mode 100644
index 0000000..cf84f01
--- /dev/null
+++ b/arch/mips/fw/cfe/cfe_api.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ *
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * This module contains device function stubs (small routines to
+ * call the standard "iocb" interface entry point to CFE).
+ * There should be one routine here per iocb function call.
+ *
+ * Authors:  Mitch Lichtenberg, Chris Demetriou
+ */
+
+#include <asm/fw/cfe/cfe_api.h>
+#include "cfe_api_int.h"
+
+/* Cast from a native pointer to a cfe_xptr_t and back.	 */
+#define XPTR_FROM_NATIVE(n)	((cfe_xptr_t) (intptr_t) (n))
+#define NATIVE_FROM_XPTR(x)	((void *) (intptr_t) (x))
+
+int cfe_iocb_dispatch(struct cfe_xiocb *xiocb);
+
+/*
+ * Declare the dispatch function with args of "intptr_t".
+ * This makes sure whatever model we're compiling in
+ * puts the pointers in a single register.  For example,
+ * combining -mlong64 and -mips1 or -mips2 would lead to
+ * trouble, since the handle and IOCB pointer will be
+ * passed in two registers each, and CFE expects one.
+ */
+
+static int (*cfe_dispfunc) (intptr_t handle, intptr_t xiocb);
+static u64 cfe_handle;
+
+int cfe_init(u64 handle, u64 ept)
+{
+	cfe_dispfunc = NATIVE_FROM_XPTR(ept);
+	cfe_handle = handle;
+	return 0;
+}
+
+int cfe_iocb_dispatch(struct cfe_xiocb * xiocb)
+{
+	if (!cfe_dispfunc)
+		return -1;
+	return (*cfe_dispfunc) ((intptr_t) cfe_handle, (intptr_t) xiocb);
+}
+
+int cfe_close(int handle)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_CLOSE;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = handle;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = 0;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+
+}
+
+int cfe_cpu_start(int cpu, void (*fn) (void), long sp, long gp, long a1)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_cpuctl);
+	xiocb.plist.xiocb_cpuctl.cpu_number = cpu;
+	xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_START;
+	xiocb.plist.xiocb_cpuctl.gp_val = gp;
+	xiocb.plist.xiocb_cpuctl.sp_val = sp;
+	xiocb.plist.xiocb_cpuctl.a1_val = a1;
+	xiocb.plist.xiocb_cpuctl.start_addr = (long) fn;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+int cfe_cpu_stop(int cpu)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_cpuctl);
+	xiocb.plist.xiocb_cpuctl.cpu_number = cpu;
+	xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_STOP;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_ENV_SET;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_envbuf);
+	xiocb.plist.xiocb_envbuf.enum_idx = idx;
+	xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name);
+	xiocb.plist.xiocb_envbuf.name_length = namelen;
+	xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(val);
+	xiocb.plist.xiocb_envbuf.val_length = vallen;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+int
+cfe_enummem(int idx, int flags, u64 *start, u64 *length, u64 *type)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_MEMENUM;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = flags;
+	xiocb.xiocb_psize = sizeof(struct xiocb_meminfo);
+	xiocb.plist.xiocb_meminfo.mi_idx = idx;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	if (xiocb.xiocb_status < 0)
+		return xiocb.xiocb_status;
+
+	*start = xiocb.plist.xiocb_meminfo.mi_addr;
+	*length = xiocb.plist.xiocb_meminfo.mi_size;
+	*type = xiocb.plist.xiocb_meminfo.mi_type;
+
+	return 0;
+}
+
+int cfe_exit(int warm, int status)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_RESTART;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = warm ? CFE_FLG_WARMSTART : 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_exitstat);
+	xiocb.plist.xiocb_exitstat.status = status;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+int cfe_flushcache(int flg)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_FLUSHCACHE;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = flg;
+	xiocb.xiocb_psize = 0;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+int cfe_getdevinfo(char *name)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_GETINFO;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
+	xiocb.plist.xiocb_buffer.buf_offset = 0;
+	xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(name);
+	xiocb.plist.xiocb_buffer.buf_length = strlen(name);
+
+	cfe_iocb_dispatch(&xiocb);
+
+	if (xiocb.xiocb_status < 0)
+		return xiocb.xiocb_status;
+	return xiocb.plist.xiocb_buffer.buf_ioctlcmd;
+}
+
+int cfe_getenv(char *name, char *dest, int destlen)
+{
+	struct cfe_xiocb xiocb;
+
+	*dest = 0;
+
+	xiocb.xiocb_fcode = CFE_CMD_ENV_GET;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_envbuf);
+	xiocb.plist.xiocb_envbuf.enum_idx = 0;
+	xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name);
+	xiocb.plist.xiocb_envbuf.name_length = strlen(name);
+	xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(dest);
+	xiocb.plist.xiocb_envbuf.val_length = destlen;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+int cfe_getfwinfo(cfe_fwinfo_t * info)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_GETINFO;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_fwinfo);
+
+	cfe_iocb_dispatch(&xiocb);
+
+	if (xiocb.xiocb_status < 0)
+		return xiocb.xiocb_status;
+
+	info->fwi_version = xiocb.plist.xiocb_fwinfo.fwi_version;
+	info->fwi_totalmem = xiocb.plist.xiocb_fwinfo.fwi_totalmem;
+	info->fwi_flags = xiocb.plist.xiocb_fwinfo.fwi_flags;
+	info->fwi_boardid = xiocb.plist.xiocb_fwinfo.fwi_boardid;
+	info->fwi_bootarea_va = xiocb.plist.xiocb_fwinfo.fwi_bootarea_va;
+	info->fwi_bootarea_pa = xiocb.plist.xiocb_fwinfo.fwi_bootarea_pa;
+	info->fwi_bootarea_size =
+	    xiocb.plist.xiocb_fwinfo.fwi_bootarea_size;
+#if 0
+	info->fwi_reserved1 = xiocb.plist.xiocb_fwinfo.fwi_reserved1;
+	info->fwi_reserved2 = xiocb.plist.xiocb_fwinfo.fwi_reserved2;
+	info->fwi_reserved3 = xiocb.plist.xiocb_fwinfo.fwi_reserved3;
+#endif
+
+	return 0;
+}
+
+int cfe_getstdhandle(int flg)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_GETHANDLE;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = flg;
+	xiocb.xiocb_psize = 0;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	if (xiocb.xiocb_status < 0)
+		return xiocb.xiocb_status;
+	return xiocb.xiocb_handle;
+}
+
+int64_t
+cfe_getticks(void)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_FW_GETTIME;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_time);
+	xiocb.plist.xiocb_time.ticks = 0;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.plist.xiocb_time.ticks;
+
+}
+
+int cfe_inpstat(int handle)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_INPSTAT;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = handle;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_inpstat);
+	xiocb.plist.xiocb_inpstat.inp_status = 0;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	if (xiocb.xiocb_status < 0)
+		return xiocb.xiocb_status;
+	return xiocb.plist.xiocb_inpstat.inp_status;
+}
+
+int
+cfe_ioctl(int handle, unsigned int ioctlnum, unsigned char *buffer,
+	  int length, int *retlen, u64 offset)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_IOCTL;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = handle;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
+	xiocb.plist.xiocb_buffer.buf_offset = offset;
+	xiocb.plist.xiocb_buffer.buf_ioctlcmd = ioctlnum;
+	xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer);
+	xiocb.plist.xiocb_buffer.buf_length = length;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	if (retlen)
+		*retlen = xiocb.plist.xiocb_buffer.buf_retlen;
+	return xiocb.xiocb_status;
+}
+
+int cfe_open(char *name)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_OPEN;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
+	xiocb.plist.xiocb_buffer.buf_offset = 0;
+	xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(name);
+	xiocb.plist.xiocb_buffer.buf_length = strlen(name);
+
+	cfe_iocb_dispatch(&xiocb);
+
+	if (xiocb.xiocb_status < 0)
+		return xiocb.xiocb_status;
+	return xiocb.xiocb_handle;
+}
+
+int cfe_read(int handle, unsigned char *buffer, int length)
+{
+	return cfe_readblk(handle, 0, buffer, length);
+}
+
+int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_READ;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = handle;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
+	xiocb.plist.xiocb_buffer.buf_offset = offset;
+	xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer);
+	xiocb.plist.xiocb_buffer.buf_length = length;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	if (xiocb.xiocb_status < 0)
+		return xiocb.xiocb_status;
+	return xiocb.plist.xiocb_buffer.buf_retlen;
+}
+
+int cfe_setenv(char *name, char *val)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_ENV_SET;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = 0;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_envbuf);
+	xiocb.plist.xiocb_envbuf.enum_idx = 0;
+	xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name);
+	xiocb.plist.xiocb_envbuf.name_length = strlen(name);
+	xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(val);
+	xiocb.plist.xiocb_envbuf.val_length = strlen(val);
+
+	cfe_iocb_dispatch(&xiocb);
+
+	return xiocb.xiocb_status;
+}
+
+int cfe_write(int handle, const char *buffer, int length)
+{
+	return cfe_writeblk(handle, 0, buffer, length);
+}
+
+int cfe_writeblk(int handle, s64 offset, const char *buffer, int length)
+{
+	struct cfe_xiocb xiocb;
+
+	xiocb.xiocb_fcode = CFE_CMD_DEV_WRITE;
+	xiocb.xiocb_status = 0;
+	xiocb.xiocb_handle = handle;
+	xiocb.xiocb_flags = 0;
+	xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
+	xiocb.plist.xiocb_buffer.buf_offset = offset;
+	xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer);
+	xiocb.plist.xiocb_buffer.buf_length = length;
+
+	cfe_iocb_dispatch(&xiocb);
+
+	if (xiocb.xiocb_status < 0)
+		return xiocb.xiocb_status;
+	return xiocb.plist.xiocb_buffer.buf_retlen;
+}
diff --git a/arch/mips/fw/cfe/cfe_api_int.h b/arch/mips/fw/cfe/cfe_api_int.h
new file mode 100644
index 0000000..d9759e6
--- /dev/null
+++ b/arch/mips/fw/cfe/cfe_api_int.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#ifndef CFE_API_INT_H
+#define CFE_API_INT_H
+
+/*
+ * Constants.
+ */
+#define CFE_CMD_FW_GETINFO	0
+#define CFE_CMD_FW_RESTART	1
+#define CFE_CMD_FW_BOOT		2
+#define CFE_CMD_FW_CPUCTL	3
+#define CFE_CMD_FW_GETTIME      4
+#define CFE_CMD_FW_MEMENUM	5
+#define CFE_CMD_FW_FLUSHCACHE	6
+
+#define CFE_CMD_DEV_GETHANDLE	9
+#define CFE_CMD_DEV_ENUM	10
+#define CFE_CMD_DEV_OPEN	11
+#define CFE_CMD_DEV_INPSTAT	12
+#define CFE_CMD_DEV_READ	13
+#define CFE_CMD_DEV_WRITE	14
+#define CFE_CMD_DEV_IOCTL	15
+#define CFE_CMD_DEV_CLOSE	16
+#define CFE_CMD_DEV_GETINFO	17
+
+#define CFE_CMD_ENV_ENUM	20
+#define CFE_CMD_ENV_GET		22
+#define CFE_CMD_ENV_SET		23
+#define CFE_CMD_ENV_DEL		24
+
+#define CFE_CMD_MAX		32
+
+#define CFE_CMD_VENDOR_USE	0x8000	/* codes above this are for customer use */
+
+/*
+ * Structures.
+ */
+
+/* eeek, signed "pointers" */
+typedef s64 cfe_xptr_t;
+
+struct xiocb_buffer {
+	u64 buf_offset;		/* offset on device (bytes) */
+	cfe_xptr_t  buf_ptr;		/* pointer to a buffer */
+	u64 buf_length;		/* length of this buffer */
+	u64 buf_retlen;		/* returned length (for read ops) */
+	u64 buf_ioctlcmd;	/* IOCTL command (used only for IOCTLs) */
+};
+
+struct xiocb_inpstat {
+	u64 inp_status;		/* 1 means input available */
+};
+
+struct xiocb_envbuf {
+	s64 enum_idx;		/* 0-based enumeration index */
+	cfe_xptr_t name_ptr;		/* name string buffer */
+	s64 name_length;		/* size of name buffer */
+	cfe_xptr_t val_ptr;		/* value string buffer */
+	s64 val_length;		/* size of value string buffer */
+};
+
+struct xiocb_cpuctl {
+	u64 cpu_number;		/* cpu number to control */
+	u64 cpu_command;	/* command to issue to CPU */
+	u64 start_addr;		/* CPU start address */
+	u64 gp_val;		/* starting GP value */
+	u64 sp_val;		/* starting SP value */
+	u64 a1_val;		/* starting A1 value */
+};
+
+struct xiocb_time {
+	s64 ticks;		/* current time in ticks */
+};
+
+struct xiocb_exitstat{
+	s64 status;
+};
+
+struct xiocb_meminfo {
+	s64 mi_idx;		/* 0-based enumeration index */
+	s64 mi_type;		/* type of memory block */
+	u64 mi_addr;		/* physical start address */
+	u64 mi_size;		/* block size */
+};
+
+struct xiocb_fwinfo {
+	s64 fwi_version;		/* major, minor, eco version */
+	s64 fwi_totalmem;	/* total installed mem */
+	s64 fwi_flags;		/* various flags */
+	s64 fwi_boardid;		/* board ID */
+	s64 fwi_bootarea_va;	/* VA of boot area */
+	s64 fwi_bootarea_pa;	/* PA of boot area */
+	s64 fwi_bootarea_size;	/* size of boot area */
+	s64 fwi_reserved1;
+	s64 fwi_reserved2;
+	s64 fwi_reserved3;
+};
+
+struct cfe_xiocb {
+	u64 xiocb_fcode;	/* IOCB function code */
+	s64 xiocb_status;	/* return status */
+	s64 xiocb_handle;	/* file/device handle */
+	u64 xiocb_flags;	/* flags for this IOCB */
+	u64 xiocb_psize;	/* size of parameter list */
+	union {
+		/* buffer parameters */
+		struct xiocb_buffer xiocb_buffer;
+
+		/* input status parameters */
+		struct xiocb_inpstat xiocb_inpstat;
+
+		/* environment function parameters */
+		struct xiocb_envbuf xiocb_envbuf;
+
+		/* CPU control parameters */
+		struct xiocb_cpuctl xiocb_cpuctl;
+
+		/* timer parameters */
+		struct xiocb_time xiocb_time;
+
+		/* memory arena info parameters */
+		struct xiocb_meminfo xiocb_meminfo;
+
+		/* firmware information */
+		struct xiocb_fwinfo xiocb_fwinfo;
+
+		/* Exit Status */
+		struct xiocb_exitstat xiocb_exitstat;
+	} plist;
+};
+
+#endif /* CFE_API_INT_H */
diff --git a/arch/mips/fw/lib/Makefile b/arch/mips/fw/lib/Makefile
new file mode 100644
index 0000000..5291505
--- /dev/null
+++ b/arch/mips/fw/lib/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for generic prom monitor library routines under Linux.
+#
+
+lib-y			+= cmdline.o
+
+lib-$(CONFIG_64BIT)	+= call_o32.o
diff --git a/arch/mips/fw/lib/call_o32.S b/arch/mips/fw/lib/call_o32.S
new file mode 100644
index 0000000..4703fe4
--- /dev/null
+++ b/arch/mips/fw/lib/call_o32.S
@@ -0,0 +1,108 @@
+/*
+ *	O32 interface for the 64 (or N32) ABI.
+ *
+ *	Copyright (C) 2002, 2014  Maciej W. Rozycki
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+/* O32 register size.  */
+#define O32_SZREG	4
+/* Maximum number of arguments supported.  Must be even!  */
+#define O32_ARGC	32
+/* Number of static registers we save.  */
+#define O32_STATC	11
+/* Argument area frame size.  */
+#define O32_ARGSZ	(O32_SZREG * O32_ARGC)
+/* Static register save area frame size.  */
+#define O32_STATSZ	(SZREG * O32_STATC)
+/* Stack pointer register save area frame size.  */
+#define O32_SPSZ	SZREG
+/* Combined area frame size.  */
+#define O32_FRAMESZ	(O32_ARGSZ + O32_SPSZ + O32_STATSZ)
+/* Switched stack frame size.  */
+#define O32_NFRAMESZ	(O32_ARGSZ + O32_SPSZ)
+
+		.text
+
+/*
+ * O32 function call dispatcher, for interfacing 32-bit ROM routines.
+ *
+ * The standard 64 (N32) calling sequence is supported, with a0 holding
+ * a function pointer, a1 a pointer to the new stack to call the
+ * function with or 0 if no stack switching is requested, a2-a7 -- the
+ * function call's first six arguments, and the stack -- the remaining
+ * arguments (up to O32_ARGC, including a2-a7).  Static registers, gp
+ * and fp are preserved, v0 holds the result.  This code relies on the
+ * called o32 function for sp and ra restoration and this dispatcher has
+ * to be placed in a KSEGx (or KUSEG) address space.  Any pointers
+ * passed have to point to addresses within one of these spaces as well.
+ */
+NESTED(call_o32, O32_FRAMESZ, ra)
+		REG_SUBU	sp,O32_FRAMESZ
+
+		REG_S		ra,O32_FRAMESZ-1*SZREG(sp)
+		REG_S		fp,O32_FRAMESZ-2*SZREG(sp)
+		REG_S		gp,O32_FRAMESZ-3*SZREG(sp)
+		REG_S		s7,O32_FRAMESZ-4*SZREG(sp)
+		REG_S		s6,O32_FRAMESZ-5*SZREG(sp)
+		REG_S		s5,O32_FRAMESZ-6*SZREG(sp)
+		REG_S		s4,O32_FRAMESZ-7*SZREG(sp)
+		REG_S		s3,O32_FRAMESZ-8*SZREG(sp)
+		REG_S		s2,O32_FRAMESZ-9*SZREG(sp)
+		REG_S		s1,O32_FRAMESZ-10*SZREG(sp)
+		REG_S		s0,O32_FRAMESZ-11*SZREG(sp)
+
+		move		jp,a0
+
+		move		fp,sp
+		beqz		a1,0f
+		REG_SUBU	fp,a1,O32_NFRAMESZ
+0:
+		REG_S		sp,O32_NFRAMESZ-1*SZREG(fp)
+
+		sll		a0,a2,zero
+		sll		a1,a3,zero
+		sll		a2,a4,zero
+		sll		a3,a5,zero
+		sw		a6,4*O32_SZREG(fp)
+		sw		a7,5*O32_SZREG(fp)
+
+		PTR_LA		t0,O32_FRAMESZ(sp)
+		PTR_LA		t1,6*O32_SZREG(fp)
+		li		t2,O32_ARGC-6
+1:
+		lw		t3,(t0)
+		REG_ADDU	t0,SZREG
+		sw		t3,(t1)
+		REG_SUBU	t2,1
+		REG_ADDU	t1,O32_SZREG
+		bnez		t2,1b
+
+		move		sp,fp
+
+		jalr		jp
+
+		REG_L		sp,O32_NFRAMESZ-1*SZREG(sp)
+
+		REG_L		s0,O32_FRAMESZ-11*SZREG(sp)
+		REG_L		s1,O32_FRAMESZ-10*SZREG(sp)
+		REG_L		s2,O32_FRAMESZ-9*SZREG(sp)
+		REG_L		s3,O32_FRAMESZ-8*SZREG(sp)
+		REG_L		s4,O32_FRAMESZ-7*SZREG(sp)
+		REG_L		s5,O32_FRAMESZ-6*SZREG(sp)
+		REG_L		s6,O32_FRAMESZ-5*SZREG(sp)
+		REG_L		s7,O32_FRAMESZ-4*SZREG(sp)
+		REG_L		gp,O32_FRAMESZ-3*SZREG(sp)
+		REG_L		fp,O32_FRAMESZ-2*SZREG(sp)
+		REG_L		ra,O32_FRAMESZ-1*SZREG(sp)
+
+		REG_ADDU	sp,O32_FRAMESZ
+		jr		ra
+END(call_o32)
diff --git a/arch/mips/fw/lib/cmdline.c b/arch/mips/fw/lib/cmdline.c
new file mode 100644
index 0000000..6ecda64
--- /dev/null
+++ b/arch/mips/fw/lib/cmdline.c
@@ -0,0 +1,101 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/addrspace.h>
+#include <asm/fw/fw.h>
+
+int fw_argc;
+int *_fw_argv;
+int *_fw_envp;
+
+void __init fw_init_cmdline(void)
+{
+	int i;
+
+	/* Validate command line parameters. */
+	if ((fw_arg0 >= CKSEG0) || (fw_arg1 < CKSEG0)) {
+		fw_argc = 0;
+		_fw_argv = NULL;
+	} else {
+		fw_argc = (fw_arg0 & 0x0000ffff);
+		_fw_argv = (int *)fw_arg1;
+	}
+
+	/* Validate environment pointer. */
+	if (fw_arg2 < CKSEG0)
+		_fw_envp = NULL;
+	else
+		_fw_envp = (int *)fw_arg2;
+
+	for (i = 1; i < fw_argc; i++) {
+		strlcat(arcs_cmdline, fw_argv(i), COMMAND_LINE_SIZE);
+		if (i < (fw_argc - 1))
+			strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
+	}
+}
+
+char * __init fw_getcmdline(void)
+{
+	return &(arcs_cmdline[0]);
+}
+
+char *fw_getenv(char *envname)
+{
+	char *result = NULL;
+
+	if (_fw_envp != NULL) {
+		/*
+		 * Return a pointer to the given environment variable.
+		 * YAMON uses "name", "value" pairs, while U-Boot uses
+		 * "name=value".
+		 */
+		int i, yamon, index = 0;
+
+		yamon = (strchr(fw_envp(index), '=') == NULL);
+		i = strlen(envname);
+
+		while (fw_envp(index)) {
+			if (strncmp(envname, fw_envp(index), i) == 0) {
+				if (yamon) {
+					result = fw_envp(index + 1);
+					break;
+				} else if (fw_envp(index)[i] == '=') {
+					result = fw_envp(index) + i + 1;
+					break;
+				}
+			}
+
+			/* Increment array index. */
+			if (yamon)
+				index += 2;
+			else
+				index += 1;
+		}
+	}
+
+	return result;
+}
+
+unsigned long fw_getenvl(char *envname)
+{
+	unsigned long envl = 0UL;
+	char *str;
+	int tmp;
+
+	str = fw_getenv(envname);
+	if (str) {
+		tmp = kstrtoul(str, 0, &envl);
+		if (tmp)
+			envl = 0;
+	}
+
+	return envl;
+}
diff --git a/arch/mips/fw/sni/Makefile b/arch/mips/fw/sni/Makefile
new file mode 100644
index 0000000..3f01dd3
--- /dev/null
+++ b/arch/mips/fw/sni/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the SNI prom monitor routines under Linux.
+#
+
+lib-$(CONFIG_FW_SNIPROM)	+= sniprom.o
diff --git a/arch/mips/fw/sni/sniprom.c b/arch/mips/fw/sni/sniprom.c
new file mode 100644
index 0000000..8772617
--- /dev/null
+++ b/arch/mips/fw/sni/sniprom.c
@@ -0,0 +1,153 @@
+/*
+ * Big Endian PROM code for SNI RM machines
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005-2006 Florian Lohoff (flo@rfc822.org)
+ * Copyright (C) 2005-2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/console.h>
+
+#include <asm/addrspace.h>
+#include <asm/sni.h>
+#include <asm/mipsprom.h>
+#include <asm/mipsregs.h>
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
+
+/* special SNI prom calls */
+/*
+ * This does not exist in all proms - SINIX compares
+ * the prom env variable "version" against "2.0008"
+ * or greater. If lesser it tries to probe interesting
+ * registers
+ */
+#define PROM_GET_MEMCONF	58
+#define PROM_GET_HWCONF		61
+
+#define PROM_VEC		(u64 *)CKSEG1ADDR(0x1fc00000)
+#define PROM_ENTRY(x)		(PROM_VEC + (x))
+
+#define ___prom_putchar		((int *(*)(int))PROM_ENTRY(PROM_PUTCHAR))
+#define ___prom_getenv		((char *(*)(char *))PROM_ENTRY(PROM_GETENV))
+#define ___prom_get_memconf	((void (*)(void *))PROM_ENTRY(PROM_GET_MEMCONF))
+#define ___prom_get_hwconf	((u32 (*)(void))PROM_ENTRY(PROM_GET_HWCONF))
+
+#ifdef CONFIG_64BIT
+
+/* O32 stack has to be 8-byte aligned. */
+static u64 o32_stk[4096];
+#define O32_STK	  &o32_stk[sizeof(o32_stk)]
+
+#define __PROM_O32(fun, arg) fun arg __asm__(#fun); \
+				     __asm__(#fun " = call_o32")
+
+int   __PROM_O32(__prom_putchar, (int *(*)(int), void *, int));
+char *__PROM_O32(__prom_getenv, (char *(*)(char *), void *, char *));
+void  __PROM_O32(__prom_get_memconf, (void (*)(void *), void *, void *));
+u32   __PROM_O32(__prom_get_hwconf, (u32 (*)(void), void *));
+
+#define _prom_putchar(x)     __prom_putchar(___prom_putchar, O32_STK, x)
+#define _prom_getenv(x)	     __prom_getenv(___prom_getenv, O32_STK, x)
+#define _prom_get_memconf(x) __prom_get_memconf(___prom_get_memconf, O32_STK, x)
+#define _prom_get_hwconf()   __prom_get_hwconf(___prom_get_hwconf, O32_STK)
+
+#else
+#define _prom_putchar(x)     ___prom_putchar(x)
+#define _prom_getenv(x)	     ___prom_getenv(x)
+#define _prom_get_memconf(x) ___prom_get_memconf(x)
+#define _prom_get_hwconf(x)  ___prom_get_hwconf(x)
+#endif
+
+void prom_putchar(char c)
+{
+	_prom_putchar(c);
+}
+
+
+char *prom_getenv(char *s)
+{
+	return _prom_getenv(s);
+}
+
+void *prom_get_hwconf(void)
+{
+	u32 hwconf = _prom_get_hwconf();
+
+	if (hwconf == 0xffffffff)
+		return NULL;
+
+	return (void *)CKSEG1ADDR(hwconf);
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+/*
+ * /proc/cpuinfo system type
+ *
+ */
+char *system_type = "Unknown";
+const char *get_system_type(void)
+{
+	return system_type;
+}
+
+static void __init sni_mem_init(void)
+{
+	int i, memsize;
+	struct membank {
+		u32		size;
+		u32		base;
+		u32		size2;
+		u32		pad1;
+		u32		pad2;
+	} memconf[8];
+	int brd_type = *(unsigned char *)SNI_IDPROM_BRDTYPE;
+
+
+	/* MemSIZE from prom in 16MByte chunks */
+	memsize = *((unsigned char *) SNI_IDPROM_MEMSIZE) * 16;
+
+	pr_debug("IDProm memsize: %u MByte\n", memsize);
+
+	/* get memory bank layout from prom */
+	_prom_get_memconf(&memconf);
+
+	pr_debug("prom_get_mem_conf memory configuration:\n");
+	for (i = 0; i < 8 && memconf[i].size; i++) {
+		if (brd_type == SNI_BRD_PCI_TOWER ||
+		    brd_type == SNI_BRD_PCI_TOWER_CPLUS) {
+			if (memconf[i].base >= 0x20000000 &&
+			    memconf[i].base <  0x30000000)
+				memconf[i].base -= 0x20000000;
+		}
+		pr_debug("Bank%d: %08x @ %08x\n", i,
+			memconf[i].size, memconf[i].base);
+		add_memory_region(memconf[i].base, memconf[i].size,
+				  BOOT_MEM_RAM);
+	}
+}
+
+void __init prom_init(void)
+{
+	int argc = fw_arg0;
+	u32 *argv = (u32 *)CKSEG0ADDR(fw_arg1);
+	int i;
+
+	sni_mem_init();
+
+	/* copy prom cmdline parameters to kernel cmdline */
+	for (i = 1; i < argc; i++) {
+		strcat(arcs_cmdline, (char *)CKSEG0ADDR(argv[i]));
+		if (i < (argc - 1))
+			strcat(arcs_cmdline, " ");
+	}
+}