]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
openrisc: Add cpu files
authorStefan Kristiansson <stefan.kristiansson@saunalahti.fi>
Sat, 26 Nov 2011 19:04:51 +0000 (19:04 +0000)
committerWolfgang Denk <wd@denx.de>
Fri, 13 Jan 2012 20:16:44 +0000 (21:16 +0100)
Signed-off-by: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
arch/openrisc/config.mk [new file with mode: 0644]
arch/openrisc/cpu/Makefile [new file with mode: 0644]
arch/openrisc/cpu/cache.c [new file with mode: 0644]
arch/openrisc/cpu/cpu.c [new file with mode: 0644]
arch/openrisc/cpu/exceptions.c [new file with mode: 0644]
arch/openrisc/cpu/interrupts.c [new file with mode: 0644]
arch/openrisc/cpu/start.S [new file with mode: 0644]

diff --git a/arch/openrisc/config.mk b/arch/openrisc/config.mk
new file mode 100644 (file)
index 0000000..521e73a
--- /dev/null
@@ -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 (file)
index 0000000..b3b1a24
--- /dev/null
@@ -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 (file)
index 0000000..2a73a4f
--- /dev/null
@@ -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 (file)
index 0000000..25cd624
--- /dev/null
@@ -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 (file)
index 0000000..5d9f117
--- /dev/null
@@ -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 (file)
index 0000000..8f06724
--- /dev/null
@@ -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 (file)
index 0000000..3a42717
--- /dev/null
@@ -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