[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/kernel/linux/v4.14/arch/mips/sni/Makefile b/src/kernel/linux/v4.14/arch/mips/sni/Makefile
new file mode 100644
index 0000000..9d3bad3
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sni/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the SNI specific part of the kernel
+#
+
+obj-y += irq.o reset.o setup.o a20r.o rm200.o pcimt.o pcit.o time.o
+obj-$(CONFIG_EISA) += eisa.o
diff --git a/src/kernel/linux/v4.14/arch/mips/sni/Platform b/src/kernel/linux/v4.14/arch/mips/sni/Platform
new file mode 100644
index 0000000..2644a9d
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sni/Platform
@@ -0,0 +1,11 @@
+#
+# SNI RM
+#
+platform-$(CONFIG_SNI_RM)		+= sni/
+cflags-$(CONFIG_SNI_RM)		+= -I$(srctree)/arch/mips/include/asm/mach-rm
+ifdef CONFIG_CPU_LITTLE_ENDIAN
+load-$(CONFIG_SNI_RM)		+= 0xffffffff80600000
+else
+load-$(CONFIG_SNI_RM)		+= 0xffffffff80030000
+endif
+all-$(CONFIG_SNI_RM)		:= $(COMPRESSION_FNAME).ecoff
diff --git a/src/kernel/linux/v4.14/arch/mips/sni/a20r.c b/src/kernel/linux/v4.14/arch/mips/sni/a20r.c
new file mode 100644
index 0000000..c6af704
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sni/a20r.c
@@ -0,0 +1,254 @@
+/*
+ * A20R specific code
+ *
+ * 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) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+
+#include <asm/sni.h>
+#include <asm/time.h>
+
+#define PORT(_base,_irq)				\
+	{						\
+		.iobase		= _base,		\
+		.irq		= _irq,			\
+		.uartclk	= 1843200,		\
+		.iotype		= UPIO_PORT,		\
+		.flags		= UPF_BOOT_AUTOCONF,	\
+	}
+
+static struct plat_serial8250_port a20r_data[] = {
+	PORT(0x3f8, 4),
+	PORT(0x2f8, 3),
+	{ },
+};
+
+static struct platform_device a20r_serial8250_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= a20r_data,
+	},
+};
+
+static struct resource a20r_ds1216_rsrc[] = {
+	{
+		.start = 0x1c081ffc,
+		.end   = 0x1c081fff,
+		.flags = IORESOURCE_MEM
+	}
+};
+
+static struct platform_device a20r_ds1216_device = {
+	.name		= "rtc-ds1216",
+	.num_resources	= ARRAY_SIZE(a20r_ds1216_rsrc),
+	.resource	= a20r_ds1216_rsrc
+};
+
+static struct resource snirm_82596_rsrc[] = {
+	{
+		.start = 0x18000000,
+		.end   = 0x18000004,
+		.flags = IORESOURCE_MEM
+	},
+	{
+		.start = 0x18010000,
+		.end   = 0x18010004,
+		.flags = IORESOURCE_MEM
+	},
+	{
+		.start = 0x1ff00000,
+		.end   = 0x1ff00020,
+		.flags = IORESOURCE_MEM
+	},
+	{
+		.start = 22,
+		.end   = 22,
+		.flags = IORESOURCE_IRQ
+	},
+	{
+		.flags = 0x01		     /* 16bit mpu port access */
+	}
+};
+
+static struct platform_device snirm_82596_pdev = {
+	.name		= "snirm_82596",
+	.num_resources	= ARRAY_SIZE(snirm_82596_rsrc),
+	.resource	= snirm_82596_rsrc
+};
+
+static struct resource snirm_53c710_rsrc[] = {
+	{
+		.start = 0x19000000,
+		.end   = 0x190fffff,
+		.flags = IORESOURCE_MEM
+	},
+	{
+		.start = 19,
+		.end   = 19,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+static struct platform_device snirm_53c710_pdev = {
+	.name		= "snirm_53c710",
+	.num_resources	= ARRAY_SIZE(snirm_53c710_rsrc),
+	.resource	= snirm_53c710_rsrc
+};
+
+static struct resource sc26xx_rsrc[] = {
+	{
+		.start = 0x1c070000,
+		.end   = 0x1c0700ff,
+		.flags = IORESOURCE_MEM
+	},
+	{
+		.start = 20,
+		.end   = 20,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+#include <linux/platform_data/serial-sccnxp.h>
+
+static struct sccnxp_pdata sccnxp_data = {
+	.reg_shift	= 2,
+	.mctrl_cfg[0]	= MCTRL_SIG(DTR_OP, LINE_OP7) |
+			  MCTRL_SIG(RTS_OP, LINE_OP3) |
+			  MCTRL_SIG(DSR_IP, LINE_IP5) |
+			  MCTRL_SIG(DCD_IP, LINE_IP6),
+	.mctrl_cfg[1]	= MCTRL_SIG(DTR_OP, LINE_OP2) |
+			  MCTRL_SIG(RTS_OP, LINE_OP1) |
+			  MCTRL_SIG(DSR_IP, LINE_IP0) |
+			  MCTRL_SIG(CTS_IP, LINE_IP1) |
+			  MCTRL_SIG(DCD_IP, LINE_IP2) |
+			  MCTRL_SIG(RNG_IP, LINE_IP3),
+};
+
+static struct platform_device sc26xx_pdev = {
+	.name		= "sc2681",
+	.resource	= sc26xx_rsrc,
+	.num_resources	= ARRAY_SIZE(sc26xx_rsrc),
+	.dev	= {
+		.platform_data	= &sccnxp_data,
+	},
+};
+
+/*
+ * Trigger chipset to update CPU's CAUSE IP field
+ */
+static u32 a20r_update_cause_ip(void)
+{
+	u32 status = read_c0_status();
+
+	write_c0_status(status | 0x00010000);
+	asm volatile(
+	"	.set	push			\n"
+	"	.set	noat			\n"
+	"	.set	noreorder		\n"
+	"	lw	$1, 0(%0)		\n"
+	"	sb	$0, 0(%1)		\n"
+	"	sync				\n"
+	"	lb	%1, 0(%1)		\n"
+	"	b	1f			\n"
+	"	ori	%1, $1, 2		\n"
+	"	.align	8			\n"
+	"1:					\n"
+	"	nop				\n"
+	"	sw	%1, 0(%0)		\n"
+	"	sync				\n"
+	"	li	%1, 0x20		\n"
+	"2:					\n"
+	"	nop				\n"
+	"	bnez	%1,2b			\n"
+	"	addiu	%1, -1			\n"
+	"	sw	$1, 0(%0)		\n"
+	"	sync				\n"
+		".set	pop			\n"
+	:
+	: "Jr" (PCIMT_UCONF), "Jr" (0xbc000000));
+	write_c0_status(status);
+
+	return status;
+}
+
+static inline void unmask_a20r_irq(struct irq_data *d)
+{
+	set_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE));
+	irq_enable_hazard();
+}
+
+static inline void mask_a20r_irq(struct irq_data *d)
+{
+	clear_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE));
+	irq_disable_hazard();
+}
+
+static struct irq_chip a20r_irq_type = {
+	.name		= "A20R",
+	.irq_mask	= mask_a20r_irq,
+	.irq_unmask	= unmask_a20r_irq,
+};
+
+/*
+ * hwint 0 receive all interrupts
+ */
+static void a20r_hwint(void)
+{
+	u32 cause, status;
+	int irq;
+
+	clear_c0_status(IE_IRQ0);
+	status = a20r_update_cause_ip();
+	cause = read_c0_cause();
+
+	irq = ffs(((cause & status) >> 8) & 0xf8);
+	if (likely(irq > 0))
+		do_IRQ(SNI_A20R_IRQ_BASE + irq - 1);
+
+	a20r_update_cause_ip();
+	set_c0_status(IE_IRQ0);
+}
+
+void __init sni_a20r_irq_init(void)
+{
+	int i;
+
+	for (i = SNI_A20R_IRQ_BASE + 2 ; i < SNI_A20R_IRQ_BASE + 8; i++)
+		irq_set_chip_and_handler(i, &a20r_irq_type, handle_level_irq);
+	sni_hwint = a20r_hwint;
+	change_c0_status(ST0_IM, IE_IRQ0);
+	setup_irq(SNI_A20R_IRQ_BASE + 3, &sni_isa_irq);
+}
+
+void sni_a20r_init(void)
+{
+	/* FIXME, remove if not needed */
+}
+
+static int __init snirm_a20r_setup_devinit(void)
+{
+	switch (sni_brd_type) {
+	case SNI_BRD_TOWER_OASIC:
+	case SNI_BRD_MINITOWER:
+		platform_device_register(&snirm_82596_pdev);
+		platform_device_register(&snirm_53c710_pdev);
+		platform_device_register(&sc26xx_pdev);
+		platform_device_register(&a20r_serial8250_device);
+		platform_device_register(&a20r_ds1216_device);
+		sni_eisa_root_init();
+		break;
+	}
+	return 0;
+}
+
+device_initcall(snirm_a20r_setup_devinit);
diff --git a/src/kernel/linux/v4.14/arch/mips/sni/eisa.c b/src/kernel/linux/v4.14/arch/mips/sni/eisa.c
new file mode 100644
index 0000000..179b5d5
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sni/eisa.c
@@ -0,0 +1,50 @@
+/*
+ * Virtual EISA root driver.
+ * Acts as a placeholder if we don't have a proper EISA bridge.
+ *
+ * (C) 2003 Marc Zyngier <maz@wild-wind.fr.eu.org>
+ * modified for SNI usage by Thomas Bogendoerfer
+ *
+ * This code is released under the GPL version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/eisa.h>
+#include <linux/init.h>
+
+/* The default EISA device parent (virtual root device).
+ * Now use a platform device, since that's the obvious choice. */
+
+static struct platform_device eisa_root_dev = {
+	.name = "eisa",
+	.id   = 0,
+};
+
+static struct eisa_root_device eisa_bus_root = {
+	.dev	       = &eisa_root_dev.dev,
+	.bus_base_addr = 0,
+	.res	       = &ioport_resource,
+	.slots	       = EISA_MAX_SLOTS,
+	.dma_mask      = 0xffffffff,
+	.force_probe   = 1,
+};
+
+int __init sni_eisa_root_init(void)
+{
+	int r;
+
+	r = platform_device_register(&eisa_root_dev);
+	if (!r)
+		return r;
+
+	dev_set_drvdata(&eisa_root_dev.dev, &eisa_bus_root);
+
+	if (eisa_root_register(&eisa_bus_root)) {
+		/* A real bridge may have been registered before
+		 * us. So quietly unregister. */
+		platform_device_unregister(&eisa_root_dev);
+		return -1;
+	}
+	return 0;
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sni/irq.c b/src/kernel/linux/v4.14/arch/mips/sni/irq.c
new file mode 100644
index 0000000..ac61b90
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sni/irq.c
@@ -0,0 +1,82 @@
+/*
+ * 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) 1992 Linus Torvalds
+ * Copyright (C) 1994 - 2000 Ralf Baechle
+ * Copyright (C) 2006 Thomas Bogendoerfer
+ */
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+
+#include <asm/i8259.h>
+#include <asm/io.h>
+#include <asm/sni.h>
+#include <asm/irq.h>
+#include <asm/irq_cpu.h>
+
+void (*sni_hwint)(void);
+
+asmlinkage void plat_irq_dispatch(void)
+{
+	sni_hwint();
+}
+
+/* ISA irq handler */
+static irqreturn_t sni_isa_irq_handler(int dummy, void *p)
+{
+	int irq;
+
+	irq = i8259_irq();
+	if (unlikely(irq < 0))
+		return IRQ_NONE;
+
+	generic_handle_irq(irq);
+	return IRQ_HANDLED;
+}
+
+struct irqaction sni_isa_irq = {
+	.handler = sni_isa_irq_handler,
+	.name = "ISA",
+	.flags = IRQF_SHARED
+};
+
+/*
+ * On systems with i8259-style interrupt controllers we assume for
+ * driver compatibility reasons interrupts 0 - 15 to be the i8295
+ * interrupts even if the hardware uses a different interrupt numbering.
+ */
+void __init arch_init_irq(void)
+{
+	init_i8259_irqs();			/* Integrated i8259  */
+	switch (sni_brd_type) {
+	case SNI_BRD_10:
+	case SNI_BRD_10NEW:
+	case SNI_BRD_TOWER_OASIC:
+	case SNI_BRD_MINITOWER:
+		sni_a20r_irq_init();
+		break;
+
+	case SNI_BRD_PCI_TOWER:
+		sni_pcit_irq_init();
+		break;
+
+	case SNI_BRD_PCI_TOWER_CPLUS:
+		sni_pcit_cplus_irq_init();
+		break;
+
+	case SNI_BRD_RM200:
+		sni_rm200_irq_init();
+		break;
+
+	case SNI_BRD_PCI_MTOWER:
+	case SNI_BRD_PCI_DESKTOP:
+	case SNI_BRD_PCI_MTOWER_CPLUS:
+		sni_pcimt_irq_init();
+		break;
+	}
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sni/pcimt.c b/src/kernel/linux/v4.14/arch/mips/sni/pcimt.c
new file mode 100644
index 0000000..12336c2
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sni/pcimt.c
@@ -0,0 +1,332 @@
+/*
+ * PCIMT specific code
+ *
+ * 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, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/serial_8250.h>
+
+#include <asm/sni.h>
+#include <asm/time.h>
+#include <asm/i8259.h>
+#include <asm/irq_cpu.h>
+
+#define cacheconf (*(volatile unsigned int *)PCIMT_CACHECONF)
+#define invspace (*(volatile unsigned int *)PCIMT_INVSPACE)
+
+static void __init sni_pcimt_sc_init(void)
+{
+	unsigned int scsiz, sc_size;
+
+	scsiz = cacheconf & 7;
+	if (scsiz == 0) {
+		printk("Second level cache is deactivated.\n");
+		return;
+	}
+	if (scsiz >= 6) {
+		printk("Invalid second level cache size configured, "
+		       "deactivating second level cache.\n");
+		cacheconf = 0;
+		return;
+	}
+
+	sc_size = 128 << scsiz;
+	printk("%dkb second level cache detected, deactivating.\n", sc_size);
+	cacheconf = 0;
+}
+
+
+/*
+ * A bit more gossip about the iron we're running on ...
+ */
+static inline void sni_pcimt_detect(void)
+{
+	char boardtype[80];
+	unsigned char csmsr;
+	char *p = boardtype;
+	unsigned int asic;
+
+	csmsr = *(volatile unsigned char *)PCIMT_CSMSR;
+
+	p += sprintf(p, "%s PCI", (csmsr & 0x80) ? "RM200" : "RM300");
+	if ((csmsr & 0x80) == 0)
+		p += sprintf(p, ", board revision %s",
+			     (csmsr & 0x20) ? "D" : "C");
+	asic = csmsr & 0x80;
+	asic = (csmsr & 0x08) ? asic : !asic;
+	p += sprintf(p, ", ASIC PCI Rev %s", asic ? "1.0" : "1.1");
+	printk("%s.\n", boardtype);
+}
+
+#define PORT(_base,_irq)				\
+	{						\
+		.iobase		= _base,		\
+		.irq		= _irq,			\
+		.uartclk	= 1843200,		\
+		.iotype		= UPIO_PORT,		\
+		.flags		= UPF_BOOT_AUTOCONF,	\
+	}
+
+static struct plat_serial8250_port pcimt_data[] = {
+	PORT(0x3f8, 4),
+	PORT(0x2f8, 3),
+	{ },
+};
+
+static struct platform_device pcimt_serial8250_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= pcimt_data,
+	},
+};
+
+static struct resource pcimt_cmos_rsrc[] = {
+	{
+		.start = 0x70,
+		.end   = 0x71,
+		.flags = IORESOURCE_IO
+	},
+	{
+		.start = 8,
+		.end   = 8,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+static struct platform_device pcimt_cmos_device = {
+	.name		= "rtc_cmos",
+	.num_resources	= ARRAY_SIZE(pcimt_cmos_rsrc),
+	.resource	= pcimt_cmos_rsrc
+};
+
+
+static struct resource sni_io_resource = {
+	.start	= 0x00000000UL,
+	.end	= 0x03bfffffUL,
+	.name	= "PCIMT IO MEM",
+	.flags	= IORESOURCE_IO,
+};
+
+static struct resource pcimt_io_resources[] = {
+	{
+		.start	= 0x00,
+		.end	= 0x1f,
+		.name	= "dma1",
+		.flags	= IORESOURCE_BUSY
+	}, {
+		.start	=  0x40,
+		.end	= 0x5f,
+		.name	= "timer",
+		.flags	= IORESOURCE_BUSY
+	}, {
+		.start	=  0x60,
+		.end	= 0x6f,
+		.name	= "keyboard",
+		.flags	= IORESOURCE_BUSY
+	}, {
+		.start	=  0x80,
+		.end	= 0x8f,
+		.name	= "dma page reg",
+		.flags	= IORESOURCE_BUSY
+	}, {
+		.start	=  0xc0,
+		.end	= 0xdf,
+		.name	= "dma2",
+		.flags	= IORESOURCE_BUSY
+	}, {
+		.start	=  0xcfc,
+		.end	= 0xcff,
+		.name	= "PCI config data",
+		.flags	= IORESOURCE_BUSY
+	}
+};
+
+static struct resource pcimt_mem_resources[] = {
+	{
+		/*
+		 * this region should only be 4 bytes long,
+		 * but it's 16MB on all RM300C I've checked
+		 */
+		.start	= 0x1a000000,
+		.end	= 0x1affffff,
+		.name	= "PCI INT ACK",
+		.flags	= IORESOURCE_BUSY
+	}
+};
+
+static struct resource sni_mem_resource = {
+	.start	= 0x18000000UL,
+	.end	= 0x1fbfffffUL,
+	.name	= "PCIMT PCI MEM",
+	.flags	= IORESOURCE_MEM
+};
+
+static void __init sni_pcimt_resource_init(void)
+{
+	int i;
+
+	/* request I/O space for devices used on all i[345]86 PCs */
+	for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++)
+		request_resource(&sni_io_resource, pcimt_io_resources + i);
+	/* request MEM space for devices used on all i[345]86 PCs */
+	for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++)
+		request_resource(&sni_mem_resource, pcimt_mem_resources + i);
+}
+
+extern struct pci_ops sni_pcimt_ops;
+
+#ifdef CONFIG_PCI
+static struct pci_controller sni_controller = {
+	.pci_ops	= &sni_pcimt_ops,
+	.mem_resource	= &sni_mem_resource,
+	.mem_offset	= 0x00000000UL,
+	.io_resource	= &sni_io_resource,
+	.io_offset	= 0x00000000UL,
+	.io_map_base	= SNI_PORT_BASE
+};
+#endif
+
+static void enable_pcimt_irq(struct irq_data *d)
+{
+	unsigned int mask = 1 << (d->irq - PCIMT_IRQ_INT2);
+
+	*(volatile u8 *) PCIMT_IRQSEL |= mask;
+}
+
+void disable_pcimt_irq(struct irq_data *d)
+{
+	unsigned int mask = ~(1 << (d->irq - PCIMT_IRQ_INT2));
+
+	*(volatile u8 *) PCIMT_IRQSEL &= mask;
+}
+
+static struct irq_chip pcimt_irq_type = {
+	.name = "PCIMT",
+	.irq_mask = disable_pcimt_irq,
+	.irq_unmask = enable_pcimt_irq,
+};
+
+/*
+ * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
+ * button interrupts.  Later ...
+ */
+static void pcimt_hwint0(void)
+{
+	panic("Received int0 but no handler yet ...");
+}
+
+/*
+ * hwint 1 deals with EISA and SCSI interrupts,
+ *
+ * The EISA_INT bit in CSITPEND is high active, all others are low active.
+ */
+static void pcimt_hwint1(void)
+{
+	u8 pend = *(volatile char *)PCIMT_CSITPEND;
+	unsigned long flags;
+
+	if (pend & IT_EISA) {
+		int irq;
+		/*
+		 * Note: ASIC PCI's builtin interrupt acknowledge feature is
+		 * broken.  Using it may result in loss of some or all i8259
+		 * interrupts, so don't use PCIMT_INT_ACKNOWLEDGE ...
+		 */
+		irq = i8259_irq();
+		if (unlikely(irq < 0))
+			return;
+
+		do_IRQ(irq);
+	}
+
+	if (!(pend & IT_SCSI)) {
+		flags = read_c0_status();
+		clear_c0_status(ST0_IM);
+		do_IRQ(PCIMT_IRQ_SCSI);
+		write_c0_status(flags);
+	}
+}
+
+/*
+ * hwint 3 should deal with the PCI A - D interrupts,
+ */
+static void pcimt_hwint3(void)
+{
+	u8 pend = *(volatile char *)PCIMT_CSITPEND;
+	int irq;
+
+	pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
+	pend ^= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
+	clear_c0_status(IE_IRQ3);
+	irq = PCIMT_IRQ_INT2 + ffs(pend) - 1;
+	do_IRQ(irq);
+	set_c0_status(IE_IRQ3);
+}
+
+static void sni_pcimt_hwint(void)
+{
+	u32 pending = read_c0_cause() & read_c0_status();
+
+	if (pending & C_IRQ5)
+		do_IRQ(MIPS_CPU_IRQ_BASE + 7);
+	else if (pending & C_IRQ4)
+		do_IRQ(MIPS_CPU_IRQ_BASE + 6);
+	else if (pending & C_IRQ3)
+		pcimt_hwint3();
+	else if (pending & C_IRQ1)
+		pcimt_hwint1();
+	else if (pending & C_IRQ0) {
+		pcimt_hwint0();
+	}
+}
+
+void __init sni_pcimt_irq_init(void)
+{
+	int i;
+
+	*(volatile u8 *) PCIMT_IRQSEL = IT_ETH | IT_EISA;
+	mips_cpu_irq_init();
+	/* Actually we've got more interrupts to handle ...  */
+	for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_SCSI; i++)
+		irq_set_chip_and_handler(i, &pcimt_irq_type, handle_level_irq);
+	sni_hwint = sni_pcimt_hwint;
+	change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ3);
+}
+
+void __init sni_pcimt_init(void)
+{
+	sni_pcimt_detect();
+	sni_pcimt_sc_init();
+	ioport_resource.end = sni_io_resource.end;
+#ifdef CONFIG_PCI
+	PCIBIOS_MIN_IO = 0x9000;
+	register_pci_controller(&sni_controller);
+#endif
+	sni_pcimt_resource_init();
+}
+
+static int __init snirm_pcimt_setup_devinit(void)
+{
+	switch (sni_brd_type) {
+	case SNI_BRD_PCI_MTOWER:
+	case SNI_BRD_PCI_DESKTOP:
+	case SNI_BRD_PCI_MTOWER_CPLUS:
+		platform_device_register(&pcimt_serial8250_device);
+		platform_device_register(&pcimt_cmos_device);
+		break;
+	}
+
+	return 0;
+}
+
+device_initcall(snirm_pcimt_setup_devinit);
diff --git a/src/kernel/linux/v4.14/arch/mips/sni/pcit.c b/src/kernel/linux/v4.14/arch/mips/sni/pcit.c
new file mode 100644
index 0000000..05bb516
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sni/pcit.c
@@ -0,0 +1,291 @@
+/*
+ * PCI Tower specific code
+ *
+ * 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) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/serial_8250.h>
+
+#include <asm/sni.h>
+#include <asm/time.h>
+#include <asm/irq_cpu.h>
+
+
+#define PORT(_base,_irq)				\
+	{						\
+		.iobase		= _base,		\
+		.irq		= _irq,			\
+		.uartclk	= 1843200,		\
+		.iotype		= UPIO_PORT,		\
+		.flags		= UPF_BOOT_AUTOCONF,	\
+	}
+
+static struct plat_serial8250_port pcit_data[] = {
+	PORT(0x3f8, 0),
+	PORT(0x2f8, 3),
+	{ },
+};
+
+static struct platform_device pcit_serial8250_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= pcit_data,
+	},
+};
+
+static struct plat_serial8250_port pcit_cplus_data[] = {
+	PORT(0x3f8, 0),
+	PORT(0x2f8, 3),
+	PORT(0x3e8, 4),
+	PORT(0x2e8, 3),
+	{ },
+};
+
+static struct platform_device pcit_cplus_serial8250_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= pcit_cplus_data,
+	},
+};
+
+static struct resource pcit_cmos_rsrc[] = {
+	{
+		.start = 0x70,
+		.end   = 0x71,
+		.flags = IORESOURCE_IO
+	},
+	{
+		.start = 8,
+		.end   = 8,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+static struct platform_device pcit_cmos_device = {
+	.name		= "rtc_cmos",
+	.num_resources	= ARRAY_SIZE(pcit_cmos_rsrc),
+	.resource	= pcit_cmos_rsrc
+};
+
+static struct platform_device pcit_pcspeaker_pdev = {
+	.name		= "pcspkr",
+	.id		= -1,
+};
+
+static struct resource sni_io_resource = {
+	.start	= 0x00000000UL,
+	.end	= 0x03bfffffUL,
+	.name	= "PCIT IO",
+	.flags	= IORESOURCE_IO,
+};
+
+static struct resource pcit_io_resources[] = {
+	{
+		.start	= 0x00,
+		.end	= 0x1f,
+		.name	= "dma1",
+		.flags	= IORESOURCE_BUSY
+	}, {
+		.start	=  0x40,
+		.end	= 0x5f,
+		.name	= "timer",
+		.flags	= IORESOURCE_BUSY
+	}, {
+		.start	=  0x60,
+		.end	= 0x6f,
+		.name	= "keyboard",
+		.flags	= IORESOURCE_BUSY
+	}, {
+		.start	=  0x80,
+		.end	= 0x8f,
+		.name	= "dma page reg",
+		.flags	= IORESOURCE_BUSY
+	}, {
+		.start	=  0xc0,
+		.end	= 0xdf,
+		.name	= "dma2",
+		.flags	= IORESOURCE_BUSY
+	}, {
+		.start	=  0xcf8,
+		.end	= 0xcfb,
+		.name	= "PCI config addr",
+		.flags	= IORESOURCE_BUSY
+	}, {
+		.start	=  0xcfc,
+		.end	= 0xcff,
+		.name	= "PCI config data",
+		.flags	= IORESOURCE_BUSY
+	}
+};
+
+static void __init sni_pcit_resource_init(void)
+{
+	int i;
+
+	/* request I/O space for devices used on all i[345]86 PCs */
+	for (i = 0; i < ARRAY_SIZE(pcit_io_resources); i++)
+		request_resource(&sni_io_resource, pcit_io_resources + i);
+}
+
+
+extern struct pci_ops sni_pcit_ops;
+
+#ifdef CONFIG_PCI
+static struct resource sni_mem_resource = {
+	.start	= 0x18000000UL,
+	.end	= 0x1fbfffffUL,
+	.name	= "PCIT PCI MEM",
+	.flags	= IORESOURCE_MEM
+};
+
+static struct pci_controller sni_pcit_controller = {
+	.pci_ops	= &sni_pcit_ops,
+	.mem_resource	= &sni_mem_resource,
+	.mem_offset	= 0x00000000UL,
+	.io_resource	= &sni_io_resource,
+	.io_offset	= 0x00000000UL,
+	.io_map_base	= SNI_PORT_BASE
+};
+#endif /* CONFIG_PCI */
+
+static void enable_pcit_irq(struct irq_data *d)
+{
+	u32 mask = 1 << (d->irq - SNI_PCIT_INT_START + 24);
+
+	*(volatile u32 *)SNI_PCIT_INT_REG |= mask;
+}
+
+void disable_pcit_irq(struct irq_data *d)
+{
+	u32 mask = 1 << (d->irq - SNI_PCIT_INT_START + 24);
+
+	*(volatile u32 *)SNI_PCIT_INT_REG &= ~mask;
+}
+
+static struct irq_chip pcit_irq_type = {
+	.name = "PCIT",
+	.irq_mask = disable_pcit_irq,
+	.irq_unmask = enable_pcit_irq,
+};
+
+static void pcit_hwint1(void)
+{
+	u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG;
+	int irq;
+
+	clear_c0_status(IE_IRQ1);
+	irq = ffs((pending >> 16) & 0x7f);
+
+	if (likely(irq > 0))
+		do_IRQ(irq + SNI_PCIT_INT_START - 1);
+	set_c0_status(IE_IRQ1);
+}
+
+static void pcit_hwint0(void)
+{
+	u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG;
+	int irq;
+
+	clear_c0_status(IE_IRQ0);
+	irq = ffs((pending >> 16) & 0x3f);
+
+	if (likely(irq > 0))
+		do_IRQ(irq + SNI_PCIT_INT_START - 1);
+	set_c0_status(IE_IRQ0);
+}
+
+static void sni_pcit_hwint(void)
+{
+	u32 pending = read_c0_cause() & read_c0_status();
+
+	if (pending & C_IRQ1)
+		pcit_hwint1();
+	else if (pending & C_IRQ2)
+		do_IRQ(MIPS_CPU_IRQ_BASE + 4);
+	else if (pending & C_IRQ3)
+		do_IRQ(MIPS_CPU_IRQ_BASE + 5);
+	else if (pending & C_IRQ5)
+		do_IRQ(MIPS_CPU_IRQ_BASE + 7);
+}
+
+static void sni_pcit_hwint_cplus(void)
+{
+	u32 pending = read_c0_cause() & read_c0_status();
+
+	if (pending & C_IRQ0)
+		pcit_hwint0();
+	else if (pending & C_IRQ1)
+		do_IRQ(MIPS_CPU_IRQ_BASE + 3);
+	else if (pending & C_IRQ2)
+		do_IRQ(MIPS_CPU_IRQ_BASE + 4);
+	else if (pending & C_IRQ3)
+		do_IRQ(MIPS_CPU_IRQ_BASE + 5);
+	else if (pending & C_IRQ5)
+		do_IRQ(MIPS_CPU_IRQ_BASE + 7);
+}
+
+void __init sni_pcit_irq_init(void)
+{
+	int i;
+
+	mips_cpu_irq_init();
+	for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
+		irq_set_chip_and_handler(i, &pcit_irq_type, handle_level_irq);
+	*(volatile u32 *)SNI_PCIT_INT_REG = 0;
+	sni_hwint = sni_pcit_hwint;
+	change_c0_status(ST0_IM, IE_IRQ1);
+	setup_irq(SNI_PCIT_INT_START + 6, &sni_isa_irq);
+}
+
+void __init sni_pcit_cplus_irq_init(void)
+{
+	int i;
+
+	mips_cpu_irq_init();
+	for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
+		irq_set_chip_and_handler(i, &pcit_irq_type, handle_level_irq);
+	*(volatile u32 *)SNI_PCIT_INT_REG = 0x40000000;
+	sni_hwint = sni_pcit_hwint_cplus;
+	change_c0_status(ST0_IM, IE_IRQ0);
+	setup_irq(MIPS_CPU_IRQ_BASE + 3, &sni_isa_irq);
+}
+
+void __init sni_pcit_init(void)
+{
+	ioport_resource.end = sni_io_resource.end;
+#ifdef CONFIG_PCI
+	PCIBIOS_MIN_IO = 0x9000;
+	register_pci_controller(&sni_pcit_controller);
+#endif
+	sni_pcit_resource_init();
+}
+
+static int __init snirm_pcit_setup_devinit(void)
+{
+	switch (sni_brd_type) {
+	case SNI_BRD_PCI_TOWER:
+		platform_device_register(&pcit_serial8250_device);
+		platform_device_register(&pcit_cmos_device);
+		platform_device_register(&pcit_pcspeaker_pdev);
+		break;
+
+	case SNI_BRD_PCI_TOWER_CPLUS:
+		platform_device_register(&pcit_cplus_serial8250_device);
+		platform_device_register(&pcit_cmos_device);
+		platform_device_register(&pcit_pcspeaker_pdev);
+		break;
+	}
+	return 0;
+}
+
+device_initcall(snirm_pcit_setup_devinit);
diff --git a/src/kernel/linux/v4.14/arch/mips/sni/reset.c b/src/kernel/linux/v4.14/arch/mips/sni/reset.c
new file mode 100644
index 0000000..66f963d
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sni/reset.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  linux/arch/mips/sni/process.c
+ *
+ *  Reset a SNI machine.
+ */
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/reboot.h>
+#include <asm/sni.h>
+
+/*
+ * This routine reboots the machine by asking the keyboard
+ * controller to pulse the reset-line low. We try that for a while,
+ * and if it doesn't work, we do some other stupid things.
+ */
+static inline void kb_wait(void)
+{
+	int i;
+
+	for (i = 0; i < 0x10000; i++)
+		if ((inb_p(0x64) & 0x02) == 0)
+			break;
+}
+
+/* XXX This ends up at the ARC firmware prompt ...  */
+void sni_machine_restart(char *command)
+{
+	int i;
+
+	/* This does a normal via the keyboard controller like a PC.
+	   We can do that easier ...  */
+	local_irq_disable();
+	for (;;) {
+		for (i = 0; i < 100; i++) {
+			kb_wait();
+			udelay(50);
+			outb_p(0xfe, 0x64);	 /* pulse reset low */
+			udelay(50);
+		}
+	}
+}
+
+void sni_machine_power_off(void)
+{
+	*(volatile unsigned char *)PCIMT_CSWCSM = 0xfd;
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sni/rm200.c b/src/kernel/linux/v4.14/arch/mips/sni/rm200.c
new file mode 100644
index 0000000..160b880
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sni/rm200.c
@@ -0,0 +1,490 @@
+/*
+ * RM200 specific code
+ *
+ * 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) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * i8259 parts ripped out of arch/mips/kernel/i8259.c
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/io.h>
+
+#include <asm/sni.h>
+#include <asm/time.h>
+#include <asm/irq_cpu.h>
+
+#define RM200_I8259A_IRQ_BASE 32
+
+#define MEMPORT(_base,_irq)				\
+	{						\
+		.mapbase	= _base,		\
+		.irq		= _irq,			\
+		.uartclk	= 1843200,		\
+		.iotype		= UPIO_MEM,		\
+		.flags		= UPF_BOOT_AUTOCONF|UPF_IOREMAP, \
+	}
+
+static struct plat_serial8250_port rm200_data[] = {
+	MEMPORT(0x160003f8, RM200_I8259A_IRQ_BASE + 4),
+	MEMPORT(0x160002f8, RM200_I8259A_IRQ_BASE + 3),
+	{ },
+};
+
+static struct platform_device rm200_serial8250_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= rm200_data,
+	},
+};
+
+static struct resource rm200_ds1216_rsrc[] = {
+	{
+		.start = 0x1cd41ffc,
+		.end   = 0x1cd41fff,
+		.flags = IORESOURCE_MEM
+	}
+};
+
+static struct platform_device rm200_ds1216_device = {
+	.name		= "rtc-ds1216",
+	.num_resources	= ARRAY_SIZE(rm200_ds1216_rsrc),
+	.resource	= rm200_ds1216_rsrc
+};
+
+static struct resource snirm_82596_rm200_rsrc[] = {
+	{
+		.start = 0x18000000,
+		.end   = 0x180fffff,
+		.flags = IORESOURCE_MEM
+	},
+	{
+		.start = 0x1b000000,
+		.end   = 0x1b000004,
+		.flags = IORESOURCE_MEM
+	},
+	{
+		.start = 0x1ff00000,
+		.end   = 0x1ff00020,
+		.flags = IORESOURCE_MEM
+	},
+	{
+		.start = 27,
+		.end   = 27,
+		.flags = IORESOURCE_IRQ
+	},
+	{
+		.flags = 0x00
+	}
+};
+
+static struct platform_device snirm_82596_rm200_pdev = {
+	.name		= "snirm_82596",
+	.num_resources	= ARRAY_SIZE(snirm_82596_rm200_rsrc),
+	.resource	= snirm_82596_rm200_rsrc
+};
+
+static struct resource snirm_53c710_rm200_rsrc[] = {
+	{
+		.start = 0x19000000,
+		.end   = 0x190fffff,
+		.flags = IORESOURCE_MEM
+	},
+	{
+		.start = 26,
+		.end   = 26,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+static struct platform_device snirm_53c710_rm200_pdev = {
+	.name		= "snirm_53c710",
+	.num_resources	= ARRAY_SIZE(snirm_53c710_rm200_rsrc),
+	.resource	= snirm_53c710_rm200_rsrc
+};
+
+static int __init snirm_setup_devinit(void)
+{
+	if (sni_brd_type == SNI_BRD_RM200) {
+		platform_device_register(&rm200_serial8250_device);
+		platform_device_register(&rm200_ds1216_device);
+		platform_device_register(&snirm_82596_rm200_pdev);
+		platform_device_register(&snirm_53c710_rm200_pdev);
+		sni_eisa_root_init();
+	}
+	return 0;
+}
+
+device_initcall(snirm_setup_devinit);
+
+/*
+ * RM200 has an ISA and an EISA bus. The iSA bus is only used
+ * for onboard devices and also has twi i8259 PICs. Since these
+ * PICs are no accessible via inb/outb the following code uses
+ * readb/writeb to access them
+ */
+
+static DEFINE_RAW_SPINLOCK(sni_rm200_i8259A_lock);
+#define PIC_CMD	   0x00
+#define PIC_IMR	   0x01
+#define PIC_ISR	   PIC_CMD
+#define PIC_POLL   PIC_ISR
+#define PIC_OCW3   PIC_ISR
+
+/* i8259A PIC related value */
+#define PIC_CASCADE_IR		2
+#define MASTER_ICW4_DEFAULT	0x01
+#define SLAVE_ICW4_DEFAULT	0x01
+
+/*
+ * This contains the irq mask for both 8259A irq controllers,
+ */
+static unsigned int rm200_cached_irq_mask = 0xffff;
+static __iomem u8 *rm200_pic_master;
+static __iomem u8 *rm200_pic_slave;
+
+#define cached_master_mask	(rm200_cached_irq_mask)
+#define cached_slave_mask	(rm200_cached_irq_mask >> 8)
+
+static void sni_rm200_disable_8259A_irq(struct irq_data *d)
+{
+	unsigned int mask, irq = d->irq - RM200_I8259A_IRQ_BASE;
+	unsigned long flags;
+
+	mask = 1 << irq;
+	raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
+	rm200_cached_irq_mask |= mask;
+	if (irq & 8)
+		writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
+	else
+		writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
+	raw_spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
+}
+
+static void sni_rm200_enable_8259A_irq(struct irq_data *d)
+{
+	unsigned int mask, irq = d->irq - RM200_I8259A_IRQ_BASE;
+	unsigned long flags;
+
+	mask = ~(1 << irq);
+	raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
+	rm200_cached_irq_mask &= mask;
+	if (irq & 8)
+		writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
+	else
+		writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
+	raw_spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
+}
+
+static inline int sni_rm200_i8259A_irq_real(unsigned int irq)
+{
+	int value;
+	int irqmask = 1 << irq;
+
+	if (irq < 8) {
+		writeb(0x0B, rm200_pic_master + PIC_CMD);
+		value = readb(rm200_pic_master + PIC_CMD) & irqmask;
+		writeb(0x0A, rm200_pic_master + PIC_CMD);
+		return value;
+	}
+	writeb(0x0B, rm200_pic_slave + PIC_CMD); /* ISR register */
+	value = readb(rm200_pic_slave + PIC_CMD) & (irqmask >> 8);
+	writeb(0x0A, rm200_pic_slave + PIC_CMD);
+	return value;
+}
+
+/*
+ * Careful! The 8259A is a fragile beast, it pretty
+ * much _has_ to be done exactly like this (mask it
+ * first, _then_ send the EOI, and the order of EOI
+ * to the two 8259s is important!
+ */
+void sni_rm200_mask_and_ack_8259A(struct irq_data *d)
+{
+	unsigned int irqmask, irq = d->irq - RM200_I8259A_IRQ_BASE;
+	unsigned long flags;
+
+	irqmask = 1 << irq;
+	raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
+	/*
+	 * Lightweight spurious IRQ detection. We do not want
+	 * to overdo spurious IRQ handling - it's usually a sign
+	 * of hardware problems, so we only do the checks we can
+	 * do without slowing down good hardware unnecessarily.
+	 *
+	 * Note that IRQ7 and IRQ15 (the two spurious IRQs
+	 * usually resulting from the 8259A-1|2 PICs) occur
+	 * even if the IRQ is masked in the 8259A. Thus we
+	 * can check spurious 8259A IRQs without doing the
+	 * quite slow i8259A_irq_real() call for every IRQ.
+	 * This does not cover 100% of spurious interrupts,
+	 * but should be enough to warn the user that there
+	 * is something bad going on ...
+	 */
+	if (rm200_cached_irq_mask & irqmask)
+		goto spurious_8259A_irq;
+	rm200_cached_irq_mask |= irqmask;
+
+handle_real_irq:
+	if (irq & 8) {
+		readb(rm200_pic_slave + PIC_IMR);
+		writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
+		writeb(0x60+(irq & 7), rm200_pic_slave + PIC_CMD);
+		writeb(0x60+PIC_CASCADE_IR, rm200_pic_master + PIC_CMD);
+	} else {
+		readb(rm200_pic_master + PIC_IMR);
+		writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
+		writeb(0x60+irq, rm200_pic_master + PIC_CMD);
+	}
+	raw_spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
+	return;
+
+spurious_8259A_irq:
+	/*
+	 * this is the slow path - should happen rarely.
+	 */
+	if (sni_rm200_i8259A_irq_real(irq))
+		/*
+		 * oops, the IRQ _is_ in service according to the
+		 * 8259A - not spurious, go handle it.
+		 */
+		goto handle_real_irq;
+
+	{
+		static int spurious_irq_mask;
+		/*
+		 * At this point we can be sure the IRQ is spurious,
+		 * let's ACK and report it. [once per IRQ]
+		 */
+		if (!(spurious_irq_mask & irqmask)) {
+			printk(KERN_DEBUG
+			       "spurious RM200 8259A interrupt: IRQ%d.\n", irq);
+			spurious_irq_mask |= irqmask;
+		}
+		atomic_inc(&irq_err_count);
+		/*
+		 * Theoretically we do not have to handle this IRQ,
+		 * but in Linux this does not cause problems and is
+		 * simpler for us.
+		 */
+		goto handle_real_irq;
+	}
+}
+
+static struct irq_chip sni_rm200_i8259A_chip = {
+	.name		= "RM200-XT-PIC",
+	.irq_mask	= sni_rm200_disable_8259A_irq,
+	.irq_unmask	= sni_rm200_enable_8259A_irq,
+	.irq_mask_ack	= sni_rm200_mask_and_ack_8259A,
+};
+
+/*
+ * Do the traditional i8259 interrupt polling thing.  This is for the few
+ * cases where no better interrupt acknowledge method is available and we
+ * absolutely must touch the i8259.
+ */
+static inline int sni_rm200_i8259_irq(void)
+{
+	int irq;
+
+	raw_spin_lock(&sni_rm200_i8259A_lock);
+
+	/* Perform an interrupt acknowledge cycle on controller 1. */
+	writeb(0x0C, rm200_pic_master + PIC_CMD);	/* prepare for poll */
+	irq = readb(rm200_pic_master + PIC_CMD) & 7;
+	if (irq == PIC_CASCADE_IR) {
+		/*
+		 * Interrupt is cascaded so perform interrupt
+		 * acknowledge on controller 2.
+		 */
+		writeb(0x0C, rm200_pic_slave + PIC_CMD); /* prepare for poll */
+		irq = (readb(rm200_pic_slave + PIC_CMD) & 7) + 8;
+	}
+
+	if (unlikely(irq == 7)) {
+		/*
+		 * This may be a spurious interrupt.
+		 *
+		 * Read the interrupt status register (ISR). If the most
+		 * significant bit is not set then there is no valid
+		 * interrupt.
+		 */
+		writeb(0x0B, rm200_pic_master + PIC_ISR); /* ISR register */
+		if (~readb(rm200_pic_master + PIC_ISR) & 0x80)
+			irq = -1;
+	}
+
+	raw_spin_unlock(&sni_rm200_i8259A_lock);
+
+	return likely(irq >= 0) ? irq + RM200_I8259A_IRQ_BASE : irq;
+}
+
+void sni_rm200_init_8259A(void)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
+
+	writeb(0xff, rm200_pic_master + PIC_IMR);
+	writeb(0xff, rm200_pic_slave + PIC_IMR);
+
+	writeb(0x11, rm200_pic_master + PIC_CMD);
+	writeb(0, rm200_pic_master + PIC_IMR);
+	writeb(1U << PIC_CASCADE_IR, rm200_pic_master + PIC_IMR);
+	writeb(MASTER_ICW4_DEFAULT, rm200_pic_master + PIC_IMR);
+	writeb(0x11, rm200_pic_slave + PIC_CMD);
+	writeb(8, rm200_pic_slave + PIC_IMR);
+	writeb(PIC_CASCADE_IR, rm200_pic_slave + PIC_IMR);
+	writeb(SLAVE_ICW4_DEFAULT, rm200_pic_slave + PIC_IMR);
+	udelay(100);		/* wait for 8259A to initialize */
+
+	writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
+	writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
+
+	raw_spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
+}
+
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+static struct irqaction sni_rm200_irq2 = {
+	.handler = no_action,
+	.name = "cascade",
+	.flags = IRQF_NO_THREAD,
+};
+
+static struct resource sni_rm200_pic1_resource = {
+	.name = "onboard ISA pic1",
+	.start = 0x16000020,
+	.end = 0x16000023,
+	.flags = IORESOURCE_BUSY
+};
+
+static struct resource sni_rm200_pic2_resource = {
+	.name = "onboard ISA pic2",
+	.start = 0x160000a0,
+	.end = 0x160000a3,
+	.flags = IORESOURCE_BUSY
+};
+
+/* ISA irq handler */
+static irqreturn_t sni_rm200_i8259A_irq_handler(int dummy, void *p)
+{
+	int irq;
+
+	irq = sni_rm200_i8259_irq();
+	if (unlikely(irq < 0))
+		return IRQ_NONE;
+
+	do_IRQ(irq);
+	return IRQ_HANDLED;
+}
+
+struct irqaction sni_rm200_i8259A_irq = {
+	.handler = sni_rm200_i8259A_irq_handler,
+	.name = "onboard ISA",
+	.flags = IRQF_SHARED
+};
+
+void __init sni_rm200_i8259_irqs(void)
+{
+	int i;
+
+	rm200_pic_master = ioremap_nocache(0x16000020, 4);
+	if (!rm200_pic_master)
+		return;
+	rm200_pic_slave = ioremap_nocache(0x160000a0, 4);
+	if (!rm200_pic_slave) {
+		iounmap(rm200_pic_master);
+		return;
+	}
+
+	insert_resource(&iomem_resource, &sni_rm200_pic1_resource);
+	insert_resource(&iomem_resource, &sni_rm200_pic2_resource);
+
+	sni_rm200_init_8259A();
+
+	for (i = RM200_I8259A_IRQ_BASE; i < RM200_I8259A_IRQ_BASE + 16; i++)
+		irq_set_chip_and_handler(i, &sni_rm200_i8259A_chip,
+					 handle_level_irq);
+
+	setup_irq(RM200_I8259A_IRQ_BASE + PIC_CASCADE_IR, &sni_rm200_irq2);
+}
+
+
+#define SNI_RM200_INT_STAT_REG	CKSEG1ADDR(0xbc000000)
+#define SNI_RM200_INT_ENA_REG	CKSEG1ADDR(0xbc080000)
+
+#define SNI_RM200_INT_START  24
+#define SNI_RM200_INT_END    28
+
+static void enable_rm200_irq(struct irq_data *d)
+{
+	unsigned int mask = 1 << (d->irq - SNI_RM200_INT_START);
+
+	*(volatile u8 *)SNI_RM200_INT_ENA_REG &= ~mask;
+}
+
+void disable_rm200_irq(struct irq_data *d)
+{
+	unsigned int mask = 1 << (d->irq - SNI_RM200_INT_START);
+
+	*(volatile u8 *)SNI_RM200_INT_ENA_REG |= mask;
+}
+
+static struct irq_chip rm200_irq_type = {
+	.name = "RM200",
+	.irq_mask = disable_rm200_irq,
+	.irq_unmask = enable_rm200_irq,
+};
+
+static void sni_rm200_hwint(void)
+{
+	u32 pending = read_c0_cause() & read_c0_status();
+	u8 mask;
+	u8 stat;
+	int irq;
+
+	if (pending & C_IRQ5)
+		do_IRQ(MIPS_CPU_IRQ_BASE + 7);
+	else if (pending & C_IRQ0) {
+		clear_c0_status(IE_IRQ0);
+		mask = *(volatile u8 *)SNI_RM200_INT_ENA_REG ^ 0x1f;
+		stat = *(volatile u8 *)SNI_RM200_INT_STAT_REG ^ 0x14;
+		irq = ffs(stat & mask & 0x1f);
+
+		if (likely(irq > 0))
+			do_IRQ(irq + SNI_RM200_INT_START - 1);
+		set_c0_status(IE_IRQ0);
+	}
+}
+
+void __init sni_rm200_irq_init(void)
+{
+	int i;
+
+	* (volatile u8 *)SNI_RM200_INT_ENA_REG = 0x1f;
+
+	sni_rm200_i8259_irqs();
+	mips_cpu_irq_init();
+	/* Actually we've got more interrupts to handle ...  */
+	for (i = SNI_RM200_INT_START; i <= SNI_RM200_INT_END; i++)
+		irq_set_chip_and_handler(i, &rm200_irq_type, handle_level_irq);
+	sni_hwint = sni_rm200_hwint;
+	change_c0_status(ST0_IM, IE_IRQ0);
+	setup_irq(SNI_RM200_INT_START + 0, &sni_rm200_i8259A_irq);
+	setup_irq(SNI_RM200_INT_START + 1, &sni_isa_irq);
+}
+
+void __init sni_rm200_init(void)
+{
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sni/setup.c b/src/kernel/linux/v4.14/arch/mips/sni/setup.c
new file mode 100644
index 0000000..efad85c
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sni/setup.c
@@ -0,0 +1,263 @@
+/*
+ * Setup pointers to hardware-dependent routines.
+ *
+ * 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, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+#include <linux/eisa.h>
+#include <linux/init.h>
+#include <linux/export.h>
+#include <linux/console.h>
+#include <linux/fb.h>
+#include <linux/screen_info.h>
+
+#ifdef CONFIG_FW_ARC
+#include <asm/fw/arc/types.h>
+#include <asm/sgialib.h>
+#endif
+
+#ifdef CONFIG_FW_SNIPROM
+#include <asm/mipsprom.h>
+#endif
+
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/io.h>
+#include <asm/reboot.h>
+#include <asm/sni.h>
+
+unsigned int sni_brd_type;
+EXPORT_SYMBOL(sni_brd_type);
+
+extern void sni_machine_restart(char *command);
+extern void sni_machine_power_off(void);
+
+static void __init sni_display_setup(void)
+{
+#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) && defined(CONFIG_FW_ARC)
+	struct screen_info *si = &screen_info;
+	DISPLAY_STATUS *di;
+
+	di = ArcGetDisplayStatus(1);
+
+	if (di) {
+		si->orig_x		= di->CursorXPosition;
+		si->orig_y		= di->CursorYPosition;
+		si->orig_video_cols	= di->CursorMaxXPosition;
+		si->orig_video_lines	= di->CursorMaxYPosition;
+		si->orig_video_isVGA	= VIDEO_TYPE_VGAC;
+		si->orig_video_points	= 16;
+	}
+#endif
+}
+
+static void __init sni_console_setup(void)
+{
+#ifndef CONFIG_FW_ARC
+	char *ctype;
+	char *cdev;
+	char *baud;
+	int port;
+	static char options[8] __initdata;
+
+	cdev = prom_getenv("console_dev");
+	if (strncmp(cdev, "tty", 3) == 0) {
+		ctype = prom_getenv("console");
+		switch (*ctype) {
+		default:
+		case 'l':
+			port = 0;
+			baud = prom_getenv("lbaud");
+			break;
+		case 'r':
+			port = 1;
+			baud = prom_getenv("rbaud");
+			break;
+		}
+		if (baud)
+			strcpy(options, baud);
+		if (strncmp(cdev, "tty552", 6) == 0)
+			add_preferred_console("ttyS", port,
+					      baud ? options : NULL);
+		else
+			add_preferred_console("ttySC", port,
+					      baud ? options : NULL);
+	}
+#endif
+}
+
+#ifdef DEBUG
+static void __init sni_idprom_dump(void)
+{
+	int	i;
+
+	pr_debug("SNI IDProm dump:\n");
+	for (i = 0; i < 256; i++) {
+		if (i%16 == 0)
+			pr_debug("%04x ", i);
+
+		printk("%02x ", *(unsigned char *) (SNI_IDPROM_BASE + i));
+
+		if (i % 16 == 15)
+			printk("\n");
+	}
+}
+#endif
+
+void __init plat_mem_setup(void)
+{
+	int cputype;
+
+	set_io_port_base(SNI_PORT_BASE);
+//	ioport_resource.end = sni_io_resource.end;
+
+	/*
+	 * Setup (E)ISA I/O memory access stuff
+	 */
+#ifdef CONFIG_EISA
+	EISA_bus = 1;
+#endif
+
+	sni_brd_type = *(unsigned char *)SNI_IDPROM_BRDTYPE;
+	cputype = *(unsigned char *)SNI_IDPROM_CPUTYPE;
+	switch (sni_brd_type) {
+	case SNI_BRD_TOWER_OASIC:
+		switch (cputype) {
+		case SNI_CPU_M8030:
+			system_type = "RM400-330";
+			break;
+		case SNI_CPU_M8031:
+			system_type = "RM400-430";
+			break;
+		case SNI_CPU_M8037:
+			system_type = "RM400-530";
+			break;
+		case SNI_CPU_M8034:
+			system_type = "RM400-730";
+			break;
+		default:
+			system_type = "RM400-xxx";
+			break;
+		}
+		break;
+	case SNI_BRD_MINITOWER:
+		switch (cputype) {
+		case SNI_CPU_M8021:
+		case SNI_CPU_M8043:
+			system_type = "RM400-120";
+			break;
+		case SNI_CPU_M8040:
+			system_type = "RM400-220";
+			break;
+		case SNI_CPU_M8053:
+			system_type = "RM400-225";
+			break;
+		case SNI_CPU_M8050:
+			system_type = "RM400-420";
+			break;
+		default:
+			system_type = "RM400-xxx";
+			break;
+		}
+		break;
+	case SNI_BRD_PCI_TOWER:
+		system_type = "RM400-Cxx";
+		break;
+	case SNI_BRD_RM200:
+		system_type = "RM200-xxx";
+		break;
+	case SNI_BRD_PCI_MTOWER:
+		system_type = "RM300-Cxx";
+		break;
+	case SNI_BRD_PCI_DESKTOP:
+		switch (read_c0_prid() & PRID_IMP_MASK) {
+		case PRID_IMP_R4600:
+		case PRID_IMP_R4700:
+			system_type = "RM200-C20";
+			break;
+		case PRID_IMP_R5000:
+			system_type = "RM200-C40";
+			break;
+		default:
+			system_type = "RM200-Cxx";
+			break;
+		}
+		break;
+	case SNI_BRD_PCI_TOWER_CPLUS:
+		system_type = "RM400-Exx";
+		break;
+	case SNI_BRD_PCI_MTOWER_CPLUS:
+		system_type = "RM300-Exx";
+		break;
+	}
+	pr_debug("Found SNI brdtype %02x name %s\n", sni_brd_type, system_type);
+
+#ifdef DEBUG
+	sni_idprom_dump();
+#endif
+
+	switch (sni_brd_type) {
+	case SNI_BRD_10:
+	case SNI_BRD_10NEW:
+	case SNI_BRD_TOWER_OASIC:
+	case SNI_BRD_MINITOWER:
+		sni_a20r_init();
+		break;
+
+	case SNI_BRD_PCI_TOWER:
+	case SNI_BRD_PCI_TOWER_CPLUS:
+		sni_pcit_init();
+		break;
+
+	case SNI_BRD_RM200:
+		sni_rm200_init();
+		break;
+
+	case SNI_BRD_PCI_MTOWER:
+	case SNI_BRD_PCI_DESKTOP:
+	case SNI_BRD_PCI_MTOWER_CPLUS:
+		sni_pcimt_init();
+		break;
+	}
+
+	_machine_restart = sni_machine_restart;
+	pm_power_off = sni_machine_power_off;
+
+	sni_display_setup();
+	sni_console_setup();
+}
+
+#ifdef CONFIG_PCI
+
+#include <linux/pci.h>
+#include <video/vga.h>
+#include <video/cirrus.h>
+
+static void quirk_cirrus_ram_size(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	/*
+	 * firmware doesn't set the ram size correct, so we
+	 * need to do it here, otherwise we get screen corruption
+	 * on older Cirrus chips
+	 */
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	if ((cmd & (PCI_COMMAND_IO|PCI_COMMAND_MEMORY))
+		== (PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) {
+		vga_wseq(NULL, CL_SEQR6, 0x12); /* unlock all extension registers */
+		vga_wseq(NULL, CL_SEQRF, 0x18);
+	}
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5434_8,
+			quirk_cirrus_ram_size);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5436,
+			quirk_cirrus_ram_size);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446,
+			quirk_cirrus_ram_size);
+#endif
diff --git a/src/kernel/linux/v4.14/arch/mips/sni/time.c b/src/kernel/linux/v4.14/arch/mips/sni/time.c
new file mode 100644
index 0000000..0eb7d1e
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sni/time.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/types.h>
+#include <linux/i8253.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+#include <linux/time.h>
+#include <linux/clockchips.h>
+
+#include <asm/sni.h>
+#include <asm/time.h>
+
+#define SNI_CLOCK_TICK_RATE	3686400
+#define SNI_COUNTER2_DIV	64
+#define SNI_COUNTER0_DIV	((SNI_CLOCK_TICK_RATE / SNI_COUNTER2_DIV) / HZ)
+
+static int a20r_set_periodic(struct clock_event_device *evt)
+{
+	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34;
+	wmb();
+	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV;
+	wmb();
+	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV >> 8;
+	wmb();
+
+	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4;
+	wmb();
+	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV;
+	wmb();
+	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV >> 8;
+	wmb();
+	return 0;
+}
+
+static struct clock_event_device a20r_clockevent_device = {
+	.name			= "a20r-timer",
+	.features		= CLOCK_EVT_FEAT_PERIODIC,
+
+	/* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
+
+	.rating			= 300,
+	.irq			= SNI_A20R_IRQ_TIMER,
+	.set_state_periodic	= a20r_set_periodic,
+};
+
+static irqreturn_t a20r_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *cd = dev_id;
+
+	*(volatile u8 *)A20R_PT_TIM0_ACK = 0;
+	wmb();
+
+	cd->event_handler(cd);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction a20r_irqaction = {
+	.handler	= a20r_interrupt,
+	.flags		= IRQF_PERCPU | IRQF_TIMER,
+	.name		= "a20r-timer",
+};
+
+/*
+ * a20r platform uses 2 counters to divide the input frequency.
+ * Counter 2 output is connected to Counter 0 & 1 input.
+ */
+static void __init sni_a20r_timer_setup(void)
+{
+	struct clock_event_device *cd = &a20r_clockevent_device;
+	struct irqaction *action = &a20r_irqaction;
+	unsigned int cpu = smp_processor_id();
+
+	cd->cpumask		= cpumask_of(cpu);
+	clockevents_register_device(cd);
+	action->dev_id = cd;
+	setup_irq(SNI_A20R_IRQ_TIMER, &a20r_irqaction);
+}
+
+#define SNI_8254_TICK_RATE	  1193182UL
+
+#define SNI_8254_TCSAMP_COUNTER	  ((SNI_8254_TICK_RATE / HZ) + 255)
+
+static __init unsigned long dosample(void)
+{
+	u32 ct0, ct1;
+	volatile u8 msb;
+
+	/* Start the counter. */
+	outb_p(0x34, 0x43);
+	outb_p(SNI_8254_TCSAMP_COUNTER & 0xff, 0x40);
+	outb(SNI_8254_TCSAMP_COUNTER >> 8, 0x40);
+
+	/* Get initial counter invariant */
+	ct0 = read_c0_count();
+
+	/* Latch and spin until top byte of counter0 is zero */
+	do {
+		outb(0x00, 0x43);
+		(void) inb(0x40);
+		msb = inb(0x40);
+		ct1 = read_c0_count();
+	} while (msb);
+
+	/* Stop the counter. */
+	outb(0x38, 0x43);
+	/*
+	 * Return the difference, this is how far the r4k counter increments
+	 * for every 1/HZ seconds. We round off the nearest 1 MHz of master
+	 * clock (= 1000000 / HZ / 2).
+	 */
+	/*return (ct1 - ct0 + (500000/HZ/2)) / (500000/HZ) * (500000/HZ);*/
+	return (ct1 - ct0) / (500000/HZ) * (500000/HZ);
+}
+
+/*
+ * Here we need to calibrate the cycle counter to at least be close.
+ */
+void __init plat_time_init(void)
+{
+	unsigned long r4k_ticks[3];
+	unsigned long r4k_tick;
+
+	/*
+	 * Figure out the r4k offset, the algorithm is very simple and works in
+	 * _all_ cases as long as the 8254 counter register itself works ok (as
+	 * an interrupt driving timer it does not because of bug, this is why
+	 * we are using the onchip r4k counter/compare register to serve this
+	 * purpose, but for r4k_offset calculation it will work ok for us).
+	 * There are other very complicated ways of performing this calculation
+	 * but this one works just fine so I am not going to futz around. ;-)
+	 */
+	printk(KERN_INFO "Calibrating system timer... ");
+	dosample();	/* Prime cache. */
+	dosample();	/* Prime cache. */
+	/* Zero is NOT an option. */
+	do {
+		r4k_ticks[0] = dosample();
+	} while (!r4k_ticks[0]);
+	do {
+		r4k_ticks[1] = dosample();
+	} while (!r4k_ticks[1]);
+
+	if (r4k_ticks[0] != r4k_ticks[1]) {
+		printk("warning: timer counts differ, retrying... ");
+		r4k_ticks[2] = dosample();
+		if (r4k_ticks[2] == r4k_ticks[0]
+		    || r4k_ticks[2] == r4k_ticks[1])
+			r4k_tick = r4k_ticks[2];
+		else {
+			printk("disagreement, using average... ");
+			r4k_tick = (r4k_ticks[0] + r4k_ticks[1]
+				   + r4k_ticks[2]) / 3;
+		}
+	} else
+		r4k_tick = r4k_ticks[0];
+
+	printk("%d [%d.%04d MHz CPU]\n", (int) r4k_tick,
+		(int) (r4k_tick / (500000 / HZ)),
+		(int) (r4k_tick % (500000 / HZ)));
+
+	mips_hpt_frequency = r4k_tick * HZ;
+
+	switch (sni_brd_type) {
+	case SNI_BRD_10:
+	case SNI_BRD_10NEW:
+	case SNI_BRD_TOWER_OASIC:
+	case SNI_BRD_MINITOWER:
+		sni_a20r_timer_setup();
+		break;
+	}
+	setup_pit_timer();
+}
+
+void read_persistent_clock(struct timespec *ts)
+{
+	ts->tv_sec = -1;
+	ts->tv_nsec = 0;
+}