[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/Kconfig b/src/kernel/linux/v4.14/arch/mips/sibyte/Kconfig
new file mode 100644
index 0000000..f4dbce2
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/Kconfig
@@ -0,0 +1,168 @@
+# SPDX-License-Identifier: GPL-2.0
+config SIBYTE_SB1250
+	bool
+	select CEVT_SB1250
+	select CSRC_SB1250
+	select HW_HAS_PCI
+	select IRQ_MIPS_CPU
+	select SIBYTE_ENABLE_LDT_IF_PCI
+	select SIBYTE_HAS_ZBUS_PROFILING
+	select SIBYTE_SB1xxx_SOC
+	select SYS_SUPPORTS_SMP
+
+config SIBYTE_BCM1120
+	bool
+	select CEVT_SB1250
+	select CSRC_SB1250
+	select IRQ_MIPS_CPU
+	select SIBYTE_BCM112X
+	select SIBYTE_HAS_ZBUS_PROFILING
+	select SIBYTE_SB1xxx_SOC
+
+config SIBYTE_BCM1125
+	bool
+	select CEVT_SB1250
+	select CSRC_SB1250
+	select HW_HAS_PCI
+	select IRQ_MIPS_CPU
+	select SIBYTE_BCM112X
+	select SIBYTE_HAS_ZBUS_PROFILING
+	select SIBYTE_SB1xxx_SOC
+
+config SIBYTE_BCM1125H
+	bool
+	select CEVT_SB1250
+	select CSRC_SB1250
+	select HW_HAS_PCI
+	select IRQ_MIPS_CPU
+	select SIBYTE_BCM112X
+	select SIBYTE_ENABLE_LDT_IF_PCI
+	select SIBYTE_HAS_ZBUS_PROFILING
+	select SIBYTE_SB1xxx_SOC
+
+config SIBYTE_BCM112X
+	bool
+	select CEVT_SB1250
+	select CSRC_SB1250
+	select IRQ_MIPS_CPU
+	select SIBYTE_SB1xxx_SOC
+	select SIBYTE_HAS_ZBUS_PROFILING
+
+config SIBYTE_BCM1x80
+	bool
+	select CEVT_BCM1480
+	select CSRC_BCM1480
+	select HW_HAS_PCI
+	select IRQ_MIPS_CPU
+	select SIBYTE_HAS_ZBUS_PROFILING
+	select SIBYTE_SB1xxx_SOC
+	select SYS_SUPPORTS_SMP
+
+config SIBYTE_BCM1x55
+	bool
+	select CEVT_BCM1480
+	select CSRC_BCM1480
+	select HW_HAS_PCI
+	select IRQ_MIPS_CPU
+	select SIBYTE_SB1xxx_SOC
+	select SIBYTE_HAS_ZBUS_PROFILING
+	select SYS_SUPPORTS_SMP
+
+config SIBYTE_SB1xxx_SOC
+	bool
+	select DMA_COHERENT
+	select IRQ_MIPS_CPU
+	select SWAP_IO_SPACE
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select SYS_SUPPORTS_64BIT_KERNEL
+	select FW_CFE
+	select SYS_HAS_EARLY_PRINTK
+
+choice
+	prompt "SiByte SOC Stepping"
+	depends on SIBYTE_SB1xxx_SOC
+
+config CPU_SB1_PASS_2_1250
+	bool "1250 An"
+	depends on SIBYTE_SB1250
+	select CPU_SB1_PASS_2
+	help
+	  Also called BCM1250 Pass 2
+
+config CPU_SB1_PASS_2_2
+	bool "1250 Bn"
+	depends on SIBYTE_SB1250
+	select CPU_HAS_PREFETCH
+	help
+	  Also called BCM1250 Pass 2.2
+
+config CPU_SB1_PASS_4
+	bool "1250 Cn"
+	depends on SIBYTE_SB1250
+	select CPU_HAS_PREFETCH
+	help
+	  Also called BCM1250 Pass 3
+
+config CPU_SB1_PASS_2_112x
+	bool "112x Hybrid"
+	depends on SIBYTE_BCM112X
+	select CPU_SB1_PASS_2
+
+config CPU_SB1_PASS_3
+	bool "112x An"
+	depends on SIBYTE_BCM112X
+	select CPU_HAS_PREFETCH
+
+endchoice
+
+config CPU_SB1_PASS_2
+	bool
+
+config SIBYTE_HAS_LDT
+	bool
+
+config SIBYTE_ENABLE_LDT_IF_PCI
+	bool
+	select SIBYTE_HAS_LDT if PCI
+
+config SB1_CEX_ALWAYS_FATAL
+	bool "All cache exceptions considered fatal (no recovery attempted)"
+	depends on SIBYTE_SB1xxx_SOC
+
+config SB1_CERR_STALL
+	bool "Stall (rather than panic) on fatal cache error"
+	depends on SIBYTE_SB1xxx_SOC
+
+config SIBYTE_CFE_CONSOLE
+	bool "Use firmware console"
+	depends on SIBYTE_SB1xxx_SOC
+	help
+	  Use the CFE API's console write routines during boot.  Other console
+	  options (VT console, sb1250 duart console, etc.) should not be
+	  configured.
+
+config SIBYTE_BUS_WATCHER
+	bool "Support for Bus Watcher statistics"
+	depends on SIBYTE_SB1xxx_SOC && \
+		(SIBYTE_BCM112X || SIBYTE_SB1250 || \
+		 SIBYTE_BCM1x55 || SIBYTE_BCM1x80)
+	help
+	  Handle and keep statistics on the bus error interrupts (COR_ECC,
+	  BAD_ECC, IO_BUS).
+
+config SIBYTE_BW_TRACE
+	bool "Capture bus trace before bus error"
+	depends on SIBYTE_BUS_WATCHER
+	help
+	  Run a continuous bus trace, dumping the raw data as soon as
+	  a ZBbus error is detected.  Cannot work if ZBbus profiling
+	  is turned on, and also will interfere with JTAG-based trace
+	  buffer activity.  Raw buffer data is dumped to console, and
+	  must be processed off-line.
+
+config SIBYTE_TBPROF
+	tristate "Support for ZBbus profiling"
+	depends on SIBYTE_HAS_ZBUS_PROFILING
+
+config SIBYTE_HAS_ZBUS_PROFILING
+	bool
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/Makefile b/src/kernel/linux/v4.14/arch/mips/sibyte/Makefile
new file mode 100644
index 0000000..d015c4d
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/Makefile
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Sibyte SB1250 / BCM1480 family of SOCs
+#
+obj-$(CONFIG_SIBYTE_BCM112X)	+= sb1250/
+obj-$(CONFIG_SIBYTE_BCM112X)	+= common/
+obj-$(CONFIG_SIBYTE_SB1250)	+= sb1250/
+obj-$(CONFIG_SIBYTE_SB1250)	+= common/
+obj-$(CONFIG_SIBYTE_BCM1x55)	+= bcm1480/
+obj-$(CONFIG_SIBYTE_BCM1x55)	+= common/
+obj-$(CONFIG_SIBYTE_BCM1x80)	+= bcm1480/
+obj-$(CONFIG_SIBYTE_BCM1x80)	+= common/
+
+#
+# Sibyte BCM91120x (Carmel) board
+# Sibyte BCM91120C (CRhine) board
+# Sibyte BCM91125C (CRhone) board
+# Sibyte BCM91125E (Rhone) board
+# Sibyte SWARM board
+# Sibyte BCM91x80 (BigSur) board
+#
+obj-$(CONFIG_SIBYTE_CARMEL)	+= swarm/
+obj-$(CONFIG_SIBYTE_CRHINE)	+= swarm/
+obj-$(CONFIG_SIBYTE_CRHONE)	+= swarm/
+obj-$(CONFIG_SIBYTE_RHONE)	+= swarm/
+obj-$(CONFIG_SIBYTE_SENTOSA)	+= swarm/
+obj-$(CONFIG_SIBYTE_SWARM)	+= swarm/
+obj-$(CONFIG_SIBYTE_BIGSUR)	+= swarm/
+obj-$(CONFIG_SIBYTE_LITTLESUR)	+= swarm/
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/Platform b/src/kernel/linux/v4.14/arch/mips/sibyte/Platform
new file mode 100644
index 0000000..af11733
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/Platform
@@ -0,0 +1,44 @@
+#
+# These are all rather similar so we consider them a single platform
+#
+platform-$(CONFIG_SIBYTE_BCM112X)	+= sibyte/
+platform-$(CONFIG_SIBYTE_SB1250)	+= sibyte/
+platform-$(CONFIG_SIBYTE_BCM1x55)	+= sibyte/
+platform-$(CONFIG_SIBYTE_BCM1x80)	+= sibyte/
+
+#
+# Sibyte SB1250 / BCM1480 family of SOCs
+#
+cflags-$(CONFIG_SIBYTE_BCM112X) +=					\
+		-I$(srctree)/arch/mips/include/asm/mach-sibyte		\
+		-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
+
+cflags-$(CONFIG_SIBYTE_SB1250)	+=					\
+		-I$(srctree)/arch/mips/include/asm/mach-sibyte		\
+		-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
+
+cflags-$(CONFIG_SIBYTE_BCM1x55) +=					\
+		-I$(srctree)/arch/mips/include/asm/mach-sibyte		\
+		-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
+
+cflags-$(CONFIG_SIBYTE_BCM1x80) +=					\
+		-I$(srctree)/arch/mips/include/asm/mach-sibyte		\
+		-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
+
+#
+# Sibyte BCM91120x (Carmel) board
+# Sibyte BCM91120C (CRhine) board
+# Sibyte BCM91125C (CRhone) board
+# Sibyte BCM91125E (Rhone) board
+# Sibyte BCM91250A (SWARM) board
+# Sibyte BCM91250C2 (LittleSur) board
+# Sibyte BCM91x80 (BigSur) board
+#
+load-$(CONFIG_SIBYTE_CARMEL)	:= 0xffffffff80100000
+load-$(CONFIG_SIBYTE_CRHINE)	:= 0xffffffff80100000
+load-$(CONFIG_SIBYTE_CRHONE)	:= 0xffffffff80100000
+load-$(CONFIG_SIBYTE_RHONE)	:= 0xffffffff80100000
+load-$(CONFIG_SIBYTE_SENTOSA)	:= 0xffffffff80100000
+load-$(CONFIG_SIBYTE_SWARM)	:= 0xffffffff80100000
+load-$(CONFIG_SIBYTE_BIGSUR)	:= 0xffffffff80100000
+load-$(CONFIG_SIBYTE_LITTLESUR) := 0xffffffff80100000
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/Makefile b/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/Makefile
new file mode 100644
index 0000000..cdc4c56
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/Makefile
@@ -0,0 +1,3 @@
+obj-y := setup.o irq.o time.o
+
+obj-$(CONFIG_SMP)			+= smp.o
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/irq.c b/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/irq.c
new file mode 100644
index 0000000..373fbbc
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/irq.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2000,2001,2002,2003,2004 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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/errno.h>
+#include <asm/irq_regs.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+
+#include <asm/sibyte/bcm1480_regs.h>
+#include <asm/sibyte/bcm1480_int.h>
+#include <asm/sibyte/bcm1480_scd.h>
+
+#include <asm/sibyte/sb1250_uart.h>
+#include <asm/sibyte/sb1250.h>
+
+/*
+ * These are the routines that handle all the low level interrupt stuff.
+ * Actions handled here are: initialization of the interrupt map, requesting of
+ * interrupt lines by handlers, dispatching if interrupts to handlers, probing
+ * for interrupt lines
+ */
+
+#ifdef CONFIG_PCI
+extern unsigned long ht_eoi_space;
+#endif
+
+/* Store the CPU id (not the logical number) */
+int bcm1480_irq_owner[BCM1480_NR_IRQS];
+
+static DEFINE_RAW_SPINLOCK(bcm1480_imr_lock);
+
+void bcm1480_mask_irq(int cpu, int irq)
+{
+	unsigned long flags, hl_spacing;
+	u64 cur_ints;
+
+	raw_spin_lock_irqsave(&bcm1480_imr_lock, flags);
+	hl_spacing = 0;
+	if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) {
+		hl_spacing = BCM1480_IMR_HL_SPACING;
+		irq -= BCM1480_NR_IRQS_HALF;
+	}
+	cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
+	cur_ints |= (((u64) 1) << irq);
+	____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
+	raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
+}
+
+void bcm1480_unmask_irq(int cpu, int irq)
+{
+	unsigned long flags, hl_spacing;
+	u64 cur_ints;
+
+	raw_spin_lock_irqsave(&bcm1480_imr_lock, flags);
+	hl_spacing = 0;
+	if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) {
+		hl_spacing = BCM1480_IMR_HL_SPACING;
+		irq -= BCM1480_NR_IRQS_HALF;
+	}
+	cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
+	cur_ints &= ~(((u64) 1) << irq);
+	____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));
+	raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
+}
+
+#ifdef CONFIG_SMP
+static int bcm1480_set_affinity(struct irq_data *d, const struct cpumask *mask,
+				bool force)
+{
+	unsigned int irq_dirty, irq = d->irq;
+	int i = 0, old_cpu, cpu, int_on, k;
+	u64 cur_ints;
+	unsigned long flags;
+
+	i = cpumask_first_and(mask, cpu_online_mask);
+
+	/* Convert logical CPU to physical CPU */
+	cpu = cpu_logical_map(i);
+
+	/* Protect against other affinity changers and IMR manipulation */
+	raw_spin_lock_irqsave(&bcm1480_imr_lock, flags);
+
+	/* Swizzle each CPU's IMR (but leave the IP selection alone) */
+	old_cpu = bcm1480_irq_owner[irq];
+	irq_dirty = irq;
+	if ((irq_dirty >= BCM1480_NR_IRQS_HALF) && (irq_dirty <= BCM1480_NR_IRQS)) {
+		irq_dirty -= BCM1480_NR_IRQS_HALF;
+	}
+
+	for (k=0; k<2; k++) { /* Loop through high and low interrupt mask register */
+		cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(old_cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
+		int_on = !(cur_ints & (((u64) 1) << irq_dirty));
+		if (int_on) {
+			/* If it was on, mask it */
+			cur_ints |= (((u64) 1) << irq_dirty);
+			____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(old_cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
+		}
+		bcm1480_irq_owner[irq] = cpu;
+		if (int_on) {
+			/* unmask for the new CPU */
+			cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
+			cur_ints &= ~(((u64) 1) << irq_dirty);
+			____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
+		}
+	}
+	raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
+
+	return 0;
+}
+#endif
+
+
+/*****************************************************************************/
+
+static void disable_bcm1480_irq(struct irq_data *d)
+{
+	unsigned int irq = d->irq;
+
+	bcm1480_mask_irq(bcm1480_irq_owner[irq], irq);
+}
+
+static void enable_bcm1480_irq(struct irq_data *d)
+{
+	unsigned int irq = d->irq;
+
+	bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq);
+}
+
+
+static void ack_bcm1480_irq(struct irq_data *d)
+{
+	unsigned int irq_dirty, irq = d->irq;
+	u64 pending;
+	int k;
+
+	/*
+	 * If the interrupt was an HT interrupt, now is the time to
+	 * clear it.  NOTE: we assume the HT bridge was set up to
+	 * deliver the interrupts to all CPUs (which makes affinity
+	 * changing easier for us)
+	 */
+	irq_dirty = irq;
+	if ((irq_dirty >= BCM1480_NR_IRQS_HALF) && (irq_dirty <= BCM1480_NR_IRQS)) {
+		irq_dirty -= BCM1480_NR_IRQS_HALF;
+	}
+	for (k=0; k<2; k++) { /* Loop through high and low LDT interrupts */
+		pending = __raw_readq(IOADDR(A_BCM1480_IMR_REGISTER(bcm1480_irq_owner[irq],
+						R_BCM1480_IMR_LDT_INTERRUPT_H + (k*BCM1480_IMR_HL_SPACING))));
+		pending &= ((u64)1 << (irq_dirty));
+		if (pending) {
+#ifdef CONFIG_SMP
+			int i;
+			for (i=0; i<NR_CPUS; i++) {
+				/*
+				 * Clear for all CPUs so an affinity switch
+				 * doesn't find an old status
+				 */
+				__raw_writeq(pending, IOADDR(A_BCM1480_IMR_REGISTER(cpu_logical_map(i),
+								R_BCM1480_IMR_LDT_INTERRUPT_CLR_H + (k*BCM1480_IMR_HL_SPACING))));
+			}
+#else
+			__raw_writeq(pending, IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_LDT_INTERRUPT_CLR_H + (k*BCM1480_IMR_HL_SPACING))));
+#endif
+
+			/*
+			 * Generate EOI.  For Pass 1 parts, EOI is a nop.  For
+			 * Pass 2, the LDT world may be edge-triggered, but
+			 * this EOI shouldn't hurt.  If they are
+			 * level-sensitive, the EOI is required.
+			 */
+#ifdef CONFIG_PCI
+			if (ht_eoi_space)
+				*(uint32_t *)(ht_eoi_space+(irq<<16)+(7<<2)) = 0;
+#endif
+		}
+	}
+	bcm1480_mask_irq(bcm1480_irq_owner[irq], irq);
+}
+
+static struct irq_chip bcm1480_irq_type = {
+	.name = "BCM1480-IMR",
+	.irq_mask_ack = ack_bcm1480_irq,
+	.irq_mask = disable_bcm1480_irq,
+	.irq_unmask = enable_bcm1480_irq,
+#ifdef CONFIG_SMP
+	.irq_set_affinity = bcm1480_set_affinity
+#endif
+};
+
+void __init init_bcm1480_irqs(void)
+{
+	int i;
+
+	for (i = 0; i < BCM1480_NR_IRQS; i++) {
+		irq_set_chip_and_handler(i, &bcm1480_irq_type,
+					 handle_level_irq);
+		bcm1480_irq_owner[i] = 0;
+	}
+}
+
+/*
+ *  init_IRQ is called early in the boot sequence from init/main.c.  It
+ *  is responsible for setting up the interrupt mapper and installing the
+ *  handler that will be responsible for dispatching interrupts to the
+ *  "right" place.
+ */
+/*
+ * For now, map all interrupts to IP[2].  We could save
+ * some cycles by parceling out system interrupts to different
+ * IP lines, but keep it simple for bringup.  We'll also direct
+ * all interrupts to a single CPU; we should probably route
+ * PCI and LDT to one cpu and everything else to the other
+ * to balance the load a bit.
+ *
+ * On the second cpu, everything is set to IP5, which is
+ * ignored, EXCEPT the mailbox interrupt.  That one is
+ * set to IP[2] so it is handled.  This is needed so we
+ * can do cross-cpu function calls, as required by SMP
+ */
+
+#define IMR_IP2_VAL	K_BCM1480_INT_MAP_I0
+#define IMR_IP3_VAL	K_BCM1480_INT_MAP_I1
+#define IMR_IP4_VAL	K_BCM1480_INT_MAP_I2
+#define IMR_IP5_VAL	K_BCM1480_INT_MAP_I3
+#define IMR_IP6_VAL	K_BCM1480_INT_MAP_I4
+
+void __init arch_init_irq(void)
+{
+	unsigned int i, cpu;
+	u64 tmp;
+	unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
+		STATUSF_IP1 | STATUSF_IP0;
+
+	/* Default everything to IP2 */
+	/* Start with _high registers which has no bit 0 interrupt source */
+	for (i = 1; i < BCM1480_NR_IRQS_HALF; i++) {	/* was I0 */
+		for (cpu = 0; cpu < 4; cpu++) {
+			__raw_writeq(IMR_IP2_VAL,
+				     IOADDR(A_BCM1480_IMR_REGISTER(cpu,
+								   R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (i << 3)));
+		}
+	}
+
+	/* Now do _low registers */
+	for (i = 0; i < BCM1480_NR_IRQS_HALF; i++) {
+		for (cpu = 0; cpu < 4; cpu++) {
+			__raw_writeq(IMR_IP2_VAL,
+				     IOADDR(A_BCM1480_IMR_REGISTER(cpu,
+								   R_BCM1480_IMR_INTERRUPT_MAP_BASE_L) + (i << 3)));
+		}
+	}
+
+	init_bcm1480_irqs();
+
+	/*
+	 * Map the high 16 bits of mailbox_0 registers to IP[3], for
+	 * inter-cpu messages
+	 */
+	/* Was I1 */
+	for (cpu = 0; cpu < 4; cpu++) {
+		__raw_writeq(IMR_IP3_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) +
+						 (K_BCM1480_INT_MBOX_0_0 << 3)));
+	}
+
+
+	/* Clear the mailboxes.	 The firmware may leave them dirty */
+	for (cpu = 0; cpu < 4; cpu++) {
+		__raw_writeq(0xffffffffffffffffULL,
+			     IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_MAILBOX_0_CLR_CPU)));
+		__raw_writeq(0xffffffffffffffffULL,
+			     IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_MAILBOX_1_CLR_CPU)));
+	}
+
+
+	/* Mask everything except the high 16 bit of mailbox_0 registers for all cpus */
+	tmp = ~((u64) 0) ^ ( (((u64) 1) << K_BCM1480_INT_MBOX_0_0));
+	for (cpu = 0; cpu < 4; cpu++) {
+		__raw_writeq(tmp, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MASK_H)));
+	}
+	tmp = ~((u64) 0);
+	for (cpu = 0; cpu < 4; cpu++) {
+		__raw_writeq(tmp, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MASK_L)));
+	}
+
+	/*
+	 * Note that the timer interrupts are also mapped, but this is
+	 * done in bcm1480_time_init().	 Also, the profiling driver
+	 * does its own management of IP7.
+	 */
+
+	/* Enable necessary IPs, disable the rest */
+	change_c0_status(ST0_IM, imask);
+}
+
+extern void bcm1480_mailbox_interrupt(void);
+
+static inline void dispatch_ip2(void)
+{
+	unsigned long long mask_h, mask_l;
+	unsigned int cpu = smp_processor_id();
+	unsigned long base;
+
+	/*
+	 * Default...we've hit an IP[2] interrupt, which means we've got to
+	 * check the 1480 interrupt registers to figure out what to do.	 Need
+	 * to detect which CPU we're on, now that smp_affinity is supported.
+	 */
+	base = A_BCM1480_IMR_MAPPER(cpu);
+	mask_h = __raw_readq(
+		IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
+	mask_l = __raw_readq(
+		IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
+
+	if (mask_h) {
+		if (mask_h ^ 1)
+			do_IRQ(fls64(mask_h) - 1);
+		else if (mask_l)
+			do_IRQ(63 + fls64(mask_l));
+	}
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+	unsigned int cpu = smp_processor_id();
+	unsigned int pending;
+
+	pending = read_c0_cause() & read_c0_status();
+
+	if (pending & CAUSEF_IP4)
+		do_IRQ(K_BCM1480_INT_TIMER_0 + cpu);
+#ifdef CONFIG_SMP
+	else if (pending & CAUSEF_IP3)
+		bcm1480_mailbox_interrupt();
+#endif
+
+	else if (pending & CAUSEF_IP2)
+		dispatch_ip2();
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/setup.c b/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/setup.c
new file mode 100644
index 0000000..2035aae
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/setup.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2000,2001,2002,2003,2004 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.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/reboot.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250.h>
+
+#include <asm/sibyte/bcm1480_regs.h>
+#include <asm/sibyte/bcm1480_scd.h>
+#include <asm/sibyte/sb1250_scd.h>
+
+unsigned int sb1_pass;
+unsigned int soc_pass;
+unsigned int soc_type;
+EXPORT_SYMBOL(soc_type);
+unsigned int periph_rev;
+EXPORT_SYMBOL_GPL(periph_rev);
+unsigned int zbbus_mhz;
+EXPORT_SYMBOL(zbbus_mhz);
+
+static unsigned int part_type;
+
+static char *soc_str;
+static char *pass_str;
+
+static int __init setup_bcm1x80_bcm1x55(void)
+{
+	int ret = 0;
+
+	switch (soc_pass) {
+	case K_SYS_REVISION_BCM1480_S0:
+		periph_rev = 1;
+		pass_str = "S0 (pass1)";
+		break;
+	case K_SYS_REVISION_BCM1480_A1:
+		periph_rev = 1;
+		pass_str = "A1 (pass1)";
+		break;
+	case K_SYS_REVISION_BCM1480_A2:
+		periph_rev = 1;
+		pass_str = "A2 (pass1)";
+		break;
+	case K_SYS_REVISION_BCM1480_A3:
+		periph_rev = 1;
+		pass_str = "A3 (pass1)";
+		break;
+	case K_SYS_REVISION_BCM1480_B0:
+		periph_rev = 1;
+		pass_str = "B0 (pass2)";
+		break;
+	default:
+		printk("Unknown %s rev %x\n", soc_str, soc_pass);
+		periph_rev = 1;
+		pass_str = "Unknown Revision";
+		break;
+	}
+
+	return ret;
+}
+
+/* Setup code likely to be common to all SiByte platforms */
+
+static int __init sys_rev_decode(void)
+{
+	int ret = 0;
+
+	switch (soc_type) {
+	case K_SYS_SOC_TYPE_BCM1x80:
+		if (part_type == K_SYS_PART_BCM1480)
+		    soc_str = "BCM1480";
+		else if (part_type == K_SYS_PART_BCM1280)
+		    soc_str = "BCM1280";
+		else
+		    soc_str = "BCM1x80";
+		ret = setup_bcm1x80_bcm1x55();
+		break;
+
+	case K_SYS_SOC_TYPE_BCM1x55:
+		if (part_type == K_SYS_PART_BCM1455)
+		    soc_str = "BCM1455";
+		else if (part_type == K_SYS_PART_BCM1255)
+		    soc_str = "BCM1255";
+		else
+		    soc_str = "BCM1x55";
+		ret = setup_bcm1x80_bcm1x55();
+		break;
+
+	default:
+		printk("Unknown part type %x\n", part_type);
+		ret = 1;
+		break;
+	}
+
+	return ret;
+}
+
+void __init bcm1480_setup(void)
+{
+	uint64_t sys_rev;
+	int plldiv;
+
+	sb1_pass = read_c0_prid() & PRID_REV_MASK;
+	sys_rev = __raw_readq(IOADDR(A_SCD_SYSTEM_REVISION));
+	soc_type = SYS_SOC_TYPE(sys_rev);
+	part_type = G_SYS_PART(sys_rev);
+	soc_pass = G_SYS_REVISION(sys_rev);
+
+	if (sys_rev_decode()) {
+		printk("Restart after failure to identify SiByte chip\n");
+		machine_restart(NULL);
+	}
+
+	plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG)));
+	zbbus_mhz = ((plldiv >> 1) * 50) + ((plldiv & 1) * 25);
+
+	printk("Broadcom SiByte %s %s @ %d MHz (SB-1A rev %d)\n",
+		    soc_str, pass_str, zbbus_mhz * 2, sb1_pass);
+	printk("Board type: %s\n", get_system_type());
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/smp.c b/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/smp.c
new file mode 100644
index 0000000..90c9d12
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/smp.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2001,2002,2004 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.
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/sched/task_stack.h>
+
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/fw/cfe/cfe_api.h>
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/bcm1480_regs.h>
+#include <asm/sibyte/bcm1480_int.h>
+
+/*
+ * These are routines for dealing with the bcm1480 smp capabilities
+ * independent of board/firmware
+ */
+
+static void *mailbox_0_set_regs[] = {
+	IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
+	IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
+	IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
+	IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
+};
+
+static void *mailbox_0_clear_regs[] = {
+	IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
+	IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
+	IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
+	IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
+};
+
+static void *mailbox_0_regs[] = {
+	IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
+	IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
+	IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
+	IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
+};
+
+/*
+ * SMP init and finish on secondary CPUs
+ */
+void bcm1480_smp_init(void)
+{
+	unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
+		STATUSF_IP1 | STATUSF_IP0;
+
+	/* Set interrupt mask, but don't enable */
+	change_c0_status(ST0_IM, imask);
+}
+
+/*
+ * These are routines for dealing with the sb1250 smp capabilities
+ * independent of board/firmware
+ */
+
+/*
+ * Simple enough; everything is set up, so just poke the appropriate mailbox
+ * register, and we should be set
+ */
+static void bcm1480_send_ipi_single(int cpu, unsigned int action)
+{
+	__raw_writeq((((u64)action)<< 48), mailbox_0_set_regs[cpu]);
+}
+
+static void bcm1480_send_ipi_mask(const struct cpumask *mask,
+				  unsigned int action)
+{
+	unsigned int i;
+
+	for_each_cpu(i, mask)
+		bcm1480_send_ipi_single(i, action);
+}
+
+/*
+ * Code to run on secondary just after probing the CPU
+ */
+static void bcm1480_init_secondary(void)
+{
+	extern void bcm1480_smp_init(void);
+
+	bcm1480_smp_init();
+}
+
+/*
+ * Do any tidying up before marking online and running the idle
+ * loop
+ */
+static void bcm1480_smp_finish(void)
+{
+	extern void sb1480_clockevent_init(void);
+
+	sb1480_clockevent_init();
+	local_irq_enable();
+}
+
+/*
+ * Setup the PC, SP, and GP of a secondary processor and start it
+ * running!
+ */
+static int bcm1480_boot_secondary(int cpu, struct task_struct *idle)
+{
+	int retval;
+
+	retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap,
+			       __KSTK_TOS(idle),
+			       (unsigned long)task_thread_info(idle), 0);
+	if (retval != 0)
+		printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval);
+	return retval;
+}
+
+/*
+ * Use CFE to find out how many CPUs are available, setting up
+ * cpu_possible_mask and the logical/physical mappings.
+ * XXXKW will the boot CPU ever not be physical 0?
+ *
+ * Common setup before any secondaries are started
+ */
+static void __init bcm1480_smp_setup(void)
+{
+	int i, num;
+
+	init_cpu_possible(cpumask_of(0));
+	__cpu_number_map[0] = 0;
+	__cpu_logical_map[0] = 0;
+
+	for (i = 1, num = 0; i < NR_CPUS; i++) {
+		if (cfe_cpu_stop(i) == 0) {
+			set_cpu_possible(i, true);
+			__cpu_number_map[i] = ++num;
+			__cpu_logical_map[num] = i;
+		}
+	}
+	printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
+}
+
+static void __init bcm1480_prepare_cpus(unsigned int max_cpus)
+{
+}
+
+const struct plat_smp_ops bcm1480_smp_ops = {
+	.send_ipi_single	= bcm1480_send_ipi_single,
+	.send_ipi_mask		= bcm1480_send_ipi_mask,
+	.init_secondary		= bcm1480_init_secondary,
+	.smp_finish		= bcm1480_smp_finish,
+	.boot_secondary		= bcm1480_boot_secondary,
+	.smp_setup		= bcm1480_smp_setup,
+	.prepare_cpus		= bcm1480_prepare_cpus,
+};
+
+void bcm1480_mailbox_interrupt(void)
+{
+	int cpu = smp_processor_id();
+	int irq = K_BCM1480_INT_MBOX_0_0;
+	unsigned int action;
+
+	kstat_incr_irq_this_cpu(irq);
+	/* Load the mailbox register to figure out what we're supposed to do */
+	action = (__raw_readq(mailbox_0_regs[cpu]) >> 48) & 0xffff;
+
+	/* Clear the mailbox to clear the interrupt */
+	__raw_writeq(((u64)action)<<48, mailbox_0_clear_regs[cpu]);
+
+	if (action & SMP_RESCHEDULE_YOURSELF)
+		scheduler_ipi();
+
+	if (action & SMP_CALL_FUNCTION) {
+		irq_enter();
+		generic_smp_call_function_interrupt();
+		irq_exit();
+	}
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/time.c b/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/time.c
new file mode 100644
index 0000000..1680a68
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/bcm1480/time.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2000,2001,2004 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.
+ */
+#include <linux/init.h>
+
+extern void sb1480_clockevent_init(void);
+extern void sb1480_clocksource_init(void);
+
+void __init plat_time_init(void)
+{
+	sb1480_clocksource_init();
+	sb1480_clockevent_init();
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/common/Makefile b/src/kernel/linux/v4.14/arch/mips/sibyte/common/Makefile
new file mode 100644
index 0000000..b3d6bf2
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/common/Makefile
@@ -0,0 +1,4 @@
+obj-y := cfe.o
+obj-$(CONFIG_SIBYTE_BUS_WATCHER)	+= bus_watcher.o
+obj-$(CONFIG_SIBYTE_CFE_CONSOLE)	+= cfe_console.o
+obj-$(CONFIG_SIBYTE_TBPROF)		+= sb_tbprof.o
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/common/bus_watcher.c b/src/kernel/linux/v4.14/arch/mips/sibyte/common/bus_watcher.c
new file mode 100644
index 0000000..a4e5599
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/common/bus_watcher.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2002,2003 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.
+ */
+
+/*
+ * The Bus Watcher monitors internal bus transactions and maintains
+ * counts of transactions with error status, logging details and
+ * causing one of several interrupts.  This driver provides a handler
+ * for those interrupts which aggregates the counts (to avoid
+ * saturating the 8-bit counters) and provides a presence in
+ * /proc/bus_watcher if PROC_FS is on.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
+
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_int.h>
+#include <asm/sibyte/sb1250_scd.h>
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+#include <asm/sibyte/bcm1480_regs.h>
+#endif
+
+
+struct bw_stats_struct {
+	uint64_t status;
+	uint32_t l2_err;
+	uint32_t memio_err;
+	int status_printed;
+	unsigned long l2_cor_d;
+	unsigned long l2_bad_d;
+	unsigned long l2_cor_t;
+	unsigned long l2_bad_t;
+	unsigned long mem_cor_d;
+	unsigned long mem_bad_d;
+	unsigned long bus_error;
+} bw_stats;
+
+
+static void print_summary(uint32_t status, uint32_t l2_err,
+			  uint32_t memio_err)
+{
+	printk("Bus watcher error counters: %08x %08x\n", l2_err, memio_err);
+	printk("\nLast recorded signature:\n");
+	printk("Request %02x from %d, answered by %d with Dcode %d\n",
+	       (unsigned int)(G_SCD_BERR_TID(status) & 0x3f),
+	       (int)(G_SCD_BERR_TID(status) >> 6),
+	       (int)G_SCD_BERR_RID(status),
+	       (int)G_SCD_BERR_DCODE(status));
+}
+
+/*
+ * check_bus_watcher is exported for use in situations where we want
+ * to see the most recent status of the bus watcher, which might have
+ * already been destructively read out of the registers.
+ *
+ * notes: this is currently used by the cache error handler
+ *	  should provide locking against the interrupt handler
+ */
+void check_bus_watcher(void)
+{
+	u32 status, l2_err, memio_err;
+
+#if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250)
+	/* Use non-destructive register */
+	status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS_DEBUG));
+#elif defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+	/* Use non-destructive register */
+	/* Same as 1250 except BUS_ERR_STATUS_DEBUG is in a different place. */
+	status = csr_in32(IOADDR(A_BCM1480_BUS_ERR_STATUS_DEBUG));
+#else
+#error bus watcher being built for unknown Sibyte SOC!
+#endif
+	if (!(status & 0x7fffffff)) {
+		printk("Using last values reaped by bus watcher driver\n");
+		status = bw_stats.status;
+		l2_err = bw_stats.l2_err;
+		memio_err = bw_stats.memio_err;
+	} else {
+		l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS));
+		memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
+	}
+	if (status & ~(1UL << 31))
+		print_summary(status, l2_err, memio_err);
+	else
+		printk("Bus watcher indicates no error\n");
+}
+
+#ifdef CONFIG_PROC_FS
+
+/* For simplicity, I want to assume a single read is required each
+   time */
+static int bw_proc_show(struct seq_file *m, void *v)
+{
+	struct bw_stats_struct *stats = m->private;
+
+	seq_puts(m, "SiByte Bus Watcher statistics\n");
+	seq_puts(m, "-----------------------------\n");
+	seq_printf(m, "L2-d-cor %8ld\nL2-d-bad %8ld\n",
+		   stats->l2_cor_d, stats->l2_bad_d);
+	seq_printf(m, "L2-t-cor %8ld\nL2-t-bad %8ld\n",
+		   stats->l2_cor_t, stats->l2_bad_t);
+	seq_printf(m, "MC-d-cor %8ld\nMC-d-bad %8ld\n",
+		   stats->mem_cor_d, stats->mem_bad_d);
+	seq_printf(m, "IO-err   %8ld\n", stats->bus_error);
+	seq_puts(m, "\nLast recorded signature:\n");
+	seq_printf(m, "Request %02x from %d, answered by %d with Dcode %d\n",
+		   (unsigned int)(G_SCD_BERR_TID(stats->status) & 0x3f),
+		   (int)(G_SCD_BERR_TID(stats->status) >> 6),
+		   (int)G_SCD_BERR_RID(stats->status),
+		   (int)G_SCD_BERR_DCODE(stats->status));
+	/* XXXKW indicate multiple errors between printings, or stats
+	   collection (or both)? */
+	if (stats->status & M_SCD_BERR_MULTERRS)
+		seq_puts(m, "Multiple errors observed since last check.\n");
+	if (stats->status_printed) {
+		seq_puts(m, "(no change since last printing)\n");
+	} else {
+		stats->status_printed = 1;
+	}
+
+	return 0;
+}
+
+static int bw_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, bw_proc_show, PDE_DATA(inode));
+}
+
+static const struct file_operations bw_proc_fops = {
+	.open		= bw_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void create_proc_decoder(struct bw_stats_struct *stats)
+{
+	struct proc_dir_entry *ent;
+
+	ent = proc_create_data("bus_watcher", S_IWUSR | S_IRUGO, NULL,
+			       &bw_proc_fops, stats);
+	if (!ent) {
+		printk(KERN_INFO "Unable to initialize bus_watcher /proc entry\n");
+		return;
+	}
+}
+
+#endif /* CONFIG_PROC_FS */
+
+/*
+ * sibyte_bw_int - handle bus watcher interrupts and accumulate counts
+ *
+ * notes: possible re-entry due to multiple sources
+ *	  should check/indicate saturation
+ */
+static irqreturn_t sibyte_bw_int(int irq, void *data)
+{
+	struct bw_stats_struct *stats = data;
+	unsigned long cntr;
+#ifdef CONFIG_SIBYTE_BW_TRACE
+	int i;
+#endif
+
+#ifdef CONFIG_SIBYTE_BW_TRACE
+	csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
+	csr_out32(M_SCD_TRACE_CFG_START_READ, IOADDR(A_SCD_TRACE_CFG));
+
+	for (i=0; i<256*6; i++)
+		printk("%016llx\n",
+		       (long long)__raw_readq(IOADDR(A_SCD_TRACE_READ)));
+
+	csr_out32(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
+	csr_out32(M_SCD_TRACE_CFG_START, IOADDR(A_SCD_TRACE_CFG));
+#endif
+
+	/* Destructive read, clears register and interrupt */
+	stats->status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
+	stats->status_printed = 0;
+
+	stats->l2_err = cntr = csr_in32(IOADDR(A_BUS_L2_ERRORS));
+	stats->l2_cor_d += G_SCD_L2ECC_CORR_D(cntr);
+	stats->l2_bad_d += G_SCD_L2ECC_BAD_D(cntr);
+	stats->l2_cor_t += G_SCD_L2ECC_CORR_T(cntr);
+	stats->l2_bad_t += G_SCD_L2ECC_BAD_T(cntr);
+	csr_out32(0, IOADDR(A_BUS_L2_ERRORS));
+
+	stats->memio_err = cntr = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
+	stats->mem_cor_d += G_SCD_MEM_ECC_CORR(cntr);
+	stats->mem_bad_d += G_SCD_MEM_ECC_BAD(cntr);
+	stats->bus_error += G_SCD_MEM_BUSERR(cntr);
+	csr_out32(0, IOADDR(A_BUS_MEM_IO_ERRORS));
+
+	return IRQ_HANDLED;
+}
+
+int __init sibyte_bus_watcher(void)
+{
+	memset(&bw_stats, 0, sizeof(struct bw_stats_struct));
+	bw_stats.status_printed = 1;
+
+	if (request_irq(K_INT_BAD_ECC, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
+		printk("Failed to register bus watcher BAD_ECC irq\n");
+		return -1;
+	}
+	if (request_irq(K_INT_COR_ECC, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
+		free_irq(K_INT_BAD_ECC, &bw_stats);
+		printk("Failed to register bus watcher COR_ECC irq\n");
+		return -1;
+	}
+	if (request_irq(K_INT_IO_BUS, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
+		free_irq(K_INT_BAD_ECC, &bw_stats);
+		free_irq(K_INT_COR_ECC, &bw_stats);
+		printk("Failed to register bus watcher IO_BUS irq\n");
+		return -1;
+	}
+
+#ifdef CONFIG_PROC_FS
+	create_proc_decoder(&bw_stats);
+#endif
+
+#ifdef CONFIG_SIBYTE_BW_TRACE
+	csr_out32((M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE |
+		   K_SCD_TRSEQ_TRIGGER_ALL),
+		  IOADDR(A_SCD_TRACE_SEQUENCE_0));
+	csr_out32(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
+	csr_out32(M_SCD_TRACE_CFG_START, IOADDR(A_SCD_TRACE_CFG));
+#endif
+
+	return 0;
+}
+
+device_initcall(sibyte_bus_watcher);
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/common/cfe.c b/src/kernel/linux/v4.14/arch/mips/sibyte/common/cfe.c
new file mode 100644
index 0000000..1153992
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/common/cfe.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/bootmem.h>
+#include <linux/pm.h>
+#include <linux/smp.h>
+
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
+#include <asm/sibyte/board.h>
+#include <asm/smp-ops.h>
+
+#include <asm/fw/cfe/cfe_api.h>
+#include <asm/fw/cfe/cfe_error.h>
+
+/* Max ram addressable in 32-bit segments */
+#ifdef CONFIG_64BIT
+#define MAX_RAM_SIZE (~0ULL)
+#else
+#ifdef CONFIG_HIGHMEM
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+#define MAX_RAM_SIZE (~0ULL)
+#else
+#define MAX_RAM_SIZE (0xffffffffULL)
+#endif
+#else
+#define MAX_RAM_SIZE (0x1fffffffULL)
+#endif
+#endif
+
+#define SIBYTE_MAX_MEM_REGIONS 8
+phys_addr_t board_mem_region_addrs[SIBYTE_MAX_MEM_REGIONS];
+phys_addr_t board_mem_region_sizes[SIBYTE_MAX_MEM_REGIONS];
+unsigned int board_mem_region_count;
+
+int cfe_cons_handle;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern unsigned long initrd_start, initrd_end;
+#endif
+
+static void __noreturn cfe_linux_exit(void *arg)
+{
+	int warm = *(int *)arg;
+
+	if (smp_processor_id()) {
+		static int reboot_smp;
+
+		/* Don't repeat the process from another CPU */
+		if (!reboot_smp) {
+			/* Get CPU 0 to do the cfe_exit */
+			reboot_smp = 1;
+			smp_call_function(cfe_linux_exit, arg, 0);
+		}
+	} else {
+		printk("Passing control back to CFE...\n");
+		cfe_exit(warm, 0);
+		printk("cfe_exit returned??\n");
+	}
+	while (1);
+}
+
+static void __noreturn cfe_linux_restart(char *command)
+{
+	static const int zero;
+
+	cfe_linux_exit((void *)&zero);
+}
+
+static void __noreturn cfe_linux_halt(void)
+{
+	static const int one = 1;
+
+	cfe_linux_exit((void *)&one);
+}
+
+static __init void prom_meminit(void)
+{
+	u64 addr, size, type; /* regardless of PHYS_ADDR_T_64BIT */
+	int mem_flags = 0;
+	unsigned int idx;
+	int rd_flag;
+#ifdef CONFIG_BLK_DEV_INITRD
+	unsigned long initrd_pstart;
+	unsigned long initrd_pend;
+
+	initrd_pstart = CPHYSADDR(initrd_start);
+	initrd_pend = CPHYSADDR(initrd_end);
+	if (initrd_start &&
+	    ((initrd_pstart > MAX_RAM_SIZE)
+	     || (initrd_pend > MAX_RAM_SIZE))) {
+		panic("initrd out of addressable memory");
+	}
+
+#endif /* INITRD */
+
+	for (idx = 0; cfe_enummem(idx, mem_flags, &addr, &size, &type) != CFE_ERR_NOMORE;
+	     idx++) {
+		rd_flag = 0;
+		if (type == CFE_MI_AVAILABLE) {
+			/*
+			 * See if this block contains (any portion of) the
+			 * ramdisk
+			 */
+#ifdef CONFIG_BLK_DEV_INITRD
+			if (initrd_start) {
+				if ((initrd_pstart > addr) &&
+				    (initrd_pstart < (addr + size))) {
+					add_memory_region(addr,
+							  initrd_pstart - addr,
+							  BOOT_MEM_RAM);
+					rd_flag = 1;
+				}
+				if ((initrd_pend > addr) &&
+				    (initrd_pend < (addr + size))) {
+					add_memory_region(initrd_pend,
+						(addr + size) - initrd_pend,
+						 BOOT_MEM_RAM);
+					rd_flag = 1;
+				}
+			}
+#endif
+			if (!rd_flag) {
+				if (addr > MAX_RAM_SIZE)
+					continue;
+				if (addr+size > MAX_RAM_SIZE)
+					size = MAX_RAM_SIZE - (addr+size) + 1;
+				/*
+				 * memcpy/__copy_user prefetch, which
+				 * will cause a bus error for
+				 * KSEG/KUSEG addrs not backed by RAM.
+				 * Hence, reserve some padding for the
+				 * prefetch distance.
+				 */
+				if (size > 512)
+					size -= 512;
+				add_memory_region(addr, size, BOOT_MEM_RAM);
+			}
+			board_mem_region_addrs[board_mem_region_count] = addr;
+			board_mem_region_sizes[board_mem_region_count] = size;
+			board_mem_region_count++;
+			if (board_mem_region_count ==
+			    SIBYTE_MAX_MEM_REGIONS) {
+				/*
+				 * Too many regions.  Need to configure more
+				 */
+				while(1);
+			}
+		}
+	}
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start) {
+		add_memory_region(initrd_pstart, initrd_pend - initrd_pstart,
+				  BOOT_MEM_RESERVED);
+	}
+#endif
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+static int __init initrd_setup(char *str)
+{
+	char rdarg[64];
+	int idx;
+	char *tmp, *endptr;
+	unsigned long initrd_size;
+
+	/* Make a copy of the initrd argument so we can smash it up here */
+	for (idx = 0; idx < sizeof(rdarg)-1; idx++) {
+		if (!str[idx] || (str[idx] == ' ')) break;
+		rdarg[idx] = str[idx];
+	}
+
+	rdarg[idx] = 0;
+	str = rdarg;
+
+	/*
+	 *Initrd location comes in the form "<hex size of ramdisk in bytes>@<location in memory>"
+	 *  e.g. initrd=3abfd@80010000.	 This is set up by the loader.
+	 */
+	for (tmp = str; *tmp != '@'; tmp++) {
+		if (!*tmp) {
+			goto fail;
+		}
+	}
+	*tmp = 0;
+	tmp++;
+	if (!*tmp) {
+		goto fail;
+	}
+	initrd_size = simple_strtoul(str, &endptr, 16);
+	if (*endptr) {
+		*(tmp-1) = '@';
+		goto fail;
+	}
+	*(tmp-1) = '@';
+	initrd_start = simple_strtoul(tmp, &endptr, 16);
+	if (*endptr) {
+		goto fail;
+	}
+	initrd_end = initrd_start + initrd_size;
+	printk("Found initrd of %lx@%lx\n", initrd_size, initrd_start);
+	return 1;
+ fail:
+	printk("Bad initrd argument.  Disabling initrd\n");
+	initrd_start = 0;
+	initrd_end = 0;
+	return 1;
+}
+
+#endif
+
+extern const struct plat_smp_ops sb_smp_ops;
+extern const struct plat_smp_ops bcm1480_smp_ops;
+
+/*
+ * prom_init is called just after the cpu type is determined, from setup_arch()
+ */
+void __init prom_init(void)
+{
+	uint64_t cfe_ept, cfe_handle;
+	unsigned int cfe_eptseal;
+	int argc = fw_arg0;
+	char **envp = (char **) fw_arg2;
+	int *prom_vec = (int *) fw_arg3;
+
+	_machine_restart   = cfe_linux_restart;
+	_machine_halt	   = cfe_linux_halt;
+	pm_power_off = cfe_linux_halt;
+
+	/*
+	 * Check if a loader was used; if NOT, the 4 arguments are
+	 * what CFE gives us (handle, 0, EPT and EPTSEAL)
+	 */
+	if (argc < 0) {
+		cfe_handle = (uint64_t)(long)argc;
+		cfe_ept = (long)envp;
+		cfe_eptseal = (uint32_t)(unsigned long)prom_vec;
+	} else {
+		if ((int32_t)(long)prom_vec < 0) {
+			/*
+			 * Old loader; all it gives us is the handle,
+			 * so use the "known" entrypoint and assume
+			 * the seal.
+			 */
+			cfe_handle = (uint64_t)(long)prom_vec;
+			cfe_ept = (uint64_t)((int32_t)0x9fc00500);
+			cfe_eptseal = CFE_EPTSEAL;
+		} else {
+			/*
+			 * Newer loaders bundle the handle/ept/eptseal
+			 * Note: prom_vec is in the loader's useg
+			 * which is still alive in the TLB.
+			 */
+			cfe_handle = (uint64_t)((int32_t *)prom_vec)[0];
+			cfe_ept = (uint64_t)((int32_t *)prom_vec)[2];
+			cfe_eptseal = (unsigned int)((uint32_t *)prom_vec)[3];
+		}
+	}
+	if (cfe_eptseal != CFE_EPTSEAL) {
+		/* too early for panic to do any good */
+		printk("CFE's entrypoint seal doesn't match. Spinning.");
+		while (1) ;
+	}
+	cfe_init(cfe_handle, cfe_ept);
+	/*
+	 * Get the handle for (at least) prom_putchar, possibly for
+	 * boot console
+	 */
+	cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
+	if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, COMMAND_LINE_SIZE) < 0) {
+		if (argc >= 0) {
+			/* The loader should have set the command line */
+			/* too early for panic to do any good */
+			printk("LINUX_CMDLINE not defined in cfe.");
+			while (1) ;
+		}
+	}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	{
+		char *ptr;
+		/* Need to find out early whether we've got an initrd.	So scan
+		   the list looking now */
+		for (ptr = arcs_cmdline; *ptr; ptr++) {
+			while (*ptr == ' ') {
+				ptr++;
+			}
+			if (!strncmp(ptr, "initrd=", 7)) {
+				initrd_setup(ptr+7);
+				break;
+			} else {
+				while (*ptr && (*ptr != ' ')) {
+					ptr++;
+				}
+			}
+		}
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	/* Not sure this is needed, but it's the safe way. */
+	arcs_cmdline[COMMAND_LINE_SIZE-1] = 0;
+
+	prom_meminit();
+
+#if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250)
+	register_smp_ops(&sb_smp_ops);
+#endif
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+	register_smp_ops(&bcm1480_smp_ops);
+#endif
+}
+
+void __init prom_free_prom_memory(void)
+{
+	/* Not sure what I'm supposed to do here.  Nothing, I think */
+}
+
+void prom_putchar(char c)
+{
+	int ret;
+
+	while ((ret = cfe_write(cfe_cons_handle, &c, 1)) == 0)
+		;
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/common/cfe_console.c b/src/kernel/linux/v4.14/arch/mips/sibyte/common/cfe_console.c
new file mode 100644
index 0000000..8af7b41
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/common/cfe_console.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/console.h>
+
+#include <asm/sibyte/board.h>
+
+#include <asm/fw/cfe/cfe_api.h>
+#include <asm/fw/cfe/cfe_error.h>
+
+extern int cfe_cons_handle;
+
+static void cfe_console_write(struct console *cons, const char *str,
+		       unsigned int count)
+{
+	int i, last, written;
+
+	for (i=0, last=0; i<count; i++) {
+		if (!str[i])
+			/* XXXKW can/should this ever happen? */
+			return;
+		if (str[i] == '\n') {
+			do {
+				written = cfe_write(cfe_cons_handle, &str[last], i-last);
+				if (written < 0)
+					;
+				last += written;
+			} while (last < i);
+			while (cfe_write(cfe_cons_handle, "\r", 1) <= 0)
+				;
+		}
+	}
+	if (last != count) {
+		do {
+			written = cfe_write(cfe_cons_handle, &str[last], count-last);
+			if (written < 0)
+				;
+			last += written;
+		} while (last < count);
+	}
+
+}
+
+static int cfe_console_setup(struct console *cons, char *str)
+{
+	char consdev[32];
+	/* XXXKW think about interaction with 'console=' cmdline arg */
+	/* If none of the console options are configured, the build will break. */
+	if (cfe_getenv("BOOT_CONSOLE", consdev, 32) >= 0) {
+#ifdef CONFIG_SERIAL_SB1250_DUART
+		if (!strcmp(consdev, "uart0")) {
+			setleds("u0cn");
+		} else if (!strcmp(consdev, "uart1")) {
+			setleds("u1cn");
+		} else
+#endif
+#ifdef CONFIG_VGA_CONSOLE
+		       if (!strcmp(consdev, "pcconsole0")) {
+				setleds("pccn");
+		} else
+#endif
+			return -ENODEV;
+	}
+	return 0;
+}
+
+static struct console sb1250_cfe_cons = {
+	.name		= "cfe",
+	.write		= cfe_console_write,
+	.setup		= cfe_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+};
+
+static int __init sb1250_cfe_console_init(void)
+{
+	register_console(&sb1250_cfe_cons);
+	return 0;
+}
+
+console_initcall(sb1250_cfe_console_init);
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/common/sb_tbprof.c b/src/kernel/linux/v4.14/arch/mips/sibyte/common/sb_tbprof.c
new file mode 100644
index 0000000..99c720b
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/common/sb_tbprof.c
@@ -0,0 +1,607 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2001, 2002, 2003 Broadcom Corporation
+ * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org>
+ * Copyright (C) 2007 MIPS Technologies, Inc.
+ *    written by Ralf Baechle <ralf@linux-mips.org>
+ */
+
+#undef DEBUG
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250.h>
+
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+#include <asm/sibyte/bcm1480_regs.h>
+#include <asm/sibyte/bcm1480_scd.h>
+#include <asm/sibyte/bcm1480_int.h>
+#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_scd.h>
+#include <asm/sibyte/sb1250_int.h>
+#else
+#error invalid SiByte UART configuration
+#endif
+
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+#undef K_INT_TRACE_FREEZE
+#define K_INT_TRACE_FREEZE K_BCM1480_INT_TRACE_FREEZE
+#undef K_INT_PERF_CNT
+#define K_INT_PERF_CNT K_BCM1480_INT_PERF_CNT
+#endif
+
+#include <linux/uaccess.h>
+
+#define SBPROF_TB_MAJOR 240
+
+typedef u64 tb_sample_t[6*256];
+
+enum open_status {
+	SB_CLOSED,
+	SB_OPENING,
+	SB_OPEN
+};
+
+struct sbprof_tb {
+	wait_queue_head_t	tb_sync;
+	wait_queue_head_t	tb_read;
+	struct mutex		lock;
+	enum open_status	open;
+	tb_sample_t		*sbprof_tbbuf;
+	int			next_tb_sample;
+
+	volatile int		tb_enable;
+	volatile int		tb_armed;
+
+};
+
+static struct sbprof_tb sbp;
+
+#define MAX_SAMPLE_BYTES (24*1024*1024)
+#define MAX_TBSAMPLE_BYTES (12*1024*1024)
+
+#define MAX_SAMPLES (MAX_SAMPLE_BYTES/sizeof(u_int32_t))
+#define TB_SAMPLE_SIZE (sizeof(tb_sample_t))
+#define MAX_TB_SAMPLES (MAX_TBSAMPLE_BYTES/TB_SAMPLE_SIZE)
+
+/* ioctls */
+#define SBPROF_ZBSTART		_IOW('s', 0, int)
+#define SBPROF_ZBSTOP		_IOW('s', 1, int)
+#define SBPROF_ZBWAITFULL	_IOW('s', 2, int)
+
+/*
+ * Routines for using 40-bit SCD cycle counter
+ *
+ * Client responsible for either handling interrupts or making sure
+ * the cycles counter never saturates, e.g., by doing
+ * zclk_timer_init(0) at least every 2^40 - 1 ZCLKs.
+ */
+
+/*
+ * Configures SCD counter 0 to count ZCLKs starting from val;
+ * Configures SCD counters1,2,3 to count nothing.
+ * Must not be called while gathering ZBbus profiles.
+ */
+
+#define zclk_timer_init(val) \
+  __asm__ __volatile__ (".set push;" \
+			".set mips64;" \
+			"la   $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
+			"sd   %0, 0x10($8);"   /* write val to counter0 */ \
+			"sd   %1, 0($8);"      /* config counter0 for zclks*/ \
+			".set pop" \
+			: /* no outputs */ \
+						     /* enable, counter0 */ \
+			: /* inputs */ "r"(val), "r" ((1ULL << 33) | 1ULL) \
+			: /* modifies */ "$8" )
+
+
+/* Reads SCD counter 0 and puts result in value
+   unsigned long long val; */
+#define zclk_get(val) \
+  __asm__ __volatile__ (".set push;" \
+			".set mips64;" \
+			"la   $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
+			"ld   %0, 0x10($8);"   /* write val to counter0 */ \
+			".set pop" \
+			: /* outputs */ "=r"(val) \
+			: /* inputs */ \
+			: /* modifies */ "$8" )
+
+#define DEVNAME "sb_tbprof"
+
+#define TB_FULL (sbp.next_tb_sample == MAX_TB_SAMPLES)
+
+/*
+ * Support for ZBbus sampling using the trace buffer
+ *
+ * We use the SCD performance counter interrupt, caused by a Zclk counter
+ * overflow, to trigger the start of tracing.
+ *
+ * We set the trace buffer to sample everything and freeze on
+ * overflow.
+ *
+ * We map the interrupt for trace_buffer_freeze to handle it on CPU 0.
+ *
+ */
+
+static u64 tb_period;
+
+static void arm_tb(void)
+{
+	u64 scdperfcnt;
+	u64 next = (1ULL << 40) - tb_period;
+	u64 tb_options = M_SCD_TRACE_CFG_FREEZE_FULL;
+
+	/*
+	 * Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to
+	 * trigger start of trace.  XXX vary sampling period
+	 */
+	__raw_writeq(0, IOADDR(A_SCD_PERF_CNT_1));
+	scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
+
+	/*
+	 * Unfortunately, in Pass 2 we must clear all counters to knock down
+	 * a previous interrupt request.  This means that bus profiling
+	 * requires ALL of the SCD perf counters.
+	 */
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+	__raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) |
+						/* keep counters 0,2,3,4,5,6,7 as is */
+		     V_SPC_CFG_SRC1(1),		/* counter 1 counts cycles */
+		     IOADDR(A_BCM1480_SCD_PERF_CNT_CFG0));
+	__raw_writeq(
+		     M_SPC_CFG_ENABLE |		/* enable counting */
+		     M_SPC_CFG_CLEAR |		/* clear all counters */
+		     V_SPC_CFG_SRC1(1),		/* counter 1 counts cycles */
+		     IOADDR(A_BCM1480_SCD_PERF_CNT_CFG1));
+#else
+	__raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) |
+						/* keep counters 0,2,3 as is */
+		     M_SPC_CFG_ENABLE |		/* enable counting */
+		     M_SPC_CFG_CLEAR |		/* clear all counters */
+		     V_SPC_CFG_SRC1(1),		/* counter 1 counts cycles */
+		     IOADDR(A_SCD_PERF_CNT_CFG));
+#endif
+	__raw_writeq(next, IOADDR(A_SCD_PERF_CNT_1));
+	/* Reset the trace buffer */
+	__raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
+#if 0 && defined(M_SCD_TRACE_CFG_FORCECNT)
+	/* XXXKW may want to expose control to the data-collector */
+	tb_options |= M_SCD_TRACE_CFG_FORCECNT;
+#endif
+	__raw_writeq(tb_options, IOADDR(A_SCD_TRACE_CFG));
+	sbp.tb_armed = 1;
+}
+
+static irqreturn_t sbprof_tb_intr(int irq, void *dev_id)
+{
+	int i;
+
+	pr_debug(DEVNAME ": tb_intr\n");
+
+	if (sbp.next_tb_sample < MAX_TB_SAMPLES) {
+		/* XXX should use XKPHYS to make writes bypass L2 */
+		u64 *p = sbp.sbprof_tbbuf[sbp.next_tb_sample++];
+		/* Read out trace */
+		__raw_writeq(M_SCD_TRACE_CFG_START_READ,
+			     IOADDR(A_SCD_TRACE_CFG));
+		__asm__ __volatile__ ("sync" : : : "memory");
+		/* Loop runs backwards because bundles are read out in reverse order */
+		for (i = 256 * 6; i > 0; i -= 6) {
+			/* Subscripts decrease to put bundle in the order */
+			/*   t0 lo, t0 hi, t1 lo, t1 hi, t2 lo, t2 hi */
+			p[i - 1] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t2 hi */
+			p[i - 2] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t2 lo */
+			p[i - 3] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t1 hi */
+			p[i - 4] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t1 lo */
+			p[i - 5] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t0 hi */
+			p[i - 6] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t0 lo */
+		}
+		if (!sbp.tb_enable) {
+			pr_debug(DEVNAME ": tb_intr shutdown\n");
+			__raw_writeq(M_SCD_TRACE_CFG_RESET,
+				     IOADDR(A_SCD_TRACE_CFG));
+			sbp.tb_armed = 0;
+			wake_up_interruptible(&sbp.tb_sync);
+		} else {
+			/* knock down current interrupt and get another one later */
+			arm_tb();
+		}
+	} else {
+		/* No more trace buffer samples */
+		pr_debug(DEVNAME ": tb_intr full\n");
+		__raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
+		sbp.tb_armed = 0;
+		if (!sbp.tb_enable)
+			wake_up_interruptible(&sbp.tb_sync);
+		wake_up_interruptible(&sbp.tb_read);
+	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sbprof_pc_intr(int irq, void *dev_id)
+{
+	printk(DEVNAME ": unexpected pc_intr");
+	return IRQ_NONE;
+}
+
+/*
+ * Requires: Already called zclk_timer_init with a value that won't
+ *	     saturate 40 bits.	No subsequent use of SCD performance counters
+ *	     or trace buffer.
+ */
+
+static int sbprof_zbprof_start(struct file *filp)
+{
+	u64 scdperfcnt;
+	int err;
+
+	if (xchg(&sbp.tb_enable, 1))
+		return -EBUSY;
+
+	pr_debug(DEVNAME ": starting\n");
+
+	sbp.next_tb_sample = 0;
+	filp->f_pos = 0;
+
+	err = request_irq(K_INT_TRACE_FREEZE, sbprof_tb_intr, 0,
+			  DEVNAME " trace freeze", &sbp);
+	if (err)
+		return -EBUSY;
+
+	/* Make sure there isn't a perf-cnt interrupt waiting */
+	scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
+	/* Disable and clear counters, override SRC_1 */
+	__raw_writeq((scdperfcnt & ~(M_SPC_CFG_SRC1 | M_SPC_CFG_ENABLE)) |
+		     M_SPC_CFG_ENABLE | M_SPC_CFG_CLEAR | V_SPC_CFG_SRC1(1),
+		     IOADDR(A_SCD_PERF_CNT_CFG));
+
+	/*
+	 * We grab this interrupt to prevent others from trying to use
+	 * it, even though we don't want to service the interrupts
+	 * (they only feed into the trace-on-interrupt mechanism)
+	 */
+	if (request_irq(K_INT_PERF_CNT, sbprof_pc_intr, 0, DEVNAME " scd perfcnt", &sbp)) {
+		free_irq(K_INT_TRACE_FREEZE, &sbp);
+		return -EBUSY;
+	}
+
+	/*
+	 * I need the core to mask these, but the interrupt mapper to
+	 *  pass them through.	I am exploiting my knowledge that
+	 *  cp0_status masks out IP[5]. krw
+	 */
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+	__raw_writeq(K_BCM1480_INT_MAP_I3,
+		     IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_MAP_BASE_L) +
+			    ((K_BCM1480_INT_PERF_CNT & 0x3f) << 3)));
+#else
+	__raw_writeq(K_INT_MAP_I3,
+		     IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +
+			    (K_INT_PERF_CNT << 3)));
+#endif
+
+	/* Initialize address traps */
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_0));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_1));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_2));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_3));
+
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_0));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_1));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_2));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_3));
+
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_0));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_1));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_2));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_3));
+
+	/* Initialize Trace Event 0-7 */
+	/*				when interrupt	*/
+	__raw_writeq(M_SCD_TREVT_INTERRUPT, IOADDR(A_SCD_TRACE_EVENT_0));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_1));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_2));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_3));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_4));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_5));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_6));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_7));
+
+	/* Initialize Trace Sequence 0-7 */
+	/*				     Start on event 0 (interrupt) */
+	__raw_writeq(V_SCD_TRSEQ_FUNC_START | 0x0fff,
+		     IOADDR(A_SCD_TRACE_SEQUENCE_0));
+	/*			  dsamp when d used | asamp when a used */
+	__raw_writeq(M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE |
+		     K_SCD_TRSEQ_TRIGGER_ALL,
+		     IOADDR(A_SCD_TRACE_SEQUENCE_1));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_2));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_3));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_4));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_5));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_6));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_7));
+
+	/* Now indicate the PERF_CNT interrupt as a trace-relevant interrupt */
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+	__raw_writeq(1ULL << (K_BCM1480_INT_PERF_CNT & 0x3f),
+		     IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_TRACE_L)));
+#else
+	__raw_writeq(1ULL << K_INT_PERF_CNT,
+		     IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_TRACE)));
+#endif
+	arm_tb();
+
+	pr_debug(DEVNAME ": done starting\n");
+
+	return 0;
+}
+
+static int sbprof_zbprof_stop(void)
+{
+	int err = 0;
+
+	pr_debug(DEVNAME ": stopping\n");
+
+	if (sbp.tb_enable) {
+		/*
+		 * XXXKW there is a window here where the intr handler may run,
+		 * see the disable, and do the wake_up before this sleep
+		 * happens.
+		 */
+		pr_debug(DEVNAME ": wait for disarm\n");
+		err = wait_event_interruptible(sbp.tb_sync, !sbp.tb_armed);
+		pr_debug(DEVNAME ": disarm complete, stat %d\n", err);
+
+		if (err)
+			return err;
+
+		sbp.tb_enable = 0;
+		free_irq(K_INT_TRACE_FREEZE, &sbp);
+		free_irq(K_INT_PERF_CNT, &sbp);
+	}
+
+	pr_debug(DEVNAME ": done stopping\n");
+
+	return err;
+}
+
+static int sbprof_tb_open(struct inode *inode, struct file *filp)
+{
+	int minor;
+
+	minor = iminor(inode);
+	if (minor != 0)
+		return -ENODEV;
+
+	if (xchg(&sbp.open, SB_OPENING) != SB_CLOSED)
+		return -EBUSY;
+
+	memset(&sbp, 0, sizeof(struct sbprof_tb));
+	sbp.sbprof_tbbuf = vzalloc(MAX_TBSAMPLE_BYTES);
+	if (!sbp.sbprof_tbbuf) {
+		sbp.open = SB_CLOSED;
+		wmb();
+		return -ENOMEM;
+	}
+
+	init_waitqueue_head(&sbp.tb_sync);
+	init_waitqueue_head(&sbp.tb_read);
+	mutex_init(&sbp.lock);
+
+	sbp.open = SB_OPEN;
+	wmb();
+
+	return 0;
+}
+
+static int sbprof_tb_release(struct inode *inode, struct file *filp)
+{
+	int minor;
+
+	minor = iminor(inode);
+	if (minor != 0 || sbp.open != SB_CLOSED)
+		return -ENODEV;
+
+	mutex_lock(&sbp.lock);
+
+	if (sbp.tb_armed || sbp.tb_enable)
+		sbprof_zbprof_stop();
+
+	vfree(sbp.sbprof_tbbuf);
+	sbp.open = SB_CLOSED;
+	wmb();
+
+	mutex_unlock(&sbp.lock);
+
+	return 0;
+}
+
+static ssize_t sbprof_tb_read(struct file *filp, char *buf,
+			      size_t size, loff_t *offp)
+{
+	int cur_sample, sample_off, cur_count, sample_left;
+	char *src;
+	int   count   =	 0;
+	char *dest    =	 buf;
+	long  cur_off = *offp;
+
+	if (!access_ok(VERIFY_WRITE, buf, size))
+		return -EFAULT;
+
+	mutex_lock(&sbp.lock);
+
+	count = 0;
+	cur_sample = cur_off / TB_SAMPLE_SIZE;
+	sample_off = cur_off % TB_SAMPLE_SIZE;
+	sample_left = TB_SAMPLE_SIZE - sample_off;
+
+	while (size && (cur_sample < sbp.next_tb_sample)) {
+		int err;
+
+		cur_count = size < sample_left ? size : sample_left;
+		src = (char *)(((long)sbp.sbprof_tbbuf[cur_sample])+sample_off);
+		err = __copy_to_user(dest, src, cur_count);
+		if (err) {
+			*offp = cur_off + cur_count - err;
+			mutex_unlock(&sbp.lock);
+			return err;
+		}
+		pr_debug(DEVNAME ": read from sample %d, %d bytes\n",
+			 cur_sample, cur_count);
+		size -= cur_count;
+		sample_left -= cur_count;
+		if (!sample_left) {
+			cur_sample++;
+			sample_off = 0;
+			sample_left = TB_SAMPLE_SIZE;
+		} else {
+			sample_off += cur_count;
+		}
+		cur_off += cur_count;
+		dest += cur_count;
+		count += cur_count;
+	}
+	*offp = cur_off;
+	mutex_unlock(&sbp.lock);
+
+	return count;
+}
+
+static long sbprof_tb_ioctl(struct file *filp,
+			    unsigned int command,
+			    unsigned long arg)
+{
+	int err = 0;
+
+	switch (command) {
+	case SBPROF_ZBSTART:
+		mutex_lock(&sbp.lock);
+		err = sbprof_zbprof_start(filp);
+		mutex_unlock(&sbp.lock);
+		break;
+
+	case SBPROF_ZBSTOP:
+		mutex_lock(&sbp.lock);
+		err = sbprof_zbprof_stop();
+		mutex_unlock(&sbp.lock);
+		break;
+
+	case SBPROF_ZBWAITFULL: {
+		err = wait_event_interruptible(sbp.tb_read, TB_FULL);
+		if (err)
+			break;
+
+		err = put_user(TB_FULL, (int *) arg);
+		break;
+	}
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static const struct file_operations sbprof_tb_fops = {
+	.owner		= THIS_MODULE,
+	.open		= sbprof_tb_open,
+	.release	= sbprof_tb_release,
+	.read		= sbprof_tb_read,
+	.unlocked_ioctl = sbprof_tb_ioctl,
+	.compat_ioctl	= sbprof_tb_ioctl,
+	.mmap		= NULL,
+	.llseek		= default_llseek,
+};
+
+static struct class *tb_class;
+static struct device *tb_dev;
+
+static int __init sbprof_tb_init(void)
+{
+	struct device *dev;
+	struct class *tbc;
+	int err;
+
+	if (register_chrdev(SBPROF_TB_MAJOR, DEVNAME, &sbprof_tb_fops)) {
+		printk(KERN_WARNING DEVNAME ": initialization failed (dev %d)\n",
+		       SBPROF_TB_MAJOR);
+		return -EIO;
+	}
+
+	tbc = class_create(THIS_MODULE, "sb_tracebuffer");
+	if (IS_ERR(tbc)) {
+		err = PTR_ERR(tbc);
+		goto out_chrdev;
+	}
+
+	tb_class = tbc;
+
+	dev = device_create(tbc, NULL, MKDEV(SBPROF_TB_MAJOR, 0), NULL, "tb");
+	if (IS_ERR(dev)) {
+		err = PTR_ERR(dev);
+		goto out_class;
+	}
+	tb_dev = dev;
+
+	sbp.open = SB_CLOSED;
+	wmb();
+	tb_period = zbbus_mhz * 10000LL;
+	pr_info(DEVNAME ": initialized - tb_period = %lld\n",
+		(long long) tb_period);
+	return 0;
+
+out_class:
+	class_destroy(tb_class);
+out_chrdev:
+	unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME);
+
+	return err;
+}
+
+static void __exit sbprof_tb_cleanup(void)
+{
+	device_destroy(tb_class, MKDEV(SBPROF_TB_MAJOR, 0));
+	unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME);
+	class_destroy(tb_class);
+}
+
+module_init(sbprof_tb_init);
+module_exit(sbprof_tb_cleanup);
+
+MODULE_ALIAS_CHARDEV_MAJOR(SBPROF_TB_MAJOR);
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/Makefile b/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/Makefile
new file mode 100644
index 0000000..cdc4c56
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/Makefile
@@ -0,0 +1,3 @@
+obj-y := setup.o irq.o time.o
+
+obj-$(CONFIG_SMP)			+= smp.o
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/irq.c b/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/irq.c
new file mode 100644
index 0000000..6d8dba5
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/irq.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003 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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/mm.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/errno.h>
+#include <asm/signal.h>
+#include <asm/time.h>
+#include <asm/io.h>
+
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_int.h>
+#include <asm/sibyte/sb1250_uart.h>
+#include <asm/sibyte/sb1250_scd.h>
+#include <asm/sibyte/sb1250.h>
+
+/*
+ * These are the routines that handle all the low level interrupt stuff.
+ * Actions handled here are: initialization of the interrupt map, requesting of
+ * interrupt lines by handlers, dispatching if interrupts to handlers, probing
+ * for interrupt lines
+ */
+
+#ifdef CONFIG_SIBYTE_HAS_LDT
+extern unsigned long ldt_eoi_space;
+#endif
+
+/* Store the CPU id (not the logical number) */
+int sb1250_irq_owner[SB1250_NR_IRQS];
+
+static DEFINE_RAW_SPINLOCK(sb1250_imr_lock);
+
+void sb1250_mask_irq(int cpu, int irq)
+{
+	unsigned long flags;
+	u64 cur_ints;
+
+	raw_spin_lock_irqsave(&sb1250_imr_lock, flags);
+	cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(cpu) +
+					R_IMR_INTERRUPT_MASK));
+	cur_ints |= (((u64) 1) << irq);
+	____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(cpu) +
+					R_IMR_INTERRUPT_MASK));
+	raw_spin_unlock_irqrestore(&sb1250_imr_lock, flags);
+}
+
+void sb1250_unmask_irq(int cpu, int irq)
+{
+	unsigned long flags;
+	u64 cur_ints;
+
+	raw_spin_lock_irqsave(&sb1250_imr_lock, flags);
+	cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(cpu) +
+					R_IMR_INTERRUPT_MASK));
+	cur_ints &= ~(((u64) 1) << irq);
+	____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(cpu) +
+					R_IMR_INTERRUPT_MASK));
+	raw_spin_unlock_irqrestore(&sb1250_imr_lock, flags);
+}
+
+#ifdef CONFIG_SMP
+static int sb1250_set_affinity(struct irq_data *d, const struct cpumask *mask,
+			       bool force)
+{
+	int i = 0, old_cpu, cpu, int_on;
+	unsigned int irq = d->irq;
+	u64 cur_ints;
+	unsigned long flags;
+
+	i = cpumask_first_and(mask, cpu_online_mask);
+
+	/* Convert logical CPU to physical CPU */
+	cpu = cpu_logical_map(i);
+
+	/* Protect against other affinity changers and IMR manipulation */
+	raw_spin_lock_irqsave(&sb1250_imr_lock, flags);
+
+	/* Swizzle each CPU's IMR (but leave the IP selection alone) */
+	old_cpu = sb1250_irq_owner[irq];
+	cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(old_cpu) +
+					R_IMR_INTERRUPT_MASK));
+	int_on = !(cur_ints & (((u64) 1) << irq));
+	if (int_on) {
+		/* If it was on, mask it */
+		cur_ints |= (((u64) 1) << irq);
+		____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(old_cpu) +
+					R_IMR_INTERRUPT_MASK));
+	}
+	sb1250_irq_owner[irq] = cpu;
+	if (int_on) {
+		/* unmask for the new CPU */
+		cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(cpu) +
+					R_IMR_INTERRUPT_MASK));
+		cur_ints &= ~(((u64) 1) << irq);
+		____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(cpu) +
+					R_IMR_INTERRUPT_MASK));
+	}
+	raw_spin_unlock_irqrestore(&sb1250_imr_lock, flags);
+
+	return 0;
+}
+#endif
+
+static void disable_sb1250_irq(struct irq_data *d)
+{
+	unsigned int irq = d->irq;
+
+	sb1250_mask_irq(sb1250_irq_owner[irq], irq);
+}
+
+static void enable_sb1250_irq(struct irq_data *d)
+{
+	unsigned int irq = d->irq;
+
+	sb1250_unmask_irq(sb1250_irq_owner[irq], irq);
+}
+
+
+static void ack_sb1250_irq(struct irq_data *d)
+{
+	unsigned int irq = d->irq;
+#ifdef CONFIG_SIBYTE_HAS_LDT
+	u64 pending;
+
+	/*
+	 * If the interrupt was an HT interrupt, now is the time to
+	 * clear it.  NOTE: we assume the HT bridge was set up to
+	 * deliver the interrupts to all CPUs (which makes affinity
+	 * changing easier for us)
+	 */
+	pending = __raw_readq(IOADDR(A_IMR_REGISTER(sb1250_irq_owner[irq],
+						    R_IMR_LDT_INTERRUPT)));
+	pending &= ((u64)1 << (irq));
+	if (pending) {
+		int i;
+		for (i=0; i<NR_CPUS; i++) {
+			int cpu;
+#ifdef CONFIG_SMP
+			cpu = cpu_logical_map(i);
+#else
+			cpu = i;
+#endif
+			/*
+			 * Clear for all CPUs so an affinity switch
+			 * doesn't find an old status
+			 */
+			__raw_writeq(pending,
+				     IOADDR(A_IMR_REGISTER(cpu,
+						R_IMR_LDT_INTERRUPT_CLR)));
+		}
+
+		/*
+		 * Generate EOI.  For Pass 1 parts, EOI is a nop.  For
+		 * Pass 2, the LDT world may be edge-triggered, but
+		 * this EOI shouldn't hurt.  If they are
+		 * level-sensitive, the EOI is required.
+		 */
+		*(uint32_t *)(ldt_eoi_space+(irq<<16)+(7<<2)) = 0;
+	}
+#endif
+	sb1250_mask_irq(sb1250_irq_owner[irq], irq);
+}
+
+static struct irq_chip sb1250_irq_type = {
+	.name = "SB1250-IMR",
+	.irq_mask_ack = ack_sb1250_irq,
+	.irq_unmask = enable_sb1250_irq,
+	.irq_mask = disable_sb1250_irq,
+#ifdef CONFIG_SMP
+	.irq_set_affinity = sb1250_set_affinity
+#endif
+};
+
+void __init init_sb1250_irqs(void)
+{
+	int i;
+
+	for (i = 0; i < SB1250_NR_IRQS; i++) {
+		irq_set_chip_and_handler(i, &sb1250_irq_type,
+					 handle_level_irq);
+		sb1250_irq_owner[i] = 0;
+	}
+}
+
+
+/*
+ *  arch_init_irq is called early in the boot sequence from init/main.c via
+ *  init_IRQ.  It is responsible for setting up the interrupt mapper and
+ *  installing the handler that will be responsible for dispatching interrupts
+ *  to the "right" place.
+ */
+/*
+ * For now, map all interrupts to IP[2].  We could save
+ * some cycles by parceling out system interrupts to different
+ * IP lines, but keep it simple for bringup.  We'll also direct
+ * all interrupts to a single CPU; we should probably route
+ * PCI and LDT to one cpu and everything else to the other
+ * to balance the load a bit.
+ *
+ * On the second cpu, everything is set to IP5, which is
+ * ignored, EXCEPT the mailbox interrupt.  That one is
+ * set to IP[2] so it is handled.  This is needed so we
+ * can do cross-cpu function calls, as required by SMP
+ */
+
+#define IMR_IP2_VAL	K_INT_MAP_I0
+#define IMR_IP3_VAL	K_INT_MAP_I1
+#define IMR_IP4_VAL	K_INT_MAP_I2
+#define IMR_IP5_VAL	K_INT_MAP_I3
+#define IMR_IP6_VAL	K_INT_MAP_I4
+
+void __init arch_init_irq(void)
+{
+
+	unsigned int i;
+	u64 tmp;
+	unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
+		STATUSF_IP1 | STATUSF_IP0;
+
+	/* Default everything to IP2 */
+	for (i = 0; i < SB1250_NR_IRQS; i++) {	/* was I0 */
+		__raw_writeq(IMR_IP2_VAL,
+			     IOADDR(A_IMR_REGISTER(0,
+						   R_IMR_INTERRUPT_MAP_BASE) +
+				    (i << 3)));
+		__raw_writeq(IMR_IP2_VAL,
+			     IOADDR(A_IMR_REGISTER(1,
+						   R_IMR_INTERRUPT_MAP_BASE) +
+				    (i << 3)));
+	}
+
+	init_sb1250_irqs();
+
+	/*
+	 * Map the high 16 bits of the mailbox registers to IP[3], for
+	 * inter-cpu messages
+	 */
+	/* Was I1 */
+	__raw_writeq(IMR_IP3_VAL,
+		     IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +
+			    (K_INT_MBOX_0 << 3)));
+	__raw_writeq(IMR_IP3_VAL,
+		     IOADDR(A_IMR_REGISTER(1, R_IMR_INTERRUPT_MAP_BASE) +
+			    (K_INT_MBOX_0 << 3)));
+
+	/* Clear the mailboxes.	 The firmware may leave them dirty */
+	__raw_writeq(0xffffffffffffffffULL,
+		     IOADDR(A_IMR_REGISTER(0, R_IMR_MAILBOX_CLR_CPU)));
+	__raw_writeq(0xffffffffffffffffULL,
+		     IOADDR(A_IMR_REGISTER(1, R_IMR_MAILBOX_CLR_CPU)));
+
+	/* Mask everything except the mailbox registers for both cpus */
+	tmp = ~((u64) 0) ^ (((u64) 1) << K_INT_MBOX_0);
+	__raw_writeq(tmp, IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK)));
+	__raw_writeq(tmp, IOADDR(A_IMR_REGISTER(1, R_IMR_INTERRUPT_MASK)));
+
+	/*
+	 * Note that the timer interrupts are also mapped, but this is
+	 * done in sb1250_time_init().	Also, the profiling driver
+	 * does its own management of IP7.
+	 */
+
+	/* Enable necessary IPs, disable the rest */
+	change_c0_status(ST0_IM, imask);
+}
+
+extern void sb1250_mailbox_interrupt(void);
+
+static inline void dispatch_ip2(void)
+{
+	unsigned int cpu = smp_processor_id();
+	unsigned long long mask;
+
+	/*
+	 * Default...we've hit an IP[2] interrupt, which means we've got to
+	 * check the 1250 interrupt registers to figure out what to do.	 Need
+	 * to detect which CPU we're on, now that smp_affinity is supported.
+	 */
+	mask = __raw_readq(IOADDR(A_IMR_REGISTER(cpu,
+				  R_IMR_INTERRUPT_STATUS_BASE)));
+	if (mask)
+		do_IRQ(fls64(mask) - 1);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+	unsigned int cpu = smp_processor_id();
+	unsigned int pending;
+
+	/*
+	 * What a pain. We have to be really careful saving the upper 32 bits
+	 * of any * register across function calls if we don't want them
+	 * trashed--since were running in -o32, the calling routing never saves
+	 * the full 64 bits of a register across a function call.  Being the
+	 * interrupt handler, we're guaranteed that interrupts are disabled
+	 * during this code so we don't have to worry about random interrupts
+	 * blasting the high 32 bits.
+	 */
+
+	pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+	if (pending & CAUSEF_IP7) /* CPU performance counter interrupt */
+		do_IRQ(MIPS_CPU_IRQ_BASE + 7);
+	else if (pending & CAUSEF_IP4)
+		do_IRQ(K_INT_TIMER_0 + cpu);	/* sb1250_timer_interrupt() */
+
+#ifdef CONFIG_SMP
+	else if (pending & CAUSEF_IP3)
+		sb1250_mailbox_interrupt();
+#endif
+
+	else if (pending & CAUSEF_IP2)
+		dispatch_ip2();
+	else
+		spurious_interrupt();
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/setup.c b/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/setup.c
new file mode 100644
index 0000000..aa7713a
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/setup.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003 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.
+ */
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_scd.h>
+
+unsigned int sb1_pass;
+unsigned int soc_pass;
+unsigned int soc_type;
+EXPORT_SYMBOL(soc_type);
+unsigned int periph_rev;
+EXPORT_SYMBOL_GPL(periph_rev);
+unsigned int zbbus_mhz;
+EXPORT_SYMBOL(zbbus_mhz);
+
+static char *soc_str;
+static char *pass_str;
+static unsigned int war_pass;	/* XXXKW don't overload PASS defines? */
+
+static int __init setup_bcm1250(void)
+{
+	int ret = 0;
+
+	switch (soc_pass) {
+	case K_SYS_REVISION_BCM1250_PASS1:
+		periph_rev = 1;
+		pass_str = "Pass 1";
+		break;
+	case K_SYS_REVISION_BCM1250_A10:
+		periph_rev = 2;
+		pass_str = "A8/A10";
+		/* XXXKW different war_pass? */
+		war_pass = K_SYS_REVISION_BCM1250_PASS2;
+		break;
+	case K_SYS_REVISION_BCM1250_PASS2_2:
+		periph_rev = 2;
+		pass_str = "B1";
+		break;
+	case K_SYS_REVISION_BCM1250_B2:
+		periph_rev = 2;
+		pass_str = "B2";
+		war_pass = K_SYS_REVISION_BCM1250_PASS2_2;
+		break;
+	case K_SYS_REVISION_BCM1250_PASS3:
+		periph_rev = 3;
+		pass_str = "C0";
+		break;
+	case K_SYS_REVISION_BCM1250_C1:
+		periph_rev = 3;
+		pass_str = "C1";
+		break;
+	default:
+		if (soc_pass < K_SYS_REVISION_BCM1250_PASS2_2) {
+			periph_rev = 2;
+			pass_str = "A0-A6";
+			war_pass = K_SYS_REVISION_BCM1250_PASS2;
+		} else {
+			printk("Unknown BCM1250 rev %x\n", soc_pass);
+			ret = 1;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+int sb1250_m3_workaround_needed(void)
+{
+	switch (soc_type) {
+	case K_SYS_SOC_TYPE_BCM1250:
+	case K_SYS_SOC_TYPE_BCM1250_ALT:
+	case K_SYS_SOC_TYPE_BCM1250_ALT2:
+	case K_SYS_SOC_TYPE_BCM1125:
+	case K_SYS_SOC_TYPE_BCM1125H:
+		return soc_pass < K_SYS_REVISION_BCM1250_C0;
+
+	default:
+		return 0;
+	}
+}
+
+static int __init setup_bcm112x(void)
+{
+	int ret = 0;
+
+	switch (soc_pass) {
+	case 0:
+		/* Early build didn't have revid set */
+		periph_rev = 3;
+		pass_str = "A1";
+		war_pass = K_SYS_REVISION_BCM112x_A1;
+		break;
+	case K_SYS_REVISION_BCM112x_A1:
+		periph_rev = 3;
+		pass_str = "A1";
+		break;
+	case K_SYS_REVISION_BCM112x_A2:
+		periph_rev = 3;
+		pass_str = "A2";
+		break;
+	case K_SYS_REVISION_BCM112x_A3:
+		periph_rev = 3;
+		pass_str = "A3";
+		break;
+	case K_SYS_REVISION_BCM112x_A4:
+		periph_rev = 3;
+		pass_str = "A4";
+		break;
+	case K_SYS_REVISION_BCM112x_B0:
+		periph_rev = 3;
+		pass_str = "B0";
+		break;
+	default:
+		printk("Unknown %s rev %x\n", soc_str, soc_pass);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+/* Setup code likely to be common to all SiByte platforms */
+
+static int __init sys_rev_decode(void)
+{
+	int ret = 0;
+
+	war_pass = soc_pass;
+	switch (soc_type) {
+	case K_SYS_SOC_TYPE_BCM1250:
+	case K_SYS_SOC_TYPE_BCM1250_ALT:
+	case K_SYS_SOC_TYPE_BCM1250_ALT2:
+		soc_str = "BCM1250";
+		ret = setup_bcm1250();
+		break;
+	case K_SYS_SOC_TYPE_BCM1120:
+		soc_str = "BCM1120";
+		ret = setup_bcm112x();
+		break;
+	case K_SYS_SOC_TYPE_BCM1125:
+		soc_str = "BCM1125";
+		ret = setup_bcm112x();
+		break;
+	case K_SYS_SOC_TYPE_BCM1125H:
+		soc_str = "BCM1125H";
+		ret = setup_bcm112x();
+		break;
+	default:
+		printk("Unknown SOC type %x\n", soc_type);
+		ret = 1;
+		break;
+	}
+
+	return ret;
+}
+
+void __init sb1250_setup(void)
+{
+	uint64_t sys_rev;
+	int plldiv;
+	int bad_config = 0;
+
+	sb1_pass = read_c0_prid() & PRID_REV_MASK;
+	sys_rev = __raw_readq(IOADDR(A_SCD_SYSTEM_REVISION));
+	soc_type = SYS_SOC_TYPE(sys_rev);
+	soc_pass = G_SYS_REVISION(sys_rev);
+
+	if (sys_rev_decode()) {
+		printk("Restart after failure to identify SiByte chip\n");
+		machine_restart(NULL);
+	}
+
+	plldiv = G_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG)));
+	zbbus_mhz = ((plldiv >> 1) * 50) + ((plldiv & 1) * 25);
+
+	printk("Broadcom SiByte %s %s @ %d MHz (SB1 rev %d)\n",
+		    soc_str, pass_str, zbbus_mhz * 2, sb1_pass);
+	printk("Board type: %s\n", get_system_type());
+
+	switch (war_pass) {
+	case K_SYS_REVISION_BCM1250_PASS1:
+		printk("@@@@ This is a BCM1250 A0-A2 (Pass 1) board, "
+			    "and the kernel doesn't have the proper "
+			    "workarounds compiled in. @@@@\n");
+		bad_config = 1;
+		break;
+	case K_SYS_REVISION_BCM1250_PASS2:
+		/* Pass 2 - easiest as default for now - so many numbers */
+#if !defined(CONFIG_SB1_PASS_2_WORKAROUNDS) || \
+    !defined(CONFIG_SB1_PASS_2_1_WORKAROUNDS)
+		printk("@@@@ This is a BCM1250 A3-A10 board, and the "
+			    "kernel doesn't have the proper workarounds "
+			    "compiled in. @@@@\n");
+		bad_config = 1;
+#endif
+#ifdef CONFIG_CPU_HAS_PREFETCH
+		printk("@@@@ Prefetches may be enabled in this kernel, "
+			    "but are buggy on this board.  @@@@\n");
+		bad_config = 1;
+#endif
+		break;
+	case K_SYS_REVISION_BCM1250_PASS2_2:
+#ifndef CONFIG_SB1_PASS_2_WORKAROUNDS
+		printk("@@@@ This is a BCM1250 B1/B2. board, and the "
+			    "kernel doesn't have the proper workarounds "
+			    "compiled in. @@@@\n");
+		bad_config = 1;
+#endif
+#if defined(CONFIG_SB1_PASS_2_1_WORKAROUNDS) || \
+    !defined(CONFIG_CPU_HAS_PREFETCH)
+		printk("@@@@ This is a BCM1250 B1/B2, but the kernel is "
+			    "conservatively configured for an 'A' stepping. "
+			    "@@@@\n");
+#endif
+		break;
+	default:
+		break;
+	}
+	if (bad_config) {
+		printk("Invalid configuration for this chip.\n");
+		machine_restart(NULL);
+	}
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/smp.c b/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/smp.c
new file mode 100644
index 0000000..5baabca
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/smp.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2001, 2002, 2003 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.
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched/task_stack.h>
+
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/fw/cfe/cfe_api.h>
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_int.h>
+
+static void *mailbox_set_regs[] = {
+	IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU),
+	IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_SET_CPU)
+};
+
+static void *mailbox_clear_regs[] = {
+	IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU),
+	IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CLR_CPU)
+};
+
+static void *mailbox_regs[] = {
+	IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU),
+	IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CPU)
+};
+
+/*
+ * SMP init and finish on secondary CPUs
+ */
+void sb1250_smp_init(void)
+{
+	unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
+		STATUSF_IP1 | STATUSF_IP0;
+
+	/* Set interrupt mask, but don't enable */
+	change_c0_status(ST0_IM, imask);
+}
+
+/*
+ * These are routines for dealing with the sb1250 smp capabilities
+ * independent of board/firmware
+ */
+
+/*
+ * Simple enough; everything is set up, so just poke the appropriate mailbox
+ * register, and we should be set
+ */
+static void sb1250_send_ipi_single(int cpu, unsigned int action)
+{
+	__raw_writeq((((u64)action) << 48), mailbox_set_regs[cpu]);
+}
+
+static inline void sb1250_send_ipi_mask(const struct cpumask *mask,
+					unsigned int action)
+{
+	unsigned int i;
+
+	for_each_cpu(i, mask)
+		sb1250_send_ipi_single(i, action);
+}
+
+/*
+ * Code to run on secondary just after probing the CPU
+ */
+static void sb1250_init_secondary(void)
+{
+	extern void sb1250_smp_init(void);
+
+	sb1250_smp_init();
+}
+
+/*
+ * Do any tidying up before marking online and running the idle
+ * loop
+ */
+static void sb1250_smp_finish(void)
+{
+	extern void sb1250_clockevent_init(void);
+
+	sb1250_clockevent_init();
+	local_irq_enable();
+}
+
+/*
+ * Setup the PC, SP, and GP of a secondary processor and start it
+ * running!
+ */
+static int sb1250_boot_secondary(int cpu, struct task_struct *idle)
+{
+	int retval;
+
+	retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap,
+			       __KSTK_TOS(idle),
+			       (unsigned long)task_thread_info(idle), 0);
+	if (retval != 0)
+		printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval);
+	return retval;
+}
+
+/*
+ * Use CFE to find out how many CPUs are available, setting up
+ * cpu_possible_mask and the logical/physical mappings.
+ * XXXKW will the boot CPU ever not be physical 0?
+ *
+ * Common setup before any secondaries are started
+ */
+static void __init sb1250_smp_setup(void)
+{
+	int i, num;
+
+	init_cpu_possible(cpumask_of(0));
+	__cpu_number_map[0] = 0;
+	__cpu_logical_map[0] = 0;
+
+	for (i = 1, num = 0; i < NR_CPUS; i++) {
+		if (cfe_cpu_stop(i) == 0) {
+			set_cpu_possible(i, true);
+			__cpu_number_map[i] = ++num;
+			__cpu_logical_map[num] = i;
+		}
+	}
+	printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
+}
+
+static void __init sb1250_prepare_cpus(unsigned int max_cpus)
+{
+}
+
+const struct plat_smp_ops sb_smp_ops = {
+	.send_ipi_single	= sb1250_send_ipi_single,
+	.send_ipi_mask		= sb1250_send_ipi_mask,
+	.init_secondary		= sb1250_init_secondary,
+	.smp_finish		= sb1250_smp_finish,
+	.boot_secondary		= sb1250_boot_secondary,
+	.smp_setup		= sb1250_smp_setup,
+	.prepare_cpus		= sb1250_prepare_cpus,
+};
+
+void sb1250_mailbox_interrupt(void)
+{
+	int cpu = smp_processor_id();
+	int irq = K_INT_MBOX_0;
+	unsigned int action;
+
+	kstat_incr_irq_this_cpu(irq);
+	/* Load the mailbox register to figure out what we're supposed to do */
+	action = (____raw_readq(mailbox_regs[cpu]) >> 48) & 0xffff;
+
+	/* Clear the mailbox to clear the interrupt */
+	____raw_writeq(((u64)action) << 48, mailbox_clear_regs[cpu]);
+
+	if (action & SMP_RESCHEDULE_YOURSELF)
+		scheduler_ipi();
+
+	if (action & SMP_CALL_FUNCTION) {
+		irq_enter();
+		generic_smp_call_function_interrupt();
+		irq_exit();
+	}
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/time.c b/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/time.c
new file mode 100644
index 0000000..68337bf
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/sb1250/time.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2000, 2001 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.
+ */
+#include <linux/init.h>
+
+extern void sb1250_clocksource_init(void);
+extern void sb1250_clockevent_init(void);
+
+void __init plat_time_init(void)
+{
+	sb1250_clocksource_init();
+	sb1250_clockevent_init();
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/Makefile b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/Makefile
new file mode 100644
index 0000000..7b45f19
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/Makefile
@@ -0,0 +1,4 @@
+obj-y				:= platform.o setup.o rtc_xicor1241.o \
+				   rtc_m41t81.o
+
+obj-$(CONFIG_I2C_BOARDINFO)	+= swarm-i2c.o
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/platform.c b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/platform.c
new file mode 100644
index 0000000..484969d
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/platform.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+
+#include <asm/sibyte/board.h>
+#include <asm/sibyte/sb1250_genbus.h>
+#include <asm/sibyte/sb1250_regs.h>
+
+#if defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_LITTLESUR)
+
+#define DRV_NAME	"pata-swarm"
+
+#define SWARM_IDE_SHIFT 5
+#define SWARM_IDE_BASE	0x1f0
+#define SWARM_IDE_CTRL	0x3f6
+
+static struct resource swarm_pata_resource[] = {
+	{
+		.name	= "Swarm GenBus IDE",
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.name	= "Swarm GenBus IDE",
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.name	= "Swarm GenBus IDE",
+		.flags	= IORESOURCE_IRQ,
+		.start	= K_INT_GB_IDE,
+		.end	= K_INT_GB_IDE,
+	},
+};
+
+static struct pata_platform_info pata_platform_data = {
+	.ioport_shift	= SWARM_IDE_SHIFT,
+};
+
+static struct platform_device swarm_pata_device = {
+	.name		= "pata_platform",
+	.id		= -1,
+	.resource	= swarm_pata_resource,
+	.num_resources	= ARRAY_SIZE(swarm_pata_resource),
+	.dev  = {
+		.platform_data		= &pata_platform_data,
+		.coherent_dma_mask	= ~0,	/* grumble */
+	},
+};
+
+static int __init swarm_pata_init(void)
+{
+	u8 __iomem *base;
+	phys_addr_t offset, size;
+	struct resource *r;
+
+	if (!SIBYTE_HAVE_IDE)
+		return -ENODEV;
+
+	base = ioremap(A_IO_EXT_BASE, 0x800);
+	offset = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS));
+	size = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_MULT_SIZE, IDE_CS));
+	iounmap(base);
+
+	offset = G_IO_START_ADDR(offset) << S_IO_ADDRBASE;
+	size = (G_IO_MULT_SIZE(size) + 1) << S_IO_REGSIZE;
+	if (offset < A_PHYS_GENBUS || offset >= A_PHYS_GENBUS_END) {
+		pr_info(DRV_NAME ": PATA interface at GenBus disabled\n");
+
+		return -EBUSY;
+	}
+
+	pr_info(DRV_NAME ": PATA interface at GenBus slot %i\n", IDE_CS);
+
+	r = swarm_pata_resource;
+	r[0].start = offset + (SWARM_IDE_BASE << SWARM_IDE_SHIFT);
+	r[0].end   = offset + ((SWARM_IDE_BASE + 8) << SWARM_IDE_SHIFT) - 1;
+	r[1].start = offset + (SWARM_IDE_CTRL << SWARM_IDE_SHIFT);
+	r[1].end   = offset + ((SWARM_IDE_CTRL + 1) << SWARM_IDE_SHIFT) - 1;
+
+	return platform_device_register(&swarm_pata_device);
+}
+
+device_initcall(swarm_pata_init);
+
+#endif /* defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_LITTLESUR) */
+
+#define sb1250_dev_struct(num) \
+	static struct resource sb1250_res##num = {		\
+		.name = "SB1250 MAC " __stringify(num),		\
+		.flags = IORESOURCE_MEM,		\
+		.start = A_MAC_CHANNEL_BASE(num),	\
+		.end = A_MAC_CHANNEL_BASE(num + 1) -1,	\
+	};\
+	static struct platform_device sb1250_dev##num = {	\
+		.name = "sb1250-mac",			\
+	.id = num,					\
+	.resource = &sb1250_res##num,			\
+	.num_resources = 1,				\
+	}
+
+sb1250_dev_struct(0);
+sb1250_dev_struct(1);
+sb1250_dev_struct(2);
+sb1250_dev_struct(3);
+
+static struct platform_device *sb1250_devs[] __initdata = {
+	&sb1250_dev0,
+	&sb1250_dev1,
+	&sb1250_dev2,
+	&sb1250_dev3,
+};
+
+static int __init sb1250_device_init(void)
+{
+	int ret;
+
+	/* Set the number of available units based on the SOC type.  */
+	switch (soc_type) {
+	case K_SYS_SOC_TYPE_BCM1250:
+	case K_SYS_SOC_TYPE_BCM1250_ALT:
+		ret = platform_add_devices(sb1250_devs, 3);
+		break;
+	case K_SYS_SOC_TYPE_BCM1120:
+	case K_SYS_SOC_TYPE_BCM1125:
+	case K_SYS_SOC_TYPE_BCM1125H:
+	case K_SYS_SOC_TYPE_BCM1250_ALT2:	/* Hybrid */
+		ret = platform_add_devices(sb1250_devs, 2);
+		break;
+	case K_SYS_SOC_TYPE_BCM1x55:
+	case K_SYS_SOC_TYPE_BCM1x80:
+		ret = platform_add_devices(sb1250_devs, 4);
+		break;
+	default:
+		ret = -ENODEV;
+		break;
+	}
+	return ret;
+}
+device_initcall(sb1250_device_init);
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/rtc_m41t81.c b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/rtc_m41t81.c
new file mode 100644
index 0000000..e624664
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/rtc_m41t81.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ *
+ * Copyright (C) 2002 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * 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 <linux/bcd.h>
+#include <linux/types.h>
+#include <linux/time.h>
+
+#include <asm/time.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_smbus.h>
+
+
+/* M41T81 definitions */
+
+/*
+ * Register bits
+ */
+
+#define M41T81REG_SC_ST		0x80		/* stop bit */
+#define M41T81REG_HR_CB		0x40		/* century bit */
+#define M41T81REG_HR_CEB	0x80		/* century enable bit */
+#define M41T81REG_CTL_S		0x20		/* sign bit */
+#define M41T81REG_CTL_FT	0x40		/* frequency test bit */
+#define M41T81REG_CTL_OUT	0x80		/* output level */
+#define M41T81REG_WD_RB0	0x01		/* watchdog resolution bit 0 */
+#define M41T81REG_WD_RB1	0x02		/* watchdog resolution bit 1 */
+#define M41T81REG_WD_BMB0	0x04		/* watchdog multiplier bit 0 */
+#define M41T81REG_WD_BMB1	0x08		/* watchdog multiplier bit 1 */
+#define M41T81REG_WD_BMB2	0x10		/* watchdog multiplier bit 2 */
+#define M41T81REG_WD_BMB3	0x20		/* watchdog multiplier bit 3 */
+#define M41T81REG_WD_BMB4	0x40		/* watchdog multiplier bit 4 */
+#define M41T81REG_AMO_ABE	0x20		/* alarm in "battery back-up mode" enable bit */
+#define M41T81REG_AMO_SQWE	0x40		/* square wave enable */
+#define M41T81REG_AMO_AFE	0x80		/* alarm flag enable flag */
+#define M41T81REG_ADT_RPT5	0x40		/* alarm repeat mode bit 5 */
+#define M41T81REG_ADT_RPT4	0x80		/* alarm repeat mode bit 4 */
+#define M41T81REG_AHR_RPT3	0x80		/* alarm repeat mode bit 3 */
+#define M41T81REG_AHR_HT	0x40		/* halt update bit */
+#define M41T81REG_AMN_RPT2	0x80		/* alarm repeat mode bit 2 */
+#define M41T81REG_ASC_RPT1	0x80		/* alarm repeat mode bit 1 */
+#define M41T81REG_FLG_AF	0x40		/* alarm flag (read only) */
+#define M41T81REG_FLG_WDF	0x80		/* watchdog flag (read only) */
+#define M41T81REG_SQW_RS0	0x10		/* sqw frequency bit 0 */
+#define M41T81REG_SQW_RS1	0x20		/* sqw frequency bit 1 */
+#define M41T81REG_SQW_RS2	0x40		/* sqw frequency bit 2 */
+#define M41T81REG_SQW_RS3	0x80		/* sqw frequency bit 3 */
+
+
+/*
+ * Register numbers
+ */
+
+#define M41T81REG_TSC	0x00		/* tenths/hundredths of second */
+#define M41T81REG_SC	0x01		/* seconds */
+#define M41T81REG_MN	0x02		/* minute */
+#define M41T81REG_HR	0x03		/* hour/century */
+#define M41T81REG_DY	0x04		/* day of week */
+#define M41T81REG_DT	0x05		/* date of month */
+#define M41T81REG_MO	0x06		/* month */
+#define M41T81REG_YR	0x07		/* year */
+#define M41T81REG_CTL	0x08		/* control */
+#define M41T81REG_WD	0x09		/* watchdog */
+#define M41T81REG_AMO	0x0A		/* alarm: month */
+#define M41T81REG_ADT	0x0B		/* alarm: date */
+#define M41T81REG_AHR	0x0C		/* alarm: hour */
+#define M41T81REG_AMN	0x0D		/* alarm: minute */
+#define M41T81REG_ASC	0x0E		/* alarm: second */
+#define M41T81REG_FLG	0x0F		/* flags */
+#define M41T81REG_SQW	0x13		/* square wave register */
+
+#define M41T81_CCR_ADDRESS	0x68
+
+#define SMB_CSR(reg)	IOADDR(A_SMB_REGISTER(1, reg))
+
+static int m41t81_read(uint8_t addr)
+{
+	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	__raw_writeq(addr & 0xff, SMB_CSR(R_SMB_CMD));
+	__raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_WR1BYTE,
+		     SMB_CSR(R_SMB_START));
+
+	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	__raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
+		     SMB_CSR(R_SMB_START));
+
+	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
+		/* Clear error bit by writing a 1 */
+		__raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
+		return -1;
+	}
+
+	return __raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff;
+}
+
+static int m41t81_write(uint8_t addr, int b)
+{
+	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	__raw_writeq(addr & 0xff, SMB_CSR(R_SMB_CMD));
+	__raw_writeq(b & 0xff, SMB_CSR(R_SMB_DATA));
+	__raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_WR2BYTE,
+		     SMB_CSR(R_SMB_START));
+
+	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
+		/* Clear error bit by writing a 1 */
+		__raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
+		return -1;
+	}
+
+	/* read the same byte again to make sure it is written */
+	__raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
+		     SMB_CSR(R_SMB_START));
+
+	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	return 0;
+}
+
+int m41t81_set_time(unsigned long t)
+{
+	struct rtc_time tm;
+	unsigned long flags;
+
+	/* Note we don't care about the century */
+	rtc_time_to_tm(t, &tm);
+
+	/*
+	 * Note the write order matters as it ensures the correctness.
+	 * When we write sec, 10th sec is clear.  It is reasonable to
+	 * believe we should finish writing min within a second.
+	 */
+
+	spin_lock_irqsave(&rtc_lock, flags);
+	tm.tm_sec = bin2bcd(tm.tm_sec);
+	m41t81_write(M41T81REG_SC, tm.tm_sec);
+
+	tm.tm_min = bin2bcd(tm.tm_min);
+	m41t81_write(M41T81REG_MN, tm.tm_min);
+
+	tm.tm_hour = bin2bcd(tm.tm_hour);
+	tm.tm_hour = (tm.tm_hour & 0x3f) | (m41t81_read(M41T81REG_HR) & 0xc0);
+	m41t81_write(M41T81REG_HR, tm.tm_hour);
+
+	/* tm_wday starts from 0 to 6 */
+	if (tm.tm_wday == 0) tm.tm_wday = 7;
+	tm.tm_wday = bin2bcd(tm.tm_wday);
+	m41t81_write(M41T81REG_DY, tm.tm_wday);
+
+	tm.tm_mday = bin2bcd(tm.tm_mday);
+	m41t81_write(M41T81REG_DT, tm.tm_mday);
+
+	/* tm_mon starts from 0, *ick* */
+	tm.tm_mon ++;
+	tm.tm_mon = bin2bcd(tm.tm_mon);
+	m41t81_write(M41T81REG_MO, tm.tm_mon);
+
+	/* we don't do century, everything is beyond 2000 */
+	tm.tm_year %= 100;
+	tm.tm_year = bin2bcd(tm.tm_year);
+	m41t81_write(M41T81REG_YR, tm.tm_year);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
+	return 0;
+}
+
+unsigned long m41t81_get_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	unsigned long flags;
+
+	/*
+	 * min is valid if two reads of sec are the same.
+	 */
+	for (;;) {
+		spin_lock_irqsave(&rtc_lock, flags);
+		sec = m41t81_read(M41T81REG_SC);
+		min = m41t81_read(M41T81REG_MN);
+		if (sec == m41t81_read(M41T81REG_SC)) break;
+		spin_unlock_irqrestore(&rtc_lock, flags);
+	}
+	hour = m41t81_read(M41T81REG_HR) & 0x3f;
+	day = m41t81_read(M41T81REG_DT);
+	mon = m41t81_read(M41T81REG_MO);
+	year = m41t81_read(M41T81REG_YR);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
+	sec = bcd2bin(sec);
+	min = bcd2bin(min);
+	hour = bcd2bin(hour);
+	day = bcd2bin(day);
+	mon = bcd2bin(mon);
+	year = bcd2bin(year);
+
+	year += 2000;
+
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+int m41t81_probe(void)
+{
+	unsigned int tmp;
+
+	/* enable chip if it is not enabled yet */
+	tmp = m41t81_read(M41T81REG_SC);
+	m41t81_write(M41T81REG_SC, tmp & 0x7f);
+
+	return m41t81_read(M41T81REG_SC) != -1;
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/rtc_xicor1241.c b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/rtc_xicor1241.c
new file mode 100644
index 0000000..50a82c4
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/rtc_xicor1241.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2000, 2001 Broadcom Corporation
+ *
+ * Copyright (C) 2002 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * 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 <linux/bcd.h>
+#include <linux/types.h>
+#include <linux/time.h>
+
+#include <asm/time.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_smbus.h>
+
+
+/* Xicor 1241 definitions */
+
+/*
+ * Register bits
+ */
+
+#define X1241REG_SR_BAT 0x80		/* currently on battery power */
+#define X1241REG_SR_RWEL 0x04		/* r/w latch is enabled, can write RTC */
+#define X1241REG_SR_WEL 0x02		/* r/w latch is unlocked, can enable r/w now */
+#define X1241REG_SR_RTCF 0x01		/* clock failed */
+#define X1241REG_BL_BP2 0x80		/* block protect 2 */
+#define X1241REG_BL_BP1 0x40		/* block protect 1 */
+#define X1241REG_BL_BP0 0x20		/* block protect 0 */
+#define X1241REG_BL_WD1 0x10
+#define X1241REG_BL_WD0 0x08
+#define X1241REG_HR_MIL 0x80		/* military time format */
+
+/*
+ * Register numbers
+ */
+
+#define X1241REG_BL	0x10		/* block protect bits */
+#define X1241REG_INT	0x11		/*  */
+#define X1241REG_SC	0x30		/* Seconds */
+#define X1241REG_MN	0x31		/* Minutes */
+#define X1241REG_HR	0x32		/* Hours */
+#define X1241REG_DT	0x33		/* Day of month */
+#define X1241REG_MO	0x34		/* Month */
+#define X1241REG_YR	0x35		/* Year */
+#define X1241REG_DW	0x36		/* Day of Week */
+#define X1241REG_Y2K	0x37		/* Year 2K */
+#define X1241REG_SR	0x3F		/* Status register */
+
+#define X1241_CCR_ADDRESS	0x6F
+
+#define SMB_CSR(reg)	IOADDR(A_SMB_REGISTER(1, reg))
+
+static int xicor_read(uint8_t addr)
+{
+	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	__raw_writeq((addr >> 8) & 0x7, SMB_CSR(R_SMB_CMD));
+	__raw_writeq(addr & 0xff, SMB_CSR(R_SMB_DATA));
+	__raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR2BYTE,
+		     SMB_CSR(R_SMB_START));
+
+	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	__raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
+		     SMB_CSR(R_SMB_START));
+
+	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
+		/* Clear error bit by writing a 1 */
+		__raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
+		return -1;
+	}
+
+	return __raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff;
+}
+
+static int xicor_write(uint8_t addr, int b)
+{
+	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	__raw_writeq(addr, SMB_CSR(R_SMB_CMD));
+	__raw_writeq((addr & 0xff) | ((b & 0xff) << 8), SMB_CSR(R_SMB_DATA));
+	__raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR3BYTE,
+		     SMB_CSR(R_SMB_START));
+
+	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
+		/* Clear error bit by writing a 1 */
+		__raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
+		return -1;
+	} else {
+		return 0;
+	}
+}
+
+int xicor_set_time(unsigned long t)
+{
+	struct rtc_time tm;
+	int tmp;
+	unsigned long flags;
+
+	rtc_time_to_tm(t, &tm);
+	tm.tm_year += 1900;
+
+	spin_lock_irqsave(&rtc_lock, flags);
+	/* unlock writes to the CCR */
+	xicor_write(X1241REG_SR, X1241REG_SR_WEL);
+	xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL);
+
+	/* trivial ones */
+	tm.tm_sec = bin2bcd(tm.tm_sec);
+	xicor_write(X1241REG_SC, tm.tm_sec);
+
+	tm.tm_min = bin2bcd(tm.tm_min);
+	xicor_write(X1241REG_MN, tm.tm_min);
+
+	tm.tm_mday = bin2bcd(tm.tm_mday);
+	xicor_write(X1241REG_DT, tm.tm_mday);
+
+	/* tm_mon starts from 0, *ick* */
+	tm.tm_mon ++;
+	tm.tm_mon = bin2bcd(tm.tm_mon);
+	xicor_write(X1241REG_MO, tm.tm_mon);
+
+	/* year is split */
+	tmp = tm.tm_year / 100;
+	tm.tm_year %= 100;
+	xicor_write(X1241REG_YR, tm.tm_year);
+	xicor_write(X1241REG_Y2K, tmp);
+
+	/* hour is the most tricky one */
+	tmp = xicor_read(X1241REG_HR);
+	if (tmp & X1241REG_HR_MIL) {
+		/* 24 hour format */
+		tm.tm_hour = bin2bcd(tm.tm_hour);
+		tmp = (tmp & ~0x3f) | (tm.tm_hour & 0x3f);
+	} else {
+		/* 12 hour format, with 0x2 for pm */
+		tmp = tmp & ~0x3f;
+		if (tm.tm_hour >= 12) {
+			tmp |= 0x20;
+			tm.tm_hour -= 12;
+		}
+		tm.tm_hour = bin2bcd(tm.tm_hour);
+		tmp |= tm.tm_hour;
+	}
+	xicor_write(X1241REG_HR, tmp);
+
+	xicor_write(X1241REG_SR, 0);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
+	return 0;
+}
+
+unsigned long xicor_get_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec, y2k;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rtc_lock, flags);
+	sec = xicor_read(X1241REG_SC);
+	min = xicor_read(X1241REG_MN);
+	hour = xicor_read(X1241REG_HR);
+
+	if (hour & X1241REG_HR_MIL) {
+		hour &= 0x3f;
+	} else {
+		if (hour & 0x20)
+			hour = (hour & 0xf) + 0x12;
+	}
+
+	day = xicor_read(X1241REG_DT);
+	mon = xicor_read(X1241REG_MO);
+	year = xicor_read(X1241REG_YR);
+	y2k = xicor_read(X1241REG_Y2K);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
+	sec = bcd2bin(sec);
+	min = bcd2bin(min);
+	hour = bcd2bin(hour);
+	day = bcd2bin(day);
+	mon = bcd2bin(mon);
+	year = bcd2bin(year);
+	y2k = bcd2bin(y2k);
+
+	year += (y2k * 100);
+
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+int xicor_probe(void)
+{
+	return xicor_read(X1241REG_SC) != -1;
+}
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/setup.c b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/setup.c
new file mode 100644
index 0000000..494fb0a
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/setup.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004 Broadcom Corporation
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * 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.
+ */
+
+/*
+ * Setup code for the SWARM board
+ */
+
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/screen_info.h>
+#include <linux/initrd.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/time.h>
+#include <asm/traps.h>
+#include <asm/sibyte/sb1250.h>
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+#include <asm/sibyte/bcm1480_regs.h>
+#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
+#include <asm/sibyte/sb1250_regs.h>
+#else
+#error invalid SiByte board configuration
+#endif
+#include <asm/sibyte/sb1250_genbus.h>
+#include <asm/sibyte/board.h>
+
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+extern void bcm1480_setup(void);
+#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
+extern void sb1250_setup(void);
+#else
+#error invalid SiByte board configuration
+#endif
+
+extern int xicor_probe(void);
+extern int xicor_set_time(unsigned long);
+extern unsigned long xicor_get_time(void);
+
+extern int m41t81_probe(void);
+extern int m41t81_set_time(unsigned long);
+extern unsigned long m41t81_get_time(void);
+
+const char *get_system_type(void)
+{
+	return "SiByte " SIBYTE_BOARD_NAME;
+}
+
+int swarm_be_handler(struct pt_regs *regs, int is_fixup)
+{
+	if (!is_fixup && (regs->cp0_cause & 4)) {
+		/* Data bus error - print PA */
+		printk("DBE physical address: %010Lx\n",
+		       __read_64bit_c0_register($26, 1));
+	}
+	return is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
+}
+
+enum swarm_rtc_type {
+	RTC_NONE,
+	RTC_XICOR,
+	RTC_M41T81,
+};
+
+enum swarm_rtc_type swarm_rtc_type;
+
+void read_persistent_clock(struct timespec *ts)
+{
+	unsigned long sec;
+
+	switch (swarm_rtc_type) {
+	case RTC_XICOR:
+		sec = xicor_get_time();
+		break;
+
+	case RTC_M41T81:
+		sec = m41t81_get_time();
+		break;
+
+	case RTC_NONE:
+	default:
+		sec = mktime(2000, 1, 1, 0, 0, 0);
+		break;
+	}
+	ts->tv_sec = sec;
+	ts->tv_nsec = 0;
+}
+
+int rtc_mips_set_time(unsigned long sec)
+{
+	switch (swarm_rtc_type) {
+	case RTC_XICOR:
+		return xicor_set_time(sec);
+
+	case RTC_M41T81:
+		return m41t81_set_time(sec);
+
+	case RTC_NONE:
+	default:
+		return -1;
+	}
+}
+
+void __init plat_mem_setup(void)
+{
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+	bcm1480_setup();
+#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
+	sb1250_setup();
+#else
+#error invalid SiByte board configuration
+#endif
+
+	board_be_handler = swarm_be_handler;
+
+	if (xicor_probe())
+		swarm_rtc_type = RTC_XICOR;
+	if (m41t81_probe())
+		swarm_rtc_type = RTC_M41T81;
+
+#ifdef CONFIG_VT
+	screen_info = (struct screen_info) {
+		.orig_video_page	= 52,
+		.orig_video_mode	= 3,
+		.orig_video_cols	= 80,
+		.flags			= 12,
+		.orig_video_ega_bx	= 3,
+		.orig_video_lines	= 25,
+		.orig_video_isVGA	= 0x22,
+		.orig_video_points	= 16,
+       };
+       /* XXXKW for CFE, get lines/cols from environment */
+#endif
+}
+
+#ifdef LEDS_PHYS
+
+#ifdef CONFIG_SIBYTE_CARMEL
+/* XXXKW need to detect Monterey/LittleSur/etc */
+#undef LEDS_PHYS
+#define LEDS_PHYS MLEDS_PHYS
+#endif
+
+void setleds(char *str)
+{
+	void *reg;
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		reg = IOADDR(LEDS_PHYS) + 0x20 + ((3 - i) << 3);
+
+		if (!str[i])
+			writeb(' ', reg);
+		else
+			writeb(str[i], reg);
+	}
+}
+
+#endif /* LEDS_PHYS */
diff --git a/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/swarm-i2c.c b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/swarm-i2c.c
new file mode 100644
index 0000000..0625050
--- /dev/null
+++ b/src/kernel/linux/v4.14/arch/mips/sibyte/swarm/swarm-i2c.c
@@ -0,0 +1,35 @@
+/*
+ *	Broadcom BCM91250A (SWARM), etc. I2C platform setup.
+ *
+ *	Copyright (c) 2008  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 <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+
+static struct i2c_board_info swarm_i2c_info1[] __initdata = {
+	{
+		I2C_BOARD_INFO("m41t81", 0x68),
+	},
+};
+
+static int __init swarm_i2c_init(void)
+{
+	int err;
+
+	err = i2c_register_board_info(1, swarm_i2c_info1,
+				      ARRAY_SIZE(swarm_i2c_info1));
+	if (err < 0)
+		printk(KERN_ERR
+		       "swarm-i2c: cannot register board I2C devices\n");
+	return err;
+}
+
+arch_initcall(swarm_i2c_init);