openrisc: Add cpu files

Signed-off-by: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
diff --git a/arch/openrisc/config.mk b/arch/openrisc/config.mk
new file mode 100644
index 0000000..521e73a
--- /dev/null
+++ b/arch/openrisc/config.mk
@@ -0,0 +1,27 @@
+#
+# (C) Copyright 2011
+# Julius Baxter <julius@opencores.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
+#
+
+CROSS_COMPILE ?= or32-elf-
+
+# r10 used for global object pointer, already set in OR32 GCC but just to be
+# clear
+PLATFORM_CPPFLAGS += -DCONFIG_OPENRISC -D__OR1K__ -ffixed-r10
+
+CONFIG_STANDALONE_LOAD_ADDR ?= 0x40000
diff --git a/arch/openrisc/cpu/Makefile b/arch/openrisc/cpu/Makefile
new file mode 100644
index 0000000..b3b1a24
--- /dev/null
+++ b/arch/openrisc/cpu/Makefile
@@ -0,0 +1,47 @@
+#
+# (C) Copyright 2011
+# Julius Baxter <julius@opencores.org>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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 $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).o
+
+START	= start.o
+COBJS-y	= cache.o cpu.o exceptions.o interrupts.o
+
+SRCS	:= $(START:.o=.S) $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS-y))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/openrisc/cpu/cache.c b/arch/openrisc/cpu/cache.c
new file mode 100644
index 0000000..2a73a4f
--- /dev/null
+++ b/arch/openrisc/cpu/cache.c
@@ -0,0 +1,151 @@
+/*
+ * (C) Copyright 2011, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * (C) Copyright 2011, Julius Baxter <julius@opencores.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
+ */
+
+#include <common.h>
+#include <asm/system.h>
+
+void flush_dcache_range(unsigned long addr, unsigned long stop)
+{
+	ulong block_size = (mfspr(SPR_DCCFGR) & SPR_DCCFGR_CBS) ? 32 : 16;
+
+	while (addr < stop) {
+		mtspr(SPR_DCBFR, addr);
+		addr += block_size;
+	}
+}
+
+void invalidate_dcache_range(unsigned long addr, unsigned long stop)
+{
+	ulong block_size = (mfspr(SPR_DCCFGR) & SPR_DCCFGR_CBS) ? 32 : 16;
+
+	while (addr < stop) {
+		mtspr(SPR_DCBIR, addr);
+		addr += block_size;
+	}
+}
+
+static void invalidate_icache_range(unsigned long addr, unsigned long stop)
+{
+	ulong block_size = (mfspr(SPR_ICCFGR) & SPR_ICCFGR_CBS) ? 32 : 16;
+
+	while (addr < stop) {
+		mtspr(SPR_ICBIR, addr);
+		addr += block_size;
+	}
+}
+
+void flush_cache(unsigned long addr, unsigned long size)
+{
+	flush_dcache_range(addr, addr + size);
+	invalidate_icache_range(addr, addr + size);
+}
+
+int icache_status(void)
+{
+	return mfspr(SPR_SR) & SPR_SR_ICE;
+}
+
+int checkicache(void)
+{
+	unsigned long iccfgr;
+	unsigned long cache_set_size;
+	unsigned long cache_ways;
+	unsigned long cache_block_size;
+
+	iccfgr = mfspr(SPR_ICCFGR);
+	cache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
+	cache_set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3);
+	cache_block_size = (iccfgr & SPR_ICCFGR_CBS) ? 32 : 16;
+
+	return cache_set_size * cache_ways * cache_block_size;
+}
+
+int dcache_status(void)
+{
+	return mfspr(SPR_SR) & SPR_SR_DCE;
+}
+
+int checkdcache(void)
+{
+	unsigned long dccfgr;
+	unsigned long cache_set_size;
+	unsigned long cache_ways;
+	unsigned long cache_block_size;
+
+	dccfgr = mfspr(SPR_DCCFGR);
+	cache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW);
+	cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3);
+	cache_block_size = (dccfgr & SPR_DCCFGR_CBS) ? 32 : 16;
+
+	return cache_set_size * cache_ways * cache_block_size;
+}
+
+void dcache_enable(void)
+{
+	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_DCE);
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+}
+
+void dcache_disable(void)
+{
+	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_DCE);
+}
+
+void icache_enable(void)
+{
+	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_ICE);
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+	asm volatile("l.nop");
+}
+
+void icache_disable(void)
+{
+	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_ICE);
+}
+
+int cache_init(void)
+{
+	if (mfspr(SPR_UPR) & SPR_UPR_ICP) {
+		icache_disable();
+		invalidate_icache_range(0, checkicache());
+		icache_enable();
+	}
+
+	if (mfspr(SPR_UPR) & SPR_UPR_DCP) {
+		dcache_disable();
+		invalidate_dcache_range(0, checkdcache());
+		dcache_enable();
+	}
+
+	return 0;
+}
diff --git a/arch/openrisc/cpu/cpu.c b/arch/openrisc/cpu/cpu.c
new file mode 100644
index 0000000..25cd624
--- /dev/null
+++ b/arch/openrisc/cpu/cpu.c
@@ -0,0 +1,157 @@
+/*
+ * (C) Copyright 2011, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * (C) Copyright 2011, Julius Baxter <julius@opencores.org>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <common.h>
+#include <asm/system.h>
+#include <asm/openrisc_exc.h>
+
+static volatile int illegal_instruction;
+
+static void illegal_instruction_handler(void)
+{
+	ulong *epcr = (ulong *)mfspr(SPR_EPCR_BASE);
+
+	/* skip over the illegal instruction */
+	mtspr(SPR_EPCR_BASE, (ulong)(++epcr));
+	illegal_instruction = 1;
+}
+
+static void checkinstructions(void)
+{
+	ulong ra = 1, rb = 1, rc;
+
+	exception_install_handler(EXC_ILLEGAL_INSTR,
+				illegal_instruction_handler);
+
+	illegal_instruction = 0;
+	asm volatile("l.mul %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb));
+	printf("           Hardware multiplier: %s\n",
+		illegal_instruction ? "no" : "yes");
+
+	illegal_instruction = 0;
+	asm volatile("l.div %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb));
+	printf("           Hardware divider: %s\n",
+		illegal_instruction ? "no" : "yes");
+
+	exception_free_handler(EXC_ILLEGAL_INSTR);
+}
+
+int checkcpu(void)
+{
+	ulong upr = mfspr(SPR_UPR);
+	ulong vr = mfspr(SPR_VR);
+	ulong iccfgr = mfspr(SPR_ICCFGR);
+	ulong dccfgr = mfspr(SPR_DCCFGR);
+	ulong immucfgr = mfspr(SPR_IMMUCFGR);
+	ulong dmmucfgr = mfspr(SPR_DMMUCFGR);
+	ulong cpucfgr = mfspr(SPR_CPUCFGR);
+	uint ver = (vr & SPR_VR_VER) >> 24;
+	uint rev = vr & SPR_VR_REV;
+	uint block_size;
+	uint ways;
+	uint sets;
+
+	printf("CPU:   OpenRISC-%x00 (rev %d) @ %d MHz\n",
+		ver, rev, (CONFIG_SYS_CLK_FREQ / 1000000));
+
+	if (upr & SPR_UPR_DCP) {
+		block_size = (dccfgr & SPR_DCCFGR_CBS) ? 32 : 16;
+		ways = 1 << (dccfgr & SPR_DCCFGR_NCW);
+		printf("       D-Cache: %d bytes, %d bytes/line, %d way(s)\n",
+		       checkdcache(), block_size, ways);
+	} else {
+		printf("       D-Cache: no\n");
+	}
+
+	if (upr & SPR_UPR_ICP) {
+		block_size = (iccfgr & SPR_ICCFGR_CBS) ? 32 : 16;
+		ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
+		printf("       I-Cache: %d bytes, %d bytes/line, %d way(s)\n",
+		       checkicache(), block_size, ways);
+	} else {
+		printf("       I-Cache: no\n");
+	}
+
+	if (upr & SPR_UPR_DMP) {
+		sets = 1 << ((dmmucfgr & SPR_DMMUCFGR_NTS) >> 2);
+		ways = (dmmucfgr & SPR_DMMUCFGR_NTW) + 1;
+		printf("       DMMU: %d sets, %d way(s)\n",
+		       sets, ways);
+	} else {
+		printf("       DMMU: no\n");
+	}
+
+	if (upr & SPR_UPR_IMP) {
+		sets = 1 << ((immucfgr & SPR_IMMUCFGR_NTS) >> 2);
+		ways = (immucfgr & SPR_IMMUCFGR_NTW) + 1;
+		printf("       IMMU: %d sets, %d way(s)\n",
+		       sets, ways);
+	} else {
+		printf("       IMMU: no\n");
+	}
+
+	printf("       MAC unit: %s\n",
+		(upr & SPR_UPR_MP) ? "yes" : "no");
+	printf("       Debug unit: %s\n",
+		(upr & SPR_UPR_DUP) ? "yes" : "no");
+	printf("       Performance counters: %s\n",
+		(upr & SPR_UPR_PCUP) ? "yes" : "no");
+	printf("       Power management: %s\n",
+		(upr & SPR_UPR_PMP) ? "yes" : "no");
+	printf("       Interrupt controller: %s\n",
+		(upr & SPR_UPR_PICP) ? "yes" : "no");
+	printf("       Timer: %s\n",
+		(upr & SPR_UPR_TTP) ? "yes" : "no");
+	printf("       Custom unit(s): %s\n",
+		(upr & SPR_UPR_CUP) ? "yes" : "no");
+
+	printf("       Supported instructions:\n");
+	printf("           ORBIS32: %s\n",
+		(cpucfgr & SPR_CPUCFGR_OB32S) ? "yes" : "no");
+	printf("           ORBIS64: %s\n",
+		(cpucfgr & SPR_CPUCFGR_OB64S) ? "yes" : "no");
+	printf("           ORFPX32: %s\n",
+		(cpucfgr & SPR_CPUCFGR_OF32S) ? "yes" : "no");
+	printf("           ORFPX64: %s\n",
+		(cpucfgr & SPR_CPUCFGR_OF64S) ? "yes" : "no");
+
+	checkinstructions();
+
+	return 0;
+}
+
+int cleanup_before_linux(void)
+{
+	disable_interrupts();
+	return 0;
+}
+
+extern void __reset(void);
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	disable_interrupts();
+	__reset();
+	/* not reached, __reset does not return */
+	return 0;
+}
diff --git a/arch/openrisc/cpu/exceptions.c b/arch/openrisc/cpu/exceptions.c
new file mode 100644
index 0000000..5d9f117
--- /dev/null
+++ b/arch/openrisc/cpu/exceptions.c
@@ -0,0 +1,85 @@
+/*
+ * (C) Copyright 2011, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * (C) Copyright 2011, Julius Baxter <julius@opencores.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
+ */
+
+#include <common.h>
+#include <stdio_dev.h>
+#include <asm/system.h>
+
+static const char * const excp_table[] = {
+	"Unknown exception",
+	"Reset",
+	"Bus Error",
+	"Data Page Fault",
+	"Instruction Page Fault",
+	"Tick Timer",
+	"Alignment",
+	"Illegal Instruction",
+	"External Interrupt",
+	"D-TLB Miss",
+	"I-TLB Miss",
+	"Range",
+	"System Call",
+	"Floating Point",
+	"Trap",
+};
+
+static void (*handlers[32])(void);
+
+void exception_install_handler(int exception, void (*handler)(void))
+{
+	if (exception < 0 || exception > 31)
+		return;
+
+	handlers[exception] = handler;
+}
+
+void exception_free_handler(int exception)
+{
+	if (exception < 0 || exception > 31)
+		return;
+
+	handlers[exception] = 0;
+}
+
+static void exception_hang(int vect)
+{
+	printf("Unhandled exception at 0x%x ", vect & 0xff00);
+
+	vect = ((vect >> 8) & 0xff);
+	if (vect < ARRAY_SIZE(excp_table))
+		printf("(%s)\n", excp_table[vect]);
+	else
+		printf("(%s)\n", excp_table[0]);
+
+	printf("EPCR: 0x%08lx\n", mfspr(SPR_EPCR_BASE));
+	printf("EEAR: 0x%08lx\n", mfspr(SPR_EEAR_BASE));
+	printf("ESR:  0x%08lx\n", mfspr(SPR_ESR_BASE));
+	hang();
+}
+
+void exception_handler(int vect)
+{
+	int exception = vect >> 8;
+
+	if (handlers[exception])
+		handlers[exception]();
+	else
+		exception_hang(vect);
+}
diff --git a/arch/openrisc/cpu/interrupts.c b/arch/openrisc/cpu/interrupts.c
new file mode 100644
index 0000000..8f06724
--- /dev/null
+++ b/arch/openrisc/cpu/interrupts.c
@@ -0,0 +1,121 @@
+/*
+ * (C) Copyright 2011, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * (C) Copyright 2011, Julius Baxter <julius@opencores.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
+ */
+
+#include <common.h>
+#include <asm/types.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/openrisc_exc.h>
+
+struct irq_action {
+	interrupt_handler_t *handler;
+	void *arg;
+	int count;
+};
+
+static struct irq_action handlers[32];
+
+void interrupt_handler(void)
+{
+	int irq;
+
+	while ((irq = ffs(mfspr(SPR_PICSR)))) {
+		if (handlers[--irq].handler) {
+			handlers[irq].handler(handlers[irq].arg);
+			handlers[irq].count++;
+		} else {
+			/* disable the interrupt */
+			mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1 << irq));
+			printf("Unhandled interrupt: %d\n", irq);
+		}
+		/* clear the interrupt */
+		mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1 << irq));
+	}
+}
+
+int interrupt_init(void)
+{
+	/* install handler for external interrupt exception */
+	exception_install_handler(EXC_EXT_IRQ, interrupt_handler);
+	/* Enable interrupts in supervisor register */
+	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE);
+
+	return 0;
+}
+
+void enable_interrupts(void)
+{
+	/* Set interrupt enable bit in supervisor register */
+	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE);
+	/* Enable timer exception */
+	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_TEE);
+}
+
+int disable_interrupts(void)
+{
+	/* Clear interrupt enable bit in supervisor register */
+	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_IEE);
+	/* Disable timer exception */
+	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_TEE);
+
+	return 0;
+}
+
+void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg)
+{
+	if (irq < 0 || irq > 31)
+		return;
+
+	handlers[irq].handler = handler;
+	handlers[irq].arg = arg;
+}
+
+void irq_free_handler(int irq)
+{
+	if (irq < 0 || irq > 31)
+		return;
+
+	handlers[irq].handler = 0;
+	handlers[irq].arg = 0;
+}
+
+#if defined(CONFIG_CMD_IRQ)
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int i;
+
+	printf("\nInterrupt-Information:\n\n");
+	printf("Nr  Routine   Arg       Count\n");
+	printf("-----------------------------\n");
+
+	for (i = 0; i < 32; i++) {
+		if (handlers[i].handler) {
+			printf("%02d  %08lx  %08lx  %d\n",
+				i,
+				(ulong)handlers[i].handler,
+				(ulong)handlers[i].arg,
+				handlers[i].count);
+		}
+	}
+	printf("\n");
+
+	return 0;
+}
+#endif
diff --git a/arch/openrisc/cpu/start.S b/arch/openrisc/cpu/start.S
new file mode 100644
index 0000000..3a42717
--- /dev/null
+++ b/arch/openrisc/cpu/start.S
@@ -0,0 +1,335 @@
+/*
+ * (C) Copyright 2011, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * (C) Copyright 2011, Julius Baxter <julius@opencores.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
+ */
+
+#include <config.h>
+#include <asm-offsets.h>
+#include <asm/spr-defs.h>
+
+#define EXCEPTION_STACK_SIZE (128+128)
+
+#define HANDLE_EXCEPTION			\
+	l.addi	r1, r1, -EXCEPTION_STACK_SIZE	;\
+	l.sw	0x1c(r1), r9			;\
+	l.jal	_exception_handler		;\
+	 l.nop					;\
+	l.lwz 	r9, 0x1c(r1)			;\
+	l.addi	r1, r1, EXCEPTION_STACK_SIZE	;\
+	l.rfe					;\
+	 l.nop
+
+	.section .vectors, "ax"
+	.global __reset
+
+	/* reset */
+	.org	0x100
+__reset:
+	/* there is no guarantee r0 is hardwired to zero, clear it here */
+	l.andi	r0, r0, 0
+	/* reset stack and frame pointers */
+	l.andi	r1, r0, 0
+	l.andi	r2, r0, 0
+
+	/* set supervisor mode */
+	l.ori	r3,r0,SPR_SR_SM
+	l.mtspr	r0,r3,SPR_SR
+
+	/* Relocate u-boot */
+	l.movhi	r3,hi(__start)		/* source start address */
+	l.ori	r3,r3,lo(__start)
+	l.movhi	r4,hi(_stext)		/* dest start address */
+	l.ori	r4,r4,lo(_stext)
+	l.movhi	r5,hi(__end)		/* dest end address */
+	l.ori	r5,r5,lo(__end)
+
+.L_reloc:
+	l.lwz	r6,0(r3)
+	l.sw	0(r4),r6
+	l.addi	r3,r3,4
+	l.sfltu	r4,r5
+	l.bf	.L_reloc
+	 l.addi	r4,r4,4			/* delay slot */
+
+#ifdef CONFIG_SYS_RELOCATE_VECTORS
+	/* Relocate vectors from 0xf0000000 to 0x00000000 */
+	l.movhi r4, 0xf000 /* source */
+	l.movhi r5, 0      /* destination */
+	l.addi	r6, r5, CONFIG_SYS_VECTORS_LEN /* length */
+.L_relocvectors:
+	l.lwz	r7, 0(r4)
+	l.sw	0(r5), r7
+	l.addi	r5, r5, 4
+	l.sfeq	r5,r6
+	l.bnf	.L_relocvectors
+	 l.addi	r4,r4, 4
+#endif
+
+	l.j	_start
+	 l.nop
+
+	/* bus error */
+	.org	0x200
+	HANDLE_EXCEPTION
+
+	/* data page fault */
+	.org	0x300
+	HANDLE_EXCEPTION
+
+	/* instruction page fault */
+	.org	0x400
+	HANDLE_EXCEPTION
+
+	/* tick timer */
+	.org	0x500
+	HANDLE_EXCEPTION
+
+	/* alignment */
+	.org	0x600
+	HANDLE_EXCEPTION
+
+	/* illegal instruction */
+	.org	0x700
+	HANDLE_EXCEPTION
+
+	/* external interrupt */
+	.org	0x800
+	HANDLE_EXCEPTION
+
+	/* D-TLB miss */
+	.org	0x900
+	HANDLE_EXCEPTION
+
+	/* I-TLB miss */
+	.org	0xa00
+	HANDLE_EXCEPTION
+
+	/* range */
+	.org	0xb00
+	HANDLE_EXCEPTION
+
+	/* system call */
+	.org	0xc00
+	HANDLE_EXCEPTION
+
+	/* floating point */
+	.org	0xd00
+	HANDLE_EXCEPTION
+
+	/* trap */
+	.org	0xe00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0xf00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1100
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1200
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1300
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1400
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1500
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1600
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1700
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1800
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1900
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1a00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1b00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1c00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1d00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1e00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1f00
+	HANDLE_EXCEPTION
+
+	/* Startup routine */
+	.text
+	.global _start
+_start:
+	/* Init stack and frame pointers */
+	l.movhi	r1, hi(CONFIG_SYS_INIT_SP_ADDR)
+	l.ori	r1, r1, lo(CONFIG_SYS_INIT_SP_ADDR)
+	l.or	r2, r0, r1
+
+	/* clear BSS segments */
+	l.movhi	r4, hi(_bss_start)
+	l.ori	r4, r4, lo(_bss_start)
+	l.movhi	r5, hi(_bss_end)
+	l.ori	r5, r5, lo(_bss_end)
+.L_clear_bss:
+	l.sw	0(r4), r0
+	l.sfltu	r4,r5
+	l.bf	.L_clear_bss
+	 l.addi	r4,r4,4
+
+	/* Reset registers before jumping to board_init */
+	l.andi	r3, r0, 0
+	l.andi	r4, r0, 0
+	l.andi	r5, r0, 0
+	l.andi	r6, r0, 0
+	l.andi	r7, r0, 0
+	l.andi	r8, r0, 0
+	l.andi	r9, r0, 0
+	l.andi	r10, r0, 0
+	l.andi	r11, r0, 0
+	l.andi	r12, r0, 0
+	l.andi	r13, r0, 0
+	l.andi	r14, r0, 0
+	l.andi	r15, r0, 0
+	l.andi	r17, r0, 0
+	l.andi	r18, r0, 0
+	l.andi	r19, r0, 0
+	l.andi	r20, r0, 0
+	l.andi	r21, r0, 0
+	l.andi	r22, r0, 0
+	l.andi	r23, r0, 0
+	l.andi	r24, r0, 0
+	l.andi	r25, r0, 0
+	l.andi	r26, r0, 0
+	l.andi	r27, r0, 0
+	l.andi	r28, r0, 0
+	l.andi	r29, r0, 0
+	l.andi	r30, r0, 0
+	l.andi	r31, r0, 0
+
+	l.j	board_init
+	 l.nop
+
+	.size	_start, .-_start
+
+/*
+ * Store state onto stack and call the real exception handler
+ */
+	.section .text
+	.extern	exception_handler
+	.type	_exception_handler,@function
+
+_exception_handler:
+	/* Store state (r9 already saved)*/
+	l.sw	0x00(r1), r2
+	l.sw	0x04(r1), r3
+	l.sw	0x08(r1), r4
+	l.sw	0x0c(r1), r5
+	l.sw	0x10(r1), r6
+	l.sw	0x14(r1), r7
+	l.sw	0x18(r1), r8
+	l.sw	0x20(r1), r10
+	l.sw	0x24(r1), r11
+	l.sw	0x28(r1), r12
+	l.sw	0x2c(r1), r13
+	l.sw	0x30(r1), r14
+	l.sw	0x34(r1), r15
+	l.sw	0x38(r1), r16
+	l.sw	0x3c(r1), r17
+	l.sw	0x40(r1), r18
+	l.sw	0x44(r1), r19
+	l.sw	0x48(r1), r20
+	l.sw	0x4c(r1), r21
+	l.sw	0x50(r1), r22
+	l.sw	0x54(r1), r23
+	l.sw	0x58(r1), r24
+	l.sw	0x5c(r1), r25
+	l.sw	0x60(r1), r26
+	l.sw	0x64(r1), r27
+	l.sw	0x68(r1), r28
+	l.sw	0x6c(r1), r29
+	l.sw	0x70(r1), r30
+	l.sw	0x74(r1), r31
+
+	/* Save return address */
+	l.or	r14, r0, r9
+	/* Call exception handler with the link address as argument */
+	l.jal	exception_handler
+	 l.or	r3, r0, r14
+	/* Load return address */
+	l.or	r9, r0, r14
+
+	/* Restore state */
+	l.lwz	r2, 0x00(r1)
+	l.lwz	r3, 0x04(r1)
+	l.lwz	r4, 0x08(r1)
+	l.lwz	r5, 0x0c(r1)
+	l.lwz	r6, 0x10(r1)
+	l.lwz	r7, 0x14(r1)
+	l.lwz	r8, 0x18(r1)
+	l.lwz	r10, 0x20(r1)
+	l.lwz	r11, 0x24(r1)
+	l.lwz	r12, 0x28(r1)
+	l.lwz	r13, 0x2c(r1)
+	l.lwz	r14, 0x30(r1)
+	l.lwz	r15, 0x34(r1)
+	l.lwz	r16, 0x38(r1)
+	l.lwz	r17, 0x3c(r1)
+	l.lwz	r18, 0x40(r1)
+	l.lwz	r19, 0x44(r1)
+	l.lwz	r20, 0x48(r1)
+	l.lwz	r21, 0x4c(r1)
+	l.lwz	r22, 0x50(r1)
+	l.lwz	r23, 0x54(r1)
+	l.lwz	r24, 0x58(r1)
+	l.lwz	r25, 0x5c(r1)
+	l.lwz	r26, 0x60(r1)
+	l.lwz	r27, 0x64(r1)
+	l.lwz	r28, 0x68(r1)
+	l.lwz	r29, 0x6c(r1)
+	l.lwz	r30, 0x70(r1)
+	l.lwz	r31, 0x74(r1)
+	l.jr	r9
+	 l.nop