blackfin: Move cpu/blackfin/* to arch/blackfin/cpu/*

Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
diff --git a/arch/blackfin/cpu/.gitignore b/arch/blackfin/cpu/.gitignore
new file mode 100644
index 0000000..0ec9d56
--- /dev/null
+++ b/arch/blackfin/cpu/.gitignore
@@ -0,0 +1 @@
+bootrom-asm-offsets.[chs]
diff --git a/arch/blackfin/cpu/Makefile b/arch/blackfin/cpu/Makefile
new file mode 100644
index 0000000..211b8d5
--- /dev/null
+++ b/arch/blackfin/cpu/Makefile
@@ -0,0 +1,73 @@
+#
+# U-boot - Makefile
+#
+# Copyright (c) 2005-2008 Analog Device Inc.
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# Licensed under the GPL-2 or later.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).a
+
+EXTRA    :=
+CEXTRA   := initcode.o
+SEXTRA   := start.o
+SOBJS    := interrupt.o cache.o
+COBJS-y  += cpu.o
+COBJS-y  += interrupts.o
+COBJS-$(CONFIG_JTAG_CONSOLE) += jtag-console.o
+COBJS-y  += os_log.o
+COBJS-y  += reset.o
+COBJS-y  += serial.o
+COBJS-y  += traps.o
+COBJS-$(CONFIG_HW_WATCHDOG)  += watchdog.o
+
+ifeq ($(CONFIG_BFIN_BOOT_MODE),BFIN_BOOT_BYPASS)
+COBJS-y  += initcode.o
+endif
+
+SRCS     := $(SEXTRA:.o=.S) $(SOBJS:.o=.S) $(COBJS-y:.o=.c)
+OBJS     := $(addprefix $(obj),$(COBJS-y) $(SOBJS))
+EXTRA    := $(addprefix $(obj),$(EXTRA))
+CEXTRA   := $(addprefix $(obj),$(CEXTRA))
+SEXTRA   := $(addprefix $(obj),$(SEXTRA))
+
+all:	$(obj).depend $(LIB) $(obj).depend $(EXTRA) $(CEXTRA) $(SEXTRA) check_initcode
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+$(OBJS): $(obj)bootrom-asm-offsets.h
+$(obj)bootrom-asm-offsets.c: bootrom-asm-offsets.c.in bootrom-asm-offsets.awk
+	echo '#include <asm/mach-common/bits/bootrom.h>' | $(CPP) $(CPPFLAGS) - | gawk -f ./bootrom-asm-offsets.awk > $@.tmp
+	mv $@.tmp $@
+$(obj)bootrom-asm-offsets.s: $(obj)bootrom-asm-offsets.c
+	$(CC) $(CFLAGS) -S $^ -o $@.tmp
+	mv $@.tmp $@
+$(obj)bootrom-asm-offsets.h: $(obj)bootrom-asm-offsets.s
+	sed -ne "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}" $^ > $@
+
+# make sure our initcode (which goes into LDR) does not
+# have relocs or external references
+$(obj)initcode.o: CFLAGS += -fno-function-sections -fno-data-sections
+READINIT = env LC_ALL=C $(CROSS_COMPILE)readelf -s $<
+check_initcode: $(obj)initcode.o
+ifneq ($(CONFIG_BFIN_BOOT_MODE),BFIN_BOOT_BYPASS)
+	@if $(READINIT) | grep '\<GLOBAL\>.*\<UND\>' ; then \
+		echo "$< contains external references!" 1>&2 ; \
+		exit 1 ; \
+	fi
+endif
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/blackfin/cpu/bootrom-asm-offsets.awk b/arch/blackfin/cpu/bootrom-asm-offsets.awk
new file mode 100755
index 0000000..1d61824
--- /dev/null
+++ b/arch/blackfin/cpu/bootrom-asm-offsets.awk
@@ -0,0 +1,41 @@
+#!/usr/bin/gawk -f
+BEGIN {
+	print "/* DO NOT EDIT: AUTOMATICALLY GENERATED"
+	print " * Input files: bootrom-asm-offsets.awk bootrom-asm-offsets.c.in"
+	print " * DO NOT EDIT: AUTOMATICALLY GENERATED"
+	print " */"
+	print ""
+	system("cat bootrom-asm-offsets.c.in")
+	print "{"
+}
+
+{
+	/* find a structure definition */
+	if ($0 ~ /typedef struct .* {/) {
+		delete members;
+		i = 0;
+
+		/* extract each member of the structure */
+		while (1) {
+			getline
+			if ($1 == "}")
+				break;
+			gsub(/[*;]/, "");
+			members[i++] = $NF;
+		}
+
+		/* grab the structure's name */
+		struct = $NF;
+		sub(/;$/, "", struct);
+
+		/* output the DEFINE() macros */
+		while (i-- > 0)
+			print "\tDEFINE(" struct ", " members[i] ");"
+		print ""
+	}
+}
+
+END {
+	print "\treturn 0;"
+	print "}"
+}
diff --git a/arch/blackfin/cpu/bootrom-asm-offsets.c.in b/arch/blackfin/cpu/bootrom-asm-offsets.c.in
new file mode 100644
index 0000000..3146e46
--- /dev/null
+++ b/arch/blackfin/cpu/bootrom-asm-offsets.c.in
@@ -0,0 +1,12 @@
+/* A little trick taken from the kernel asm-offsets.h where we convert
+ * the C structures automatically into a bunch of defines for use in
+ * the assembly files.
+ */
+
+#include <linux/stddef.h>
+#include <asm/mach-common/bits/bootrom.h>
+
+#define _DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+#define DEFINE(s, m) _DEFINE(offset_##s##_##m, offsetof(s, m))
+
+int main(int argc, char *argv[])
diff --git a/arch/blackfin/cpu/cache.S b/arch/blackfin/cpu/cache.S
new file mode 100644
index 0000000..6ed655a
--- /dev/null
+++ b/arch/blackfin/cpu/cache.S
@@ -0,0 +1,87 @@
+/*
+ * Blackfin cache control code
+ *
+ * Copyright 2003-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <asm/linkage.h>
+#include <config.h>
+#include <asm/blackfin.h>
+
+.text
+/* Since all L1 caches work the same way, we use the same method for flushing
+ * them.  Only the actual flush instruction differs.  We write this in asm as
+ * GCC can be hard to coax into writing nice hardware loops.
+ *
+ * Also, we assume the following register setup:
+ * R0 = start address
+ * R1 = end address
+ */
+.macro do_flush flushins:req optflushins optnopins label
+
+	R2 = -L1_CACHE_BYTES;
+
+	/* start = (start & -L1_CACHE_BYTES) */
+	R0 = R0 & R2;
+
+	/* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */
+	R1 += -1;
+	R1 = R1 & R2;
+	R1 += L1_CACHE_BYTES;
+
+	/* count = (end - start) >> L1_CACHE_SHIFT */
+	R2 = R1 - R0;
+	R2 >>= L1_CACHE_SHIFT;
+	P1 = R2;
+
+.ifnb \label
+\label :
+.endif
+	P0 = R0;
+	LSETUP (1f, 2f) LC1 = P1;
+1:
+.ifnb \optflushins
+	\optflushins [P0];
+.endif
+#if ANOMALY_05000443
+.ifb \optnopins
+2:
+.endif
+	\flushins [P0++];
+.ifnb \optnopins
+2:	\optnopins;
+.endif
+#else
+2:	\flushins [P0++];
+#endif
+
+	RTS;
+.endm
+
+/* Invalidate all instruction cache lines assocoiated with this memory area */
+ENTRY(_blackfin_icache_flush_range)
+	do_flush IFLUSH, , nop
+ENDPROC(_blackfin_icache_flush_range)
+
+/* Flush all cache lines assocoiated with this area of memory. */
+ENTRY(_blackfin_icache_dcache_flush_range)
+	do_flush FLUSH, IFLUSH
+ENDPROC(_blackfin_icache_dcache_flush_range)
+
+/* Throw away all D-cached data in specified region without any obligation to
+ * write them back.  Since the Blackfin ISA does not have an "invalidate"
+ * instruction, we use flush/invalidate.  Perhaps as a speed optimization we
+ * could bang on the DTEST MMRs ...
+ */
+ENTRY(_blackfin_dcache_flush_invalidate_range)
+	do_flush FLUSHINV
+ENDPROC(_blackfin_dcache_flush_invalidate_range)
+
+/* Flush all data cache lines assocoiated with this memory area */
+ENTRY(_blackfin_dcache_flush_range)
+	do_flush FLUSH, , , .Ldfr
+ENDPROC(_blackfin_dcache_flush_range)
diff --git a/arch/blackfin/cpu/cpu.c b/arch/blackfin/cpu/cpu.c
new file mode 100644
index 0000000..2c8fd86
--- /dev/null
+++ b/arch/blackfin/cpu/cpu.c
@@ -0,0 +1,112 @@
+/*
+ * U-boot - cpu.c CPU specific functions
+ *
+ * Copyright (c) 2005-2008 Analog Devices Inc.
+ *
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/blackfin.h>
+#include <asm/cplb.h>
+#include <asm/mach-common/bits/core.h>
+#include <asm/mach-common/bits/ebiu.h>
+#include <asm/mach-common/bits/trace.h>
+
+#include "cpu.h"
+#include "serial.h"
+
+ulong bfin_poweron_retx;
+
+__attribute__ ((__noreturn__))
+void cpu_init_f(ulong bootflag, ulong loaded_from_ldr)
+{
+#ifndef CONFIG_BFIN_BOOTROM_USES_EVT1
+	/* Build a NOP slide over the LDR jump block.  Whee! */
+	char nops[0xC];
+	serial_early_puts("NOP Slide\n");
+	memset(nops, 0x00, sizeof(nops));
+	memcpy((void *)L1_INST_SRAM, nops, sizeof(nops));
+#endif
+
+	if (!loaded_from_ldr) {
+		/* Relocate sections into L1 if the LDR didn't do it -- don't
+		 * check length because the linker script does the size
+		 * checking at build time.
+		 */
+		serial_early_puts("L1 Relocate\n");
+		extern char _stext_l1[], _text_l1_lma[], _text_l1_len[];
+		memcpy(&_stext_l1, &_text_l1_lma, (unsigned long)_text_l1_len);
+		extern char _sdata_l1[], _data_l1_lma[], _data_l1_len[];
+		memcpy(&_sdata_l1, &_data_l1_lma, (unsigned long)_data_l1_len);
+	}
+#if defined(__ADSPBF537__) || defined(__ADSPBF536__) || defined(__ADSPBF534__)
+	/* The BF537 bootrom will reset the EBIU_AMGCTL register on us
+	 * after it has finished loading the LDR.  So configure it again.
+	 */
+	else
+		bfin_write_EBIU_AMGCTL(CONFIG_EBIU_AMGCTL_VAL);
+#endif
+
+	/* Save RETX so we can pass it while booting Linux */
+	bfin_poweron_retx = bootflag;
+
+#ifdef CONFIG_DEBUG_DUMP
+	/* Turn on hardware trace buffer */
+	bfin_write_TBUFCTL(TBUFPWR | TBUFEN);
+#endif
+
+#ifndef CONFIG_PANIC_HANG
+	/* Reset upon a double exception rather than just hanging.
+	 * Do not do bfin_read on SWRST as that will reset status bits.
+	 */
+	bfin_write_SWRST(DOUBLE_FAULT);
+#endif
+
+	serial_early_puts("Board init flash\n");
+	board_init_f(bootflag);
+}
+
+int exception_init(void)
+{
+	bfin_write_EVT3(trap);
+	return 0;
+}
+
+int irq_init(void)
+{
+#ifdef SIC_IMASK0
+	bfin_write_SIC_IMASK0(0);
+	bfin_write_SIC_IMASK1(0);
+# ifdef SIC_IMASK2
+	bfin_write_SIC_IMASK2(0);
+# endif
+#elif defined(SICA_IMASK0)
+	bfin_write_SICA_IMASK0(0);
+	bfin_write_SICA_IMASK1(0);
+#else
+	bfin_write_SIC_IMASK(0);
+#endif
+	bfin_write_EVT2(evt_default);	/* NMI */
+	bfin_write_EVT5(evt_default);	/* hardware error */
+	bfin_write_EVT6(evt_default);	/* core timer */
+	bfin_write_EVT7(evt_default);
+	bfin_write_EVT8(evt_default);
+	bfin_write_EVT9(evt_default);
+	bfin_write_EVT10(evt_default);
+	bfin_write_EVT11(evt_default);
+	bfin_write_EVT12(evt_default);
+	bfin_write_EVT13(evt_default);
+	bfin_write_EVT14(evt_default);
+	bfin_write_EVT15(evt_default);
+	bfin_write_ILAT(0);
+	CSYNC();
+	/* enable hardware error irq */
+	irq_flags = 0x3f;
+	local_irq_enable();
+	return 0;
+}
diff --git a/arch/blackfin/cpu/cpu.h b/arch/blackfin/cpu/cpu.h
new file mode 100644
index 0000000..0a13c28
--- /dev/null
+++ b/arch/blackfin/cpu/cpu.h
@@ -0,0 +1,38 @@
+/*
+ *  U-boot - cpu.h
+ *
+ *  Copyright (c) 2005-2007 Analog Devices Inc.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef _CPU_H_
+#define _CPU_H_
+
+#include <command.h>
+
+void board_reset(void) __attribute__((__weak__));
+void bfin_reset_or_hang(void) __attribute__((__noreturn__));
+void bfin_panic(struct pt_regs *reg);
+void dump(struct pt_regs *regs);
+
+asmlinkage void trap(void);
+asmlinkage void evt_default(void);
+
+#endif
diff --git a/arch/blackfin/cpu/initcode.c b/arch/blackfin/cpu/initcode.c
new file mode 100644
index 0000000..5f80ad6
--- /dev/null
+++ b/arch/blackfin/cpu/initcode.c
@@ -0,0 +1,687 @@
+/*
+ * initcode.c - Initialize the processor.  This is usually entails things
+ * like external memory, voltage regulators, etc...  Note that this file
+ * cannot make any function calls as it may be executed all by itself by
+ * the Blackfin's bootrom in LDR format.
+ *
+ * Copyright (c) 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#define BFIN_IN_INITCODE
+
+#include <config.h>
+#include <asm/blackfin.h>
+#include <asm/mach-common/bits/bootrom.h>
+#include <asm/mach-common/bits/core.h>
+#include <asm/mach-common/bits/ebiu.h>
+#include <asm/mach-common/bits/pll.h>
+#include <asm/mach-common/bits/uart.h>
+
+#include "serial.h"
+
+__attribute__((always_inline))
+static inline void serial_init(void)
+{
+#ifdef __ADSPBF54x__
+# ifdef BFIN_BOOT_UART_USE_RTS
+#  define BFIN_UART_USE_RTS 1
+# else
+#  define BFIN_UART_USE_RTS 0
+# endif
+	if (BFIN_UART_USE_RTS && CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) {
+		size_t i;
+
+		/* force RTS rather than relying on auto RTS */
+		bfin_write16(&pUART->mcr, bfin_read16(&pUART->mcr) | FCPOL);
+
+		/* Wait for the line to clear up.  We cannot rely on UART
+		 * registers as none of them reflect the status of the RSR.
+		 * Instead, we'll sleep for ~10 bit times at 9600 baud.
+		 * We can precalc things here by assuming boot values for
+		 * PLL rather than loading registers and calculating.
+		 *	baud    = SCLK / (16 ^ (1 - EDBO) * Divisor)
+		 *	EDB0    = 0
+		 *	Divisor = (SCLK / baud) / 16
+		 *	SCLK    = baud * 16 * Divisor
+		 *	SCLK    = (0x14 * CONFIG_CLKIN_HZ) / 5
+		 *	CCLK    = (16 * Divisor * 5) * (9600 / 10)
+		 * In reality, this will probably be just about 1 second delay,
+		 * so assuming 9600 baud is OK (both as a very low and too high
+		 * speed as this will buffer things enough).
+		 */
+#define _NUMBITS (10)                                   /* how many bits to delay */
+#define _LOWBAUD (9600)                                 /* low baud rate */
+#define _SCLK    ((0x14 * CONFIG_CLKIN_HZ) / 5)         /* SCLK based on PLL */
+#define _DIVISOR ((_SCLK / _LOWBAUD) / 16)              /* UART DLL/DLH */
+#define _NUMINS  (3)                                    /* how many instructions in loop */
+#define _CCLK    (((16 * _DIVISOR * 5) * (_LOWBAUD / _NUMBITS)) / _NUMINS)
+		i = _CCLK;
+		while (i--)
+			asm volatile("" : : : "memory");
+	}
+#endif
+
+	if (BFIN_DEBUG_EARLY_SERIAL) {
+		int ucen = bfin_read16(&pUART->gctl) & UCEN;
+		serial_early_init();
+
+		/* If the UART is off, that means we need to program
+		 * the baud rate ourselves initially.
+		 */
+		if (ucen != UCEN)
+			serial_early_set_baud(CONFIG_BAUDRATE);
+	}
+}
+
+__attribute__((always_inline))
+static inline void serial_deinit(void)
+{
+#ifdef __ADSPBF54x__
+	if (BFIN_UART_USE_RTS && CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) {
+		/* clear forced RTS rather than relying on auto RTS */
+		bfin_write16(&pUART->mcr, bfin_read16(&pUART->mcr) & ~FCPOL);
+	}
+#endif
+}
+
+__attribute__((always_inline))
+static inline void serial_putc(char c)
+{
+	if (!BFIN_DEBUG_EARLY_SERIAL)
+		return;
+
+	if (c == '\n')
+		serial_putc('\r');
+
+	bfin_write16(&pUART->thr, c);
+
+	while (!(bfin_read16(&pUART->lsr) & TEMT))
+		continue;
+}
+
+
+/* Max SCLK can be 133MHz ... dividing that by (2*4) gives
+ * us a freq of 16MHz for SPI which should generally be
+ * slow enough for the slow reads the bootrom uses.
+ */
+#if !defined(CONFIG_SPI_FLASH_SLOW_READ) && \
+    ((defined(__ADSPBF52x__) && __SILICON_REVISION__ >= 2) || \
+     (defined(__ADSPBF54x__) && __SILICON_REVISION__ >= 1))
+# define BOOTROM_SUPPORTS_SPI_FAST_READ 1
+#else
+# define BOOTROM_SUPPORTS_SPI_FAST_READ 0
+#endif
+#ifndef CONFIG_SPI_BAUD_INITBLOCK
+# define CONFIG_SPI_BAUD_INITBLOCK (BOOTROM_SUPPORTS_SPI_FAST_READ ? 2 : 4)
+#endif
+#ifdef SPI0_BAUD
+# define bfin_write_SPI_BAUD bfin_write_SPI0_BAUD
+#endif
+
+/* PLL_DIV defines */
+#ifndef CONFIG_PLL_DIV_VAL
+# if (CONFIG_CCLK_DIV == 1)
+#  define CONFIG_CCLK_ACT_DIV CCLK_DIV1
+# elif (CONFIG_CCLK_DIV == 2)
+#  define CONFIG_CCLK_ACT_DIV CCLK_DIV2
+# elif (CONFIG_CCLK_DIV == 4)
+#  define CONFIG_CCLK_ACT_DIV CCLK_DIV4
+# elif (CONFIG_CCLK_DIV == 8)
+#  define CONFIG_CCLK_ACT_DIV CCLK_DIV8
+# else
+#  define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly
+# endif
+# define CONFIG_PLL_DIV_VAL (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV)
+#endif
+
+#ifndef CONFIG_PLL_LOCKCNT_VAL
+# define CONFIG_PLL_LOCKCNT_VAL 0x0300
+#endif
+
+#ifndef CONFIG_PLL_CTL_VAL
+# define CONFIG_PLL_CTL_VAL (SPORT_HYST | (CONFIG_VCO_MULT << 9) | CONFIG_CLKIN_HALF)
+#endif
+
+#ifndef CONFIG_EBIU_RSTCTL_VAL
+# define CONFIG_EBIU_RSTCTL_VAL 0 /* only MDDRENABLE is useful */
+#endif
+#if ((CONFIG_EBIU_RSTCTL_VAL & 0xFFFFFFC4) != 0)
+# error invalid EBIU_RSTCTL value: must not set reserved bits
+#endif
+
+#ifndef CONFIG_EBIU_MBSCTL_VAL
+# define CONFIG_EBIU_MBSCTL_VAL 0
+#endif
+
+#if defined(CONFIG_EBIU_DDRQUE_VAL) && ((CONFIG_EBIU_DDRQUE_VAL & 0xFFFF8000) != 0)
+# error invalid EBIU_DDRQUE value: must not set reserved bits
+#endif
+
+/* Make sure our voltage value is sane so we don't blow up! */
+#ifndef CONFIG_VR_CTL_VAL
+# define BFIN_CCLK ((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) / CONFIG_CCLK_DIV)
+# if defined(__ADSPBF533__) || defined(__ADSPBF532__) || defined(__ADSPBF531__)
+#  define CCLK_VLEV_120	400000000
+#  define CCLK_VLEV_125	533000000
+# elif defined(__ADSPBF537__) || defined(__ADSPBF536__) || defined(__ADSPBF534__)
+#  define CCLK_VLEV_120	401000000
+#  define CCLK_VLEV_125	401000000
+# elif defined(__ADSPBF561__)
+#  define CCLK_VLEV_120	300000000
+#  define CCLK_VLEV_125	501000000
+# endif
+# if BFIN_CCLK < CCLK_VLEV_120
+#  define CONFIG_VR_CTL_VLEV VLEV_120
+# elif BFIN_CCLK < CCLK_VLEV_125
+#  define CONFIG_VR_CTL_VLEV VLEV_125
+# else
+#  define CONFIG_VR_CTL_VLEV VLEV_130
+# endif
+# if defined(__ADSPBF52x__)	/* TBD; use default */
+#  undef CONFIG_VR_CTL_VLEV
+#  define CONFIG_VR_CTL_VLEV VLEV_110
+# elif defined(__ADSPBF54x__)	/* TBD; use default */
+#  undef CONFIG_VR_CTL_VLEV
+#  define CONFIG_VR_CTL_VLEV VLEV_120
+# elif defined(__ADSPBF538__) || defined(__ADSPBF539__)	/* TBD; use default */
+#  undef CONFIG_VR_CTL_VLEV
+#  define CONFIG_VR_CTL_VLEV VLEV_125
+# endif
+
+# ifdef CONFIG_BFIN_MAC
+#  define CONFIG_VR_CTL_CLKBUF CLKBUFOE
+# else
+#  define CONFIG_VR_CTL_CLKBUF 0
+# endif
+
+# if defined(__ADSPBF52x__)
+#  define CONFIG_VR_CTL_FREQ FREQ_1000
+# else
+#  define CONFIG_VR_CTL_FREQ (GAIN_20 | FREQ_1000)
+# endif
+
+# define CONFIG_VR_CTL_VAL (CONFIG_VR_CTL_CLKBUF | CONFIG_VR_CTL_VLEV | CONFIG_VR_CTL_FREQ)
+#endif
+
+/* some parts do not have an on-chip voltage regulator */
+#if defined(__ADSPBF51x__)
+# define CONFIG_HAS_VR 0
+# undef CONFIG_VR_CTL_VAL
+# define CONFIG_VR_CTL_VAL 0
+#else
+# define CONFIG_HAS_VR 1
+#endif
+
+#if CONFIG_MEM_SIZE
+#ifndef EBIU_RSTCTL
+/* Blackfin with SDRAM */
+#ifndef CONFIG_EBIU_SDBCTL_VAL
+# if CONFIG_MEM_SIZE == 16
+#  define CONFIG_EBSZ_VAL EBSZ_16
+# elif CONFIG_MEM_SIZE == 32
+#  define CONFIG_EBSZ_VAL EBSZ_32
+# elif CONFIG_MEM_SIZE == 64
+#  define CONFIG_EBSZ_VAL EBSZ_64
+# elif CONFIG_MEM_SIZE == 128
+#  define CONFIG_EBSZ_VAL EBSZ_128
+# elif CONFIG_MEM_SIZE == 256
+#  define CONFIG_EBSZ_VAL EBSZ_256
+# elif CONFIG_MEM_SIZE == 512
+#  define CONFIG_EBSZ_VAL EBSZ_512
+# else
+#  error You need to define CONFIG_EBIU_SDBCTL_VAL or CONFIG_MEM_SIZE
+# endif
+# if CONFIG_MEM_ADD_WDTH == 8
+#  define CONFIG_EBCAW_VAL EBCAW_8
+# elif CONFIG_MEM_ADD_WDTH == 9
+#  define CONFIG_EBCAW_VAL EBCAW_9
+# elif CONFIG_MEM_ADD_WDTH == 10
+#  define CONFIG_EBCAW_VAL EBCAW_10
+# elif CONFIG_MEM_ADD_WDTH == 11
+#  define CONFIG_EBCAW_VAL EBCAW_11
+# else
+#  error You need to define CONFIG_EBIU_SDBCTL_VAL or CONFIG_MEM_ADD_WDTH
+# endif
+# define CONFIG_EBIU_SDBCTL_VAL (CONFIG_EBCAW_VAL | CONFIG_EBSZ_VAL | EBE)
+#endif
+#endif
+#endif
+
+/* Conflicting Column Address Widths Causes SDRAM Errors:
+ * EB2CAW and EB3CAW must be the same
+ */
+#if ANOMALY_05000362
+# if ((CONFIG_EBIU_SDBCTL_VAL & 0x30000000) >> 8) != (CONFIG_EBIU_SDBCTL_VAL & 0x00300000)
+#  error "Anomaly 05000362: EB2CAW and EB3CAW must be the same"
+# endif
+#endif
+
+__attribute__((always_inline)) static inline void
+program_early_devices(ADI_BOOT_DATA *bs, uint *sdivB, uint *divB, uint *vcoB)
+{
+	serial_putc('a');
+
+	/* Save the clock pieces that are used in baud rate calculation */
+	if (BFIN_DEBUG_EARLY_SERIAL || CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) {
+		serial_putc('b');
+		*sdivB = bfin_read_PLL_DIV() & 0xf;
+		*vcoB = (bfin_read_PLL_CTL() >> 9) & 0x3f;
+		*divB = serial_early_get_div();
+		serial_putc('c');
+	}
+
+	serial_putc('d');
+
+#ifdef CONFIG_HW_WATCHDOG
+# ifndef CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE
+#  define CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE 20000
+# endif
+	/* Program the watchdog with an initial timeout of ~20 seconds.
+	 * Hopefully that should be long enough to load the u-boot LDR
+	 * (from wherever) and then the common u-boot code can take over.
+	 * In bypass mode, the start.S would have already set a much lower
+	 * timeout, so don't clobber that.
+	 */
+	if (CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_BYPASS) {
+		serial_putc('e');
+		bfin_write_WDOG_CNT(MSEC_TO_SCLK(CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE));
+		bfin_write_WDOG_CTL(0);
+		serial_putc('f');
+	}
+#endif
+
+	serial_putc('g');
+
+	/* Blackfin bootroms use the SPI slow read opcode instead of the SPI
+	 * fast read, so we need to slow down the SPI clock a lot more during
+	 * boot.  Once we switch over to u-boot's SPI flash driver, we'll
+	 * increase the speed appropriately.
+	 */
+	if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_SPI_MASTER) {
+		serial_putc('h');
+		if (BOOTROM_SUPPORTS_SPI_FAST_READ && CONFIG_SPI_BAUD_INITBLOCK < 4)
+			bs->dFlags |= BFLAG_FASTREAD;
+		bfin_write_SPI_BAUD(CONFIG_SPI_BAUD_INITBLOCK);
+		serial_putc('i');
+	}
+
+	serial_putc('j');
+}
+
+__attribute__((always_inline)) static inline bool
+maybe_self_refresh(ADI_BOOT_DATA *bs)
+{
+	serial_putc('a');
+
+	if (!CONFIG_MEM_SIZE)
+		return false;
+
+	/* If external memory is enabled, put it into self refresh first. */
+#ifdef EBIU_RSTCTL
+	if (bfin_read_EBIU_RSTCTL() & DDR_SRESET) {
+		serial_putc('b');
+		bfin_write_EBIU_RSTCTL(bfin_read_EBIU_RSTCTL() | SRREQ);
+		return true;
+	}
+#else
+	if (bfin_read_EBIU_SDBCTL() & EBE) {
+		serial_putc('b');
+		bfin_write_EBIU_SDGCTL(bfin_read_EBIU_SDGCTL() | SRFS);
+		return true;
+	}
+#endif
+
+	serial_putc('c');
+
+	return false;
+}
+
+__attribute__((always_inline)) static inline u16
+program_clocks(ADI_BOOT_DATA *bs, bool put_into_srfs)
+{
+	u16 vr_ctl;
+
+	serial_putc('a');
+
+	vr_ctl = bfin_read_VR_CTL();
+
+	serial_putc('b');
+
+	/* If we're entering self refresh, make sure it has happened. */
+	if (put_into_srfs)
+#ifdef EBIU_RSTCTL
+		while (!(bfin_read_EBIU_RSTCTL() & SRACK))
+#else
+		while (!(bfin_read_EBIU_SDSTAT() & SDSRA))
+#endif
+			continue;
+
+	serial_putc('c');
+
+	/* With newer bootroms, we use the helper function to set up
+	 * the memory controller.  Older bootroms lacks such helpers
+	 * so we do it ourselves.
+	 */
+	if (!ANOMALY_05000386) {
+		serial_putc('d');
+
+		/* Always programming PLL_LOCKCNT avoids Anomaly 05000430 */
+		ADI_SYSCTRL_VALUES memory_settings;
+		uint32_t actions = SYSCTRL_WRITE | SYSCTRL_PLLCTL | SYSCTRL_PLLDIV | SYSCTRL_LOCKCNT;
+		if (CONFIG_HAS_VR) {
+			actions |= SYSCTRL_VRCTL;
+			if (CONFIG_VR_CTL_VAL & FREQ_MASK)
+				actions |= SYSCTRL_INTVOLTAGE;
+			else
+				actions |= SYSCTRL_EXTVOLTAGE;
+			memory_settings.uwVrCtl = CONFIG_VR_CTL_VAL;
+		} else
+			actions |= SYSCTRL_EXTVOLTAGE;
+		memory_settings.uwPllCtl = CONFIG_PLL_CTL_VAL;
+		memory_settings.uwPllDiv = CONFIG_PLL_DIV_VAL;
+		memory_settings.uwPllLockCnt = CONFIG_PLL_LOCKCNT_VAL;
+#if ANOMALY_05000432
+		bfin_write_SIC_IWR1(0);
+#endif
+		serial_putc('e');
+		bfrom_SysControl(actions, &memory_settings, NULL);
+		serial_putc('f');
+#if ANOMALY_05000432
+		bfin_write_SIC_IWR1(-1);
+#endif
+#if ANOMALY_05000171
+		bfin_write_SICA_IWR0(-1);
+		bfin_write_SICA_IWR1(-1);
+#endif
+		serial_putc('g');
+	} else {
+		serial_putc('h');
+
+		/* Disable all peripheral wakeups except for the PLL event. */
+#ifdef SIC_IWR0
+		bfin_write_SIC_IWR0(1);
+		bfin_write_SIC_IWR1(0);
+# ifdef SIC_IWR2
+		bfin_write_SIC_IWR2(0);
+# endif
+#elif defined(SICA_IWR0)
+		bfin_write_SICA_IWR0(1);
+		bfin_write_SICA_IWR1(0);
+#else
+		bfin_write_SIC_IWR(1);
+#endif
+
+		serial_putc('i');
+
+		/* Always programming PLL_LOCKCNT avoids Anomaly 05000430 */
+		bfin_write_PLL_LOCKCNT(CONFIG_PLL_LOCKCNT_VAL);
+
+		serial_putc('j');
+
+		/* Only reprogram when needed to avoid triggering unnecessary
+		 * PLL relock sequences.
+		 */
+		if (vr_ctl != CONFIG_VR_CTL_VAL) {
+			serial_putc('?');
+			bfin_write_VR_CTL(CONFIG_VR_CTL_VAL);
+			asm("idle;");
+			serial_putc('!');
+		}
+
+		serial_putc('k');
+
+		bfin_write_PLL_DIV(CONFIG_PLL_DIV_VAL);
+
+		serial_putc('l');
+
+		/* Only reprogram when needed to avoid triggering unnecessary
+		 * PLL relock sequences.
+		 */
+		if (ANOMALY_05000242 || bfin_read_PLL_CTL() != CONFIG_PLL_CTL_VAL) {
+			serial_putc('?');
+			bfin_write_PLL_CTL(CONFIG_PLL_CTL_VAL);
+			asm("idle;");
+			serial_putc('!');
+		}
+
+		serial_putc('m');
+
+		/* Restore all peripheral wakeups. */
+#ifdef SIC_IWR0
+		bfin_write_SIC_IWR0(-1);
+		bfin_write_SIC_IWR1(-1);
+# ifdef SIC_IWR2
+		bfin_write_SIC_IWR2(-1);
+# endif
+#elif defined(SICA_IWR0)
+		bfin_write_SICA_IWR0(-1);
+		bfin_write_SICA_IWR1(-1);
+#else
+		bfin_write_SIC_IWR(-1);
+#endif
+
+		serial_putc('n');
+	}
+
+	serial_putc('o');
+
+	return vr_ctl;
+}
+
+__attribute__((always_inline)) static inline void
+update_serial_clocks(ADI_BOOT_DATA *bs, uint sdivB, uint divB, uint vcoB)
+{
+	serial_putc('a');
+
+	/* Since we've changed the SCLK above, we may need to update
+	 * the UART divisors (UART baud rates are based on SCLK).
+	 * Do the division by hand as there are no native instructions
+	 * for dividing which means we'd generate a libgcc reference.
+	 */
+	if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) {
+		serial_putc('b');
+		unsigned int sdivR, vcoR;
+		sdivR = bfin_read_PLL_DIV() & 0xf;
+		vcoR = (bfin_read_PLL_CTL() >> 9) & 0x3f;
+		int dividend = sdivB * divB * vcoR;
+		int divisor = vcoB * sdivR;
+		unsigned int quotient;
+		for (quotient = 0; dividend > 0; ++quotient)
+			dividend -= divisor;
+		serial_early_put_div(quotient - ANOMALY_05000230);
+		serial_putc('c');
+	}
+
+	serial_putc('d');
+}
+
+__attribute__((always_inline)) static inline void
+program_memory_controller(ADI_BOOT_DATA *bs, bool put_into_srfs)
+{
+	serial_putc('a');
+
+	if (!CONFIG_MEM_SIZE)
+		return;
+
+	serial_putc('b');
+
+	/* Program the external memory controller before we come out of
+	 * self-refresh.  This only works with our SDRAM controller.
+	 */
+#ifndef EBIU_RSTCTL
+# ifdef CONFIG_EBIU_SDRRC_VAL
+	bfin_write_EBIU_SDRRC(CONFIG_EBIU_SDRRC_VAL);
+# endif
+# ifdef CONFIG_EBIU_SDBCTL_VAL
+	bfin_write_EBIU_SDBCTL(CONFIG_EBIU_SDBCTL_VAL);
+# endif
+# ifdef CONFIG_EBIU_SDGCTL_VAL
+	bfin_write_EBIU_SDGCTL(CONFIG_EBIU_SDGCTL_VAL);
+# endif
+#endif
+
+	serial_putc('c');
+
+	/* Now that we've reprogrammed, take things out of self refresh. */
+	if (put_into_srfs)
+#ifdef EBIU_RSTCTL
+		bfin_write_EBIU_RSTCTL(bfin_read_EBIU_RSTCTL() & ~(SRREQ));
+#else
+		bfin_write_EBIU_SDGCTL(bfin_read_EBIU_SDGCTL() & ~(SRFS));
+#endif
+
+	serial_putc('d');
+
+	/* Our DDR controller sucks and cannot be programmed while in
+	 * self-refresh.  So we have to pull it out before programming.
+	 */
+#ifdef EBIU_RSTCTL
+# ifdef CONFIG_EBIU_RSTCTL_VAL
+	bfin_write_EBIU_RSTCTL(bfin_read_EBIU_RSTCTL() | 0x1 /*DDRSRESET*/ | CONFIG_EBIU_RSTCTL_VAL);
+# endif
+# ifdef CONFIG_EBIU_DDRCTL0_VAL
+	bfin_write_EBIU_DDRCTL0(CONFIG_EBIU_DDRCTL0_VAL);
+# endif
+# ifdef CONFIG_EBIU_DDRCTL1_VAL
+	bfin_write_EBIU_DDRCTL1(CONFIG_EBIU_DDRCTL1_VAL);
+# endif
+# ifdef CONFIG_EBIU_DDRCTL2_VAL
+	bfin_write_EBIU_DDRCTL2(CONFIG_EBIU_DDRCTL2_VAL);
+# endif
+# ifdef CONFIG_EBIU_DDRCTL3_VAL
+	/* default is disable, so don't need to force this */
+	bfin_write_EBIU_DDRCTL3(CONFIG_EBIU_DDRCTL3_VAL);
+# endif
+# ifdef CONFIG_EBIU_DDRQUE_VAL
+	bfin_write_EBIU_DDRQUE(bfin_read_EBIU_DDRQUE() | CONFIG_EBIU_DDRQUE_VAL);
+# endif
+#endif
+
+	serial_putc('e');
+}
+
+__attribute__((always_inline)) static inline void
+check_hibernation(ADI_BOOT_DATA *bs, u16 vr_ctl, bool put_into_srfs)
+{
+	serial_putc('a');
+
+	if (!CONFIG_MEM_SIZE)
+		return;
+
+	serial_putc('b');
+
+	/* Are we coming out of hibernate (suspend to memory) ?
+	 * The memory layout is:
+	 * 0x0: hibernate magic for anomaly 307 (0xDEADBEEF)
+	 * 0x4: return address
+	 * 0x8: stack pointer
+	 *
+	 * SCKELOW is unreliable on older parts (anomaly 307)
+	 */
+	if (ANOMALY_05000307 || vr_ctl & 0x8000) {
+		uint32_t *hibernate_magic = 0;
+		__builtin_bfin_ssync(); /* make sure memory controller is done */
+		if (hibernate_magic[0] == 0xDEADBEEF) {
+			serial_putc('c');
+			bfin_write_EVT15(hibernate_magic[1]);
+			bfin_write_IMASK(EVT_IVG15);
+			__asm__ __volatile__ (
+				/* load reti early to avoid anomaly 281 */
+				"reti = %0;"
+				/* clear hibernate magic */
+				"[%0] = %1;"
+				/* load stack pointer */
+				"SP = [%0 + 8];"
+				/* lower ourselves from reset ivg to ivg15 */
+				"raise 15;"
+				"rti;"
+				:
+				: "p"(hibernate_magic), "d"(0x2000 /* jump.s 0 */)
+			);
+		}
+		serial_putc('d');
+	}
+
+	serial_putc('e');
+}
+
+__attribute__((always_inline)) static inline void
+program_async_controller(ADI_BOOT_DATA *bs)
+{
+	serial_putc('a');
+
+	/* Program the async banks controller. */
+	bfin_write_EBIU_AMBCTL0(CONFIG_EBIU_AMBCTL0_VAL);
+	bfin_write_EBIU_AMBCTL1(CONFIG_EBIU_AMBCTL1_VAL);
+	bfin_write_EBIU_AMGCTL(CONFIG_EBIU_AMGCTL_VAL);
+
+	serial_putc('b');
+
+	/* Not all parts have these additional MMRs. */
+#ifdef EBIU_MODE
+# ifdef CONFIG_EBIU_MBSCTL_VAL
+	bfin_write_EBIU_MBSCTL(CONFIG_EBIU_MBSCTL_VAL);
+# endif
+# ifdef CONFIG_EBIU_MODE_VAL
+	bfin_write_EBIU_MODE(CONFIG_EBIU_MODE_VAL);
+# endif
+# ifdef CONFIG_EBIU_FCTL_VAL
+	bfin_write_EBIU_FCTL(CONFIG_EBIU_FCTL_VAL);
+# endif
+#endif
+
+	serial_putc('c');
+}
+
+BOOTROM_CALLED_FUNC_ATTR
+void initcode(ADI_BOOT_DATA *bs)
+{
+	ADI_BOOT_DATA bootstruct_scratch;
+
+	serial_init();
+
+	serial_putc('A');
+
+	/* If the bootstruct is NULL, then it's because we're loading
+	 * dynamically and not via LDR (bootrom).  So set the struct to
+	 * some scratch space.
+	 */
+	if (!bs)
+		bs = &bootstruct_scratch;
+
+	serial_putc('B');
+	bool put_into_srfs = maybe_self_refresh(bs);
+
+	serial_putc('C');
+	uint sdivB, divB, vcoB;
+	program_early_devices(bs, &sdivB, &divB, &vcoB);
+
+	serial_putc('D');
+	u16 vr_ctl = program_clocks(bs, put_into_srfs);
+
+	serial_putc('E');
+	update_serial_clocks(bs, sdivB, divB, vcoB);
+
+	serial_putc('F');
+	program_memory_controller(bs, put_into_srfs);
+
+	serial_putc('G');
+	check_hibernation(bs, vr_ctl, put_into_srfs);
+
+	serial_putc('H');
+	program_async_controller(bs);
+
+#ifdef CONFIG_BFIN_BOOTROM_USES_EVT1
+	serial_putc('I');
+	/* tell the bootrom where our entry point is */
+	if (CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_BYPASS)
+		bfin_write_EVT1(CONFIG_SYS_MONITOR_BASE);
+#endif
+
+	serial_putc('>');
+	serial_putc('\n');
+
+	serial_deinit();
+}
diff --git a/arch/blackfin/cpu/interrupt.S b/arch/blackfin/cpu/interrupt.S
new file mode 100644
index 0000000..69bba3f
--- /dev/null
+++ b/arch/blackfin/cpu/interrupt.S
@@ -0,0 +1,152 @@
+/*
+ * interrupt.S - trampoline default exceptions/interrupts to C handlers
+ *
+ * Copyright (c) 2005-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <config.h>
+#include <asm/blackfin.h>
+#include <asm/entry.h>
+#include <asm/ptrace.h>
+#include <asm/deferred.h>
+#include <asm/mach-common/bits/core.h>
+
+.text
+
+/* default entry point for exceptions */
+ENTRY(_trap)
+	CONFIG_BFIN_SCRATCH_REG = sp;
+	sp.l = LO(L1_SRAM_SCRATCH_END - 20);
+	sp.h = HI(L1_SRAM_SCRATCH_END - 20);
+	SAVE_ALL_SYS
+
+	r0 = sp;	/* stack frame pt_regs pointer argument ==> r0 */
+	r1 = 3;		/* EVT3 space */
+	sp += -12;
+	call _trap_c;
+	sp += 12;
+
+#ifdef CONFIG_EXCEPTION_DEFER
+	CC = R0 == 0;
+	IF CC JUMP .Lexit_trap;
+
+	/* To avoid double faults, lower our priority to IRQ5 */
+	p4.l = lo(COREMMR_BASE);
+	p4.h = hi(COREMMR_BASE);
+
+	r7.h = _exception_to_level5;
+	r7.l = _exception_to_level5;
+	[p4 + (EVT5 - COREMMR_BASE)] = r7;
+
+	/*
+	 * Save these registers, as they are only valid in exception context
+	 *  (where we are now - as soon as we defer to IRQ5, they can change)
+	 */
+	p5.l = _deferred_regs;
+	p5.h = _deferred_regs;
+	r6 = [p4 + (DCPLB_FAULT_ADDR - COREMMR_BASE)];
+	[p5 + (deferred_regs_DCPLB_FAULT_ADDR * 4)] = r6;
+
+	r6 = [p4 + (ICPLB_FAULT_ADDR - COREMMR_BASE)];
+	[p5 + (deferred_regs_ICPLB_FAULT_ADDR * 4)] = r6;
+
+	/* Save the state of single stepping */
+	r6 = SYSCFG;
+	[p5 + (deferred_regs_SYSCFG * 4)] = r6;
+	/* Clear it while we handle the exception in IRQ5 mode
+	 * RESTORE_ALL_SYS will load it, so all we need to do is store it
+	 * in the right place
+	 */
+	BITCLR(r6, SYSCFG_SSSTEP_P);
+	[SP + PT_SYSCFG] = r6;
+
+	/* Since we are going to clobber RETX, we need to save it */
+	r6 = retx;
+	[p5 + (deferred_regs_retx * 4)] = r6;
+
+	/* Save the current IMASK, since we change in order to jump to level 5 */
+	cli r6;
+	[p5 + (deferred_regs_IMASK * 4)] = r6;
+
+	/* Disable all interrupts, but make sure level 5 is enabled so
+	 * we can switch to that level.
+	 */
+	r6 = 0x3f;
+	sti r6;
+
+	/* Clobber RETX so we don't end up back at a faulting instruction */
+	[sp + PT_RETX] = r7;
+
+	/* In case interrupts are disabled IPEND[4] (global interrupt disable bit)
+	 * clear it (re-enabling interrupts again) by the special sequence of pushing
+	 * RETI onto the stack.  This way we can lower ourselves to IVG5 even if the
+	 * exception was taken after the interrupt handler was called but before it
+	 * got a chance to enable global interrupts itself.
+	 */
+	[--sp] = reti;
+	sp += 4;
+
+	RAISE 5;
+.Lexit_trap:
+#endif
+
+#if ANOMALY_05000257
+	R7  = LC0;
+	LC0 = R7;
+	R7  = LC1;
+	LC1 = R7;
+#endif
+
+	RESTORE_ALL_SYS
+	sp = CONFIG_BFIN_SCRATCH_REG;
+	rtx;
+ENDPROC(_trap)
+
+#ifdef CONFIG_EXCEPTION_DEFER
+/* Deferred (IRQ5) exceptions */
+ENTRY(_exception_to_level5)
+	SAVE_ALL_SYS
+
+	/* Now we have to fix things up */
+	p4.l = lo(EVT5);
+	p4.h = hi(EVT5);
+	r0.l = _evt_default;
+	r0.h = _evt_default;
+	[p4] = r0;
+	csync;
+
+	p4.l = _deferred_regs;
+	p4.h = _deferred_regs;
+	r0 = [p4 + (deferred_regs_retx * 4)];
+	[sp + PT_PC] = r0;
+
+	r0 = [p4 + (deferred_regs_SYSCFG * 4)];
+	[sp + PT_SYSCFG] = r0;
+
+	r0 = sp;	/* stack frame pt_regs pointer argument ==> r0 */
+	r1 = 5;	/* EVT5 space */
+	sp += -12;
+	call _trap_c;
+	sp += 12;
+
+	/* Restore IMASK */
+	r0 = [p4 + (deferred_regs_IMASK * 4)];
+	sti r0;
+
+	RESTORE_ALL_SYS
+
+	rti;
+ENDPROC(_exception_to_level5)
+#endif
+
+/* default entry point for interrupts */
+ENTRY(_evt_default)
+	SAVE_ALL_SYS
+	r0 = sp;	/* stack frame pt_regs pointer argument ==> r0 */
+	sp += -12;
+	call _bfin_panic;
+	sp += 12;
+	RESTORE_ALL_SYS
+	rti;
+ENDPROC(_evt_default)
diff --git a/arch/blackfin/cpu/interrupts.c b/arch/blackfin/cpu/interrupts.c
new file mode 100644
index 0000000..54a67b4
--- /dev/null
+++ b/arch/blackfin/cpu/interrupts.c
@@ -0,0 +1,159 @@
+/*
+ * U-boot - interrupts.c Interrupt related routines
+ *
+ * Copyright (c) 2005-2008 Analog Devices Inc.
+ *
+ * This file is based on interrupts.c
+ * Copyright 1996 Roman Zippel
+ * Copyright 1999 D. Jeff Dionne <jeff@uclinux.org>
+ * Copyright 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca>
+ * Copyright 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
+ * Copyright 2003 Metrowerks/Motorola
+ * Copyright 2003 Bas Vermeulen <bas@buyways.nl>,
+ *			BuyWays B.V. (www.buyways.nl)
+ *
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <config.h>
+#include <watchdog.h>
+#include <asm/blackfin.h>
+#include "cpu.h"
+
+static ulong timestamp;
+static ulong last_time;
+static int int_flag;
+
+int irq_flags;			/* needed by asm-blackfin/system.h */
+
+/* Functions just to satisfy the linker */
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On Blackfin it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On Blackfin it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	ulong tbclk;
+
+	tbclk = CONFIG_SYS_HZ;
+	return tbclk;
+}
+
+void enable_interrupts(void)
+{
+	local_irq_restore(int_flag);
+}
+
+int disable_interrupts(void)
+{
+	local_irq_save(int_flag);
+	return 1;
+}
+
+void __udelay(unsigned long usec)
+{
+	unsigned long delay, start, stop;
+	unsigned long cclk;
+	cclk = (CONFIG_CCLK_HZ);
+
+	while (usec > 1) {
+		WATCHDOG_RESET();
+
+		/*
+		 * how many clock ticks to delay?
+		 *  - request(in useconds) * clock_ticks(Hz) / useconds/second
+		 */
+		if (usec < 1000) {
+			delay = (usec * (cclk / 244)) >> 12;
+			usec = 0;
+		} else {
+			delay = (1000 * (cclk / 244)) >> 12;
+			usec -= 1000;
+		}
+
+		asm volatile (" %0 = CYCLES;" : "=r" (start));
+		do {
+			asm volatile (" %0 = CYCLES; " : "=r" (stop));
+		} while (stop - start < delay);
+	}
+
+	return;
+}
+
+#define MAX_TIM_LOAD	0xFFFFFFFF
+int timer_init(void)
+{
+	bfin_write_TCNTL(0x1);
+	CSYNC();
+	bfin_write_TSCALE(0x0);
+	bfin_write_TCOUNT(MAX_TIM_LOAD);
+	bfin_write_TPERIOD(MAX_TIM_LOAD);
+	bfin_write_TCNTL(0x7);
+	CSYNC();
+
+	timestamp = 0;
+	last_time = 0;
+
+	return 0;
+}
+
+/*
+ * Any network command or flash
+ * command is started get_timer shall
+ * be called before TCOUNT gets reset,
+ * to implement the accurate timeouts.
+ *
+ * How ever milliconds doesn't return
+ * the number that has been elapsed from
+ * the last reset.
+ *
+ * As get_timer is used in the u-boot
+ * only for timeouts this should be
+ * sufficient
+ */
+ulong get_timer(ulong base)
+{
+	ulong milisec;
+
+	/* Number of clocks elapsed */
+	ulong clocks = (MAX_TIM_LOAD - bfin_read_TCOUNT());
+
+	/*
+	 * Find if the TCOUNT is reset
+	 * timestamp gives the number of times
+	 * TCOUNT got reset
+	 */
+	if (clocks < last_time)
+		timestamp++;
+	last_time = clocks;
+
+	/* Get the number of milliseconds */
+	milisec = clocks / (CONFIG_CCLK_HZ / 1000);
+
+	/*
+	 * Find the number of millisonds that
+	 * got elapsed before this TCOUNT cycle
+	 */
+	milisec += timestamp * (MAX_TIM_LOAD / (CONFIG_CCLK_HZ / 1000));
+
+	return (milisec - base);
+}
+
+void reset_timer(void)
+{
+	timer_init();
+}
diff --git a/arch/blackfin/cpu/jtag-console.c b/arch/blackfin/cpu/jtag-console.c
new file mode 100644
index 0000000..1cd619f
--- /dev/null
+++ b/arch/blackfin/cpu/jtag-console.c
@@ -0,0 +1,132 @@
+/*
+ * jtag-console.c - console driver over Blackfin JTAG
+ *
+ * Copyright (c) 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <stdio_dev.h>
+#include <asm/blackfin.h>
+
+#ifndef CONFIG_JTAG_CONSOLE_TIMEOUT
+# define CONFIG_JTAG_CONSOLE_TIMEOUT 500
+#endif
+
+/* The Blackfin tends to be much much faster than the JTAG hardware. */
+static void jtag_write_emudat(uint32_t emudat)
+{
+	static bool overflowed = false;
+	ulong timeout = get_timer(0) + CONFIG_JTAG_CONSOLE_TIMEOUT;
+	while (bfin_read_DBGSTAT() & 0x1) {
+		if (overflowed)
+			return;
+		if (timeout < get_timer(0))
+			overflowed = true;
+	}
+	overflowed = false;
+	__asm__ __volatile__("emudat = %0;" : : "d"(emudat));
+}
+/* Transmit a buffer.  The format is:
+ * [32bit length][actual data]
+ */
+static void jtag_send(const char *c, uint32_t len)
+{
+	uint32_t i;
+
+	if (len == 0)
+		return;
+
+	/* First send the length */
+	jtag_write_emudat(len);
+
+	/* Then send the data */
+	for (i = 0; i < len; i += 4)
+		jtag_write_emudat((c[i] << 0) | (c[i+1] << 8) | (c[i+2] << 16) | (c[i+3] << 24));
+}
+static void jtag_putc(const char c)
+{
+	jtag_send(&c, 1);
+}
+static void jtag_puts(const char *s)
+{
+	jtag_send(s, strlen(s));
+}
+
+static size_t inbound_len, leftovers_len;
+
+/* Lower layers want to know when jtag has data */
+static int jtag_tstc_dbg(void)
+{
+	return (bfin_read_DBGSTAT() & 0x2);
+}
+
+/* Higher layers want to know when any data is available */
+static int jtag_tstc(void)
+{
+	return jtag_tstc_dbg() || leftovers_len;
+}
+
+/* Receive a buffer.  The format is:
+ * [32bit length][actual data]
+ */
+static uint32_t leftovers;
+static int jtag_getc(void)
+{
+	int ret;
+	uint32_t emudat;
+
+	/* see if any data is left over */
+	if (leftovers_len) {
+		--leftovers_len;
+		ret = leftovers & 0xff;
+		leftovers >>= 8;
+		return ret;
+	}
+
+	/* wait for new data ! */
+	while (!jtag_tstc_dbg())
+		continue;
+	__asm__("%0 = emudat;" : "=d"(emudat));
+
+	if (inbound_len == 0) {
+		/* grab the length */
+		inbound_len = emudat;
+	} else {
+		/* store the bytes */
+		leftovers_len = min(4, inbound_len);
+		inbound_len -= leftovers_len;
+		leftovers = emudat;
+	}
+
+	return jtag_getc();
+}
+
+int drv_jtag_console_init(void)
+{
+	struct stdio_dev dev;
+	int ret;
+
+	memset(&dev, 0x00, sizeof(dev));
+	strcpy(dev.name, "jtag");
+	dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+	dev.putc = jtag_putc;
+	dev.puts = jtag_puts;
+	dev.tstc = jtag_tstc;
+	dev.getc = jtag_getc;
+
+	ret = stdio_register(&dev);
+	return (ret == 0 ? 1 : ret);
+}
+
+#ifdef CONFIG_UART_CONSOLE_IS_JTAG
+/* Since the JTAG is always available (at power on), allow it to fake a UART */
+void serial_set_baud(uint32_t baud) {}
+void serial_setbrg(void)            {}
+int serial_init(void)               { return 0; }
+void serial_putc(const char c)      __attribute__((alias("jtag_putc")));
+void serial_puts(const char *s)     __attribute__((alias("jtag_puts")));
+int serial_tstc(void)               __attribute__((alias("jtag_tstc")));
+int serial_getc(void)               __attribute__((alias("jtag_getc")));
+#endif
diff --git a/arch/blackfin/cpu/os_log.c b/arch/blackfin/cpu/os_log.c
new file mode 100644
index 0000000..e1c8e29
--- /dev/null
+++ b/arch/blackfin/cpu/os_log.c
@@ -0,0 +1,30 @@
+/*
+ * functions for handling OS log buffer
+ *
+ * Copyright (c) 2009 Analog Devices Inc.
+ *
+ * Licensed under the 2-clause BSD.
+ */
+
+#include <common.h>
+
+#define OS_LOG_MAGIC       0xDEADBEEF
+#define OS_LOG_MAGIC_ADDR  ((unsigned long *)0x4f0)
+#define OS_LOG_PTR_ADDR    ((char **)0x4f4)
+
+bool bfin_os_log_check(void)
+{
+	if (*OS_LOG_MAGIC_ADDR != OS_LOG_MAGIC)
+		return false;
+	*OS_LOG_MAGIC_ADDR = 0;
+	return true;
+}
+
+void bfin_os_log_dump(void)
+{
+	char *log = *OS_LOG_PTR_ADDR;
+	while (*log) {
+		puts(log);
+		log += strlen(log) + 1;
+	}
+}
diff --git a/arch/blackfin/cpu/reset.c b/arch/blackfin/cpu/reset.c
new file mode 100644
index 0000000..e3be740
--- /dev/null
+++ b/arch/blackfin/cpu/reset.c
@@ -0,0 +1,106 @@
+/*
+ * reset.c - logic for resetting the cpu
+ *
+ * Copyright (c) 2005-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/blackfin.h>
+#include "cpu.h"
+
+/* A system soft reset makes external memory unusable so force
+ * this function into L1.  We use the compiler ssync here rather
+ * than SSYNC() because it's safe (no interrupts and such) and
+ * we save some L1.  We do not need to force sanity in the SYSCR
+ * register as the BMODE selection bit is cleared by the soft
+ * reset while the Core B bit (on dual core parts) is cleared by
+ * the core reset.
+ */
+__attribute__ ((__l1_text__, __noreturn__))
+static void bfin_reset(void)
+{
+	/* Wait for completion of "system" events such as cache line
+	 * line fills so that we avoid infinite stalls later on as
+	 * much as possible.  This code is in L1, so it won't trigger
+	 * any such event after this point in time.
+	 */
+	__builtin_bfin_ssync();
+
+	/* The bootrom checks to see how it was reset and will
+	 * automatically perform a software reset for us when
+	 * it starts executing after the core reset.
+	 */
+	if (ANOMALY_05000353 || ANOMALY_05000386) {
+		/* Initiate System software reset. */
+		bfin_write_SWRST(0x7);
+
+		/* Due to the way reset is handled in the hardware, we need
+		 * to delay for 10 SCLKS.  The only reliable way to do this is
+		 * to calculate the CCLK/SCLK ratio and multiply 10.  For now,
+		 * we'll assume worse case which is a 1:15 ratio.
+		 */
+		asm(
+			"LSETUP (1f, 1f) LC0 = %0\n"
+			"1: nop;"
+			:
+			: "a" (15 * 10)
+			: "LC0", "LB0", "LT0"
+		);
+
+		/* Clear System software reset */
+		bfin_write_SWRST(0);
+
+		/* The BF526 ROM will crash during reset */
+#if defined(__ADSPBF522__) || defined(__ADSPBF524__) || defined(__ADSPBF526__)
+		bfin_read_SWRST();
+#endif
+
+		/* Wait for the SWRST write to complete.  Cannot rely on SSYNC
+		 * though as the System state is all reset now.
+		 */
+		asm(
+			"LSETUP (1f, 1f) LC1 = %0\n"
+			"1: nop;"
+			:
+			: "a" (15 * 1)
+			: "LC1", "LB1", "LT1"
+		);
+	}
+
+	while (1)
+		/* Issue core reset */
+		asm("raise 1");
+}
+
+/* We need to trampoline ourselves up into L1 since our linker
+ * does not have relaxtion support and will only generate a
+ * PC relative call with a 25 bit immediate.  This is not enough
+ * to get us from the top of SDRAM into L1.
+ */
+__attribute__ ((__noreturn__))
+static inline void bfin_reset_trampoline(void)
+{
+	if (board_reset)
+		board_reset();
+	while (1)
+		asm("jump (%0);" : : "a" (bfin_reset));
+}
+
+__attribute__ ((__noreturn__))
+void bfin_reset_or_hang(void)
+{
+#ifdef CONFIG_PANIC_HANG
+	hang();
+#else
+	bfin_reset_trampoline();
+#endif
+}
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	bfin_reset_trampoline();
+	return 0;
+}
diff --git a/arch/blackfin/cpu/serial.c b/arch/blackfin/cpu/serial.c
new file mode 100644
index 0000000..901cb97
--- /dev/null
+++ b/arch/blackfin/cpu/serial.c
@@ -0,0 +1,193 @@
+/*
+ * U-boot - serial.c Blackfin Serial Driver
+ *
+ * Copyright (c) 2005-2008 Analog Devices Inc.
+ *
+ * Copyright (c) 2003	Bas Vermeulen <bas@buyways.nl>,
+ *			BuyWays B.V. (www.buyways.nl)
+ *
+ * Based heavily on:
+ * blkfinserial.c: Serial driver for BlackFin DSP internal USRTs.
+ * Copyright(c) 2003	Metrowerks	<mwaddel@metrowerks.com>
+ * Copyright(c)	2001	Tony Z. Kou	<tonyko@arcturusnetworks.com>
+ * Copyright(c)	2001-2002 Arcturus Networks Inc. <www.arcturusnetworks.com>
+ *
+ * Based on code from 68328 version serial driver imlpementation which was:
+ * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
+ * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
+ * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
+ * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
+ *
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/* Anomaly notes:
+ *  05000086 - we don't support autobaud
+ *  05000099 - we only use DR bit, so losing others is not a problem
+ *  05000100 - we don't use the UART_IIR register
+ *  05000215 - we poll the uart (no dma/interrupts)
+ *  05000225 - no workaround possible, but this shouldnt cause errors ...
+ *  05000230 - we tweak the baud rate calculation slightly
+ *  05000231 - we always use 1 stop bit
+ *  05000309 - we always enable the uart before we modify it in anyway
+ *  05000350 - we always enable the uart regardless of boot mode
+ *  05000363 - we don't support break signals, so don't generate one
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <asm/blackfin.h>
+#include <asm/mach-common/bits/uart.h>
+
+#ifdef CONFIG_UART_CONSOLE
+
+#include "serial.h"
+
+#ifdef CONFIG_DEBUG_SERIAL
+uint16_t cached_lsr[256];
+uint16_t cached_rbr[256];
+size_t cache_count;
+
+/* The LSR is read-to-clear on some parts, so we have to make sure status
+ * bits aren't inadvertently lost when doing various tests.  This also
+ * works around anomaly 05000099 at the same time by keeping a cumulative
+ * tally of all the status bits.
+ */
+static uint16_t uart_lsr_save;
+static uint16_t uart_lsr_read(void)
+{
+	uint16_t lsr = bfin_read16(&pUART->lsr);
+	uart_lsr_save |= (lsr & (OE|PE|FE|BI));
+	return lsr | uart_lsr_save;
+}
+/* Just do the clear for everyone since it can't hurt. */
+static void uart_lsr_clear(void)
+{
+	uart_lsr_save = 0;
+	bfin_write16(&pUART->lsr, bfin_read16(&pUART->lsr) | -1);
+}
+#else
+/* When debugging is disabled, we only care about the DR bit, so if other
+ * bits get set/cleared, we don't really care since we don't read them
+ * anyways (and thus anomaly 05000099 is irrelevant).
+ */
+static uint16_t uart_lsr_read(void)
+{
+	return bfin_read16(&pUART->lsr);
+}
+static void uart_lsr_clear(void)
+{
+	bfin_write16(&pUART->lsr, bfin_read16(&pUART->lsr) | -1);
+}
+#endif
+
+/* Symbol for our assembly to call. */
+void serial_set_baud(uint32_t baud)
+{
+	serial_early_set_baud(baud);
+}
+
+/* Symbol for common u-boot code to call.
+ * Setup the baudrate (brg: baudrate generator).
+ */
+void serial_setbrg(void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+	serial_set_baud(gd->baudrate);
+}
+
+/* Symbol for our assembly to call. */
+void serial_initialize(void)
+{
+	serial_early_init();
+}
+
+/* Symbol for common u-boot code to call. */
+int serial_init(void)
+{
+	serial_initialize();
+	serial_setbrg();
+	uart_lsr_clear();
+#ifdef CONFIG_DEBUG_SERIAL
+	cache_count = 0;
+	memset(cached_lsr, 0x00, sizeof(cached_lsr));
+	memset(cached_rbr, 0x00, sizeof(cached_rbr));
+#endif
+	return 0;
+}
+
+void serial_putc(const char c)
+{
+	/* send a \r for compatibility */
+	if (c == '\n')
+		serial_putc('\r');
+
+	WATCHDOG_RESET();
+
+	/* wait for the hardware fifo to clear up */
+	while (!(uart_lsr_read() & THRE))
+		continue;
+
+	/* queue the character for transmission */
+	bfin_write16(&pUART->thr, c);
+	SSYNC();
+
+	WATCHDOG_RESET();
+}
+
+int serial_tstc(void)
+{
+	WATCHDOG_RESET();
+	return (uart_lsr_read() & DR) ? 1 : 0;
+}
+
+int serial_getc(void)
+{
+	uint16_t uart_rbr_val;
+
+	/* wait for data ! */
+	while (!serial_tstc())
+		continue;
+
+	/* grab the new byte */
+	uart_rbr_val = bfin_read16(&pUART->rbr);
+
+#ifdef CONFIG_DEBUG_SERIAL
+	/* grab & clear the LSR */
+	uint16_t uart_lsr_val = uart_lsr_read();
+
+	cached_lsr[cache_count] = uart_lsr_val;
+	cached_rbr[cache_count] = uart_rbr_val;
+	cache_count = (cache_count + 1) % ARRAY_SIZE(cached_lsr);
+
+	if (uart_lsr_val & (OE|PE|FE|BI)) {
+		uint16_t dll, dlh;
+		printf("\n[SERIAL ERROR]\n");
+		ACCESS_LATCH();
+		dll = bfin_read16(&pUART->dll);
+		dlh = bfin_read16(&pUART->dlh);
+		ACCESS_PORT_IER();
+		printf("\tDLL=0x%x DLH=0x%x\n", dll, dlh);
+		do {
+			--cache_count;
+			printf("\t%3i: RBR=0x%02x LSR=0x%02x\n", cache_count,
+				cached_rbr[cache_count], cached_lsr[cache_count]);
+		} while (cache_count > 0);
+		return -1;
+	}
+#endif
+	uart_lsr_clear();
+
+	return uart_rbr_val;
+}
+
+void serial_puts(const char *s)
+{
+	while (*s)
+		serial_putc(*s++);
+}
+
+#endif
diff --git a/arch/blackfin/cpu/serial.h b/arch/blackfin/cpu/serial.h
new file mode 100644
index 0000000..5f9be86
--- /dev/null
+++ b/arch/blackfin/cpu/serial.h
@@ -0,0 +1,263 @@
+/*
+ * serial.h - common serial defines for early debug and serial driver.
+ *            any functions defined here must be always_inline since
+ *            initcode cannot have function calls.
+ *
+ * Copyright (c) 2004-2007 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __BFIN_CPU_SERIAL_H__
+#define __BFIN_CPU_SERIAL_H__
+
+#include <asm/blackfin.h>
+#include <asm/mach-common/bits/uart.h>
+
+#ifndef CONFIG_UART_CONSOLE
+# define CONFIG_UART_CONSOLE 0
+#endif
+
+#ifdef CONFIG_DEBUG_EARLY_SERIAL
+# define BFIN_DEBUG_EARLY_SERIAL 1
+#else
+# define BFIN_DEBUG_EARLY_SERIAL 0
+#endif
+
+#ifndef __ASSEMBLY__
+
+#define LOB(x) ((x) & 0xFF)
+#define HIB(x) (((x) >> 8) & 0xFF)
+
+/*
+ * All Blackfin system MMRs are padded to 32bits even if the register
+ * itself is only 16bits.  So use a helper macro to streamline this.
+ */
+#define __BFP(m) u16 m; u16 __pad_##m
+struct bfin_mmr_serial {
+#ifdef __ADSPBF54x__
+	__BFP(dll);
+	__BFP(dlh);
+	__BFP(gctl);
+	__BFP(lcr);
+	__BFP(mcr);
+	__BFP(lsr);
+	__BFP(msr);
+	__BFP(scr);
+	__BFP(ier_set);
+	__BFP(ier_clear);
+	__BFP(thr);
+	__BFP(rbr);
+#else
+	union {
+		u16 dll;
+		u16 thr;
+		const u16 rbr;
+	};
+	const u16 __spad0;
+	union {
+		u16 dlh;
+		u16 ier;
+	};
+	const u16 __spad1;
+	const __BFP(iir);
+	__BFP(lcr);
+	__BFP(mcr);
+	__BFP(lsr);
+	__BFP(msr);
+	__BFP(scr);
+	const u32 __spad2;
+	__BFP(gctl);
+#endif
+};
+#undef __BFP
+
+#ifndef UART_LSR
+# if (CONFIG_UART_CONSOLE == 3)
+#  define UART_BASE UART3_DLL
+# elif (CONFIG_UART_CONSOLE == 2)
+#  define UART_BASE UART2_DLL
+# elif (CONFIG_UART_CONSOLE == 1)
+#  define UART_BASE UART1_DLL
+# elif (CONFIG_UART_CONSOLE == 0)
+#  define UART_BASE UART0_DLL
+# endif
+#else
+# if CONFIG_UART_CONSOLE != 0
+#  error CONFIG_UART_CONSOLE must be 0 on parts with only one UART
+# endif
+# define UART_BASE UART_DLL
+#endif
+#define pUART ((volatile struct bfin_mmr_serial *)UART_BASE)
+
+#ifdef __ADSPBF54x__
+# define ACCESS_LATCH()
+# define ACCESS_PORT_IER()
+#else
+# define ACCESS_LATCH() \
+	bfin_write16(&pUART->lcr, bfin_read16(&pUART->lcr) | DLAB)
+# define ACCESS_PORT_IER() \
+	bfin_write16(&pUART->lcr, bfin_read16(&pUART->lcr) & ~DLAB)
+#endif
+
+__attribute__((always_inline))
+static inline void serial_do_portmux(void)
+{
+#if defined(__ADSPBF51x__)
+# define DO_MUX(port, mux_tx, mux_rx, tx, rx) \
+	bfin_write_PORT##port##_MUX((bfin_read_PORT##port##_MUX() & ~(PORT_x_MUX_##mux_tx##_MASK | PORT_x_MUX_##mux_rx##_MASK)) | PORT_x_MUX_##mux_tx##_FUNC_2 | PORT_x_MUX_##mux_rx##_FUNC_2); \
+	bfin_write_PORT##port##_FER(bfin_read_PORT##port##_FER() | P##port##tx | P##port##rx);
+	switch (CONFIG_UART_CONSOLE) {
+	case 0: DO_MUX(G, 5, 5, 9, 10);  break;	/* Port G; mux 5; PG9 and PG10 */
+	case 1: DO_MUX(F, 2, 3, 14, 15); break;	/* Port H; mux 2/3; PH14 and PH15 */
+	}
+	SSYNC();
+#elif defined(__ADSPBF52x__)
+# define DO_MUX(port, mux, tx, rx) \
+	bfin_write_PORT##port##_MUX((bfin_read_PORT##port##_MUX() & ~PORT_x_MUX_##mux##_MASK) | PORT_x_MUX_##mux##_FUNC_3); \
+	bfin_write_PORT##port##_FER(bfin_read_PORT##port##_FER() | P##port##tx | P##port##rx);
+	switch (CONFIG_UART_CONSOLE) {
+	case 0: DO_MUX(G, 2, 7, 8);   break;	/* Port G; mux 2; PG2 and PG8 */
+	case 1: DO_MUX(F, 5, 14, 15); break;	/* Port F; mux 5; PF14 and PF15 */
+	}
+	SSYNC();
+#elif defined(__ADSPBF537__) || defined(__ADSPBF536__) || defined(__ADSPBF534__)
+# define DO_MUX(func, tx, rx) \
+	bfin_write_PORT_MUX(bfin_read_PORT_MUX() & ~(func)); \
+	bfin_write_PORTF_FER(bfin_read_PORTF_FER() | PF##tx | PF##rx);
+	switch (CONFIG_UART_CONSOLE) {
+	case 0: DO_MUX(PFDE, 0, 1); break;
+	case 1: DO_MUX(PFTE, 2, 3); break;
+	}
+	SSYNC();
+#elif defined(__ADSPBF54x__)
+# define DO_MUX(port, tx, rx) \
+	bfin_write_PORT##port##_MUX((bfin_read_PORT##port##_MUX() & ~(PORT_x_MUX_##tx##_MASK | PORT_x_MUX_##rx##_MASK)) | PORT_x_MUX_##tx##_FUNC_1 | PORT_x_MUX_##rx##_FUNC_1); \
+	bfin_write_PORT##port##_FER(bfin_read_PORT##port##_FER() | P##port##tx | P##port##rx);
+	switch (CONFIG_UART_CONSOLE) {
+	case 0: DO_MUX(E, 7, 8); break;	/* Port E; PE7 and PE8 */
+	case 1: DO_MUX(H, 0, 1); break;	/* Port H; PH0 and PH1 */
+	case 2: DO_MUX(B, 4, 5); break;	/* Port B; PB4 and PB5 */
+	case 3: DO_MUX(B, 6, 7); break;	/* Port B; PB6 and PB7 */
+	}
+	SSYNC();
+#endif
+}
+
+__attribute__((always_inline))
+static inline void serial_early_init(void)
+{
+	/* handle portmux crap on different Blackfins */
+	serial_do_portmux();
+
+	/* always enable UART -- avoids anomalies 05000309 and 05000350 */
+	bfin_write16(&pUART->gctl, UCEN);
+
+	/* Set LCR to Word Lengh 8-bit word select */
+	bfin_write16(&pUART->lcr, WLS_8);
+
+	SSYNC();
+}
+
+__attribute__((always_inline))
+static inline void serial_early_put_div(uint16_t divisor)
+{
+	/* Set DLAB in LCR to Access DLL and DLH */
+	ACCESS_LATCH();
+	SSYNC();
+
+	/* Program the divisor to get the baud rate we want */
+	bfin_write16(&pUART->dll, LOB(divisor));
+	bfin_write16(&pUART->dlh, HIB(divisor));
+	SSYNC();
+
+	/* Clear DLAB in LCR to Access THR RBR IER */
+	ACCESS_PORT_IER();
+	SSYNC();
+}
+
+__attribute__((always_inline))
+static inline uint16_t serial_early_get_div(void)
+{
+	/* Set DLAB in LCR to Access DLL and DLH */
+	ACCESS_LATCH();
+	SSYNC();
+
+	uint8_t dll = bfin_read16(&pUART->dll);
+	uint8_t dlh = bfin_read16(&pUART->dlh);
+	uint16_t divisor = (dlh << 8) | dll;
+
+	/* Clear DLAB in LCR to Access THR RBR IER */
+	ACCESS_PORT_IER();
+	SSYNC();
+
+	return divisor;
+}
+
+/* We cannot use get_sclk() early on as it uses caches in external memory */
+#if defined(BFIN_IN_INITCODE) || defined(CONFIG_DEBUG_EARLY_SERIAL)
+# define get_sclk() (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT / CONFIG_SCLK_DIV)
+#endif
+
+__attribute__((always_inline))
+static inline void serial_early_set_baud(uint32_t baud)
+{
+	/* Translate from baud into divisor in terms of SCLK.  The
+	 * weird multiplication is to make sure we over sample just
+	 * a little rather than under sample the incoming signals.
+	 */
+	serial_early_put_div((get_sclk() + (baud * 8)) / (baud * 16) - ANOMALY_05000230);
+}
+
+#ifndef BFIN_IN_INITCODE
+__attribute__((always_inline))
+static inline void serial_early_puts(const char *s)
+{
+	if (BFIN_DEBUG_EARLY_SERIAL) {
+		serial_puts("Early: ");
+		serial_puts(s);
+	}
+}
+#endif
+
+#else
+
+.macro serial_early_init
+#ifdef CONFIG_DEBUG_EARLY_SERIAL
+	call _serial_initialize;
+#endif
+.endm
+
+.macro serial_early_set_baud
+#ifdef CONFIG_DEBUG_EARLY_SERIAL
+	R0.L = LO(CONFIG_BAUDRATE);
+	R0.H = HI(CONFIG_BAUDRATE);
+	call _serial_set_baud;
+#endif
+.endm
+
+/* Since we embed the string right into our .text section, we need
+ * to find its address.  We do this by getting our PC and adding 2
+ * bytes (which is the length of the jump instruction).  Then we
+ * pass this address to serial_puts().
+ */
+#ifdef CONFIG_DEBUG_EARLY_SERIAL
+# define serial_early_puts(str) \
+	call _get_pc; \
+	jump 1f; \
+	.ascii "Early:"; \
+	.ascii __FILE__; \
+	.ascii ": "; \
+	.ascii str; \
+	.asciz "\n"; \
+	.align 4; \
+1: \
+	R0 += 2; \
+	call _serial_puts;
+#else
+# define serial_early_puts(str)
+#endif
+
+#endif
+
+#endif
diff --git a/arch/blackfin/cpu/start.S b/arch/blackfin/cpu/start.S
new file mode 100644
index 0000000..7a3abba
--- /dev/null
+++ b/arch/blackfin/cpu/start.S
@@ -0,0 +1,238 @@
+/*
+ * U-boot - start.S Startup file for Blackfin u-boot
+ *
+ * Copyright (c) 2005-2008 Analog Devices Inc.
+ *
+ * This file is based on head.S
+ * Copyright (c) 2003  Metrowerks/Motorola
+ * Copyright (C) 1998  D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
+ *                     Kenneth Albanowski <kjahds@kjahds.com>,
+ *                     The Silver Hammer Group, Ltd.
+ * (c) 1995, Dionne & Associates
+ * (c) 1995, DKG Display Tech.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <asm/blackfin.h>
+#include <asm/mach-common/bits/core.h>
+#include <asm/mach-common/bits/dma.h>
+#include <asm/mach-common/bits/pll.h>
+
+#include "serial.h"
+
+/* It may seem odd that we make calls to functions even though we haven't
+ * relocated ourselves yet out of {flash,ram,wherever}.  This is OK because
+ * the "call" instruction in the Blackfin architecture is actually PC
+ * relative.  So we can call functions all we want and not worry about them
+ * not being relocated yet.
+ */
+
+.text
+ENTRY(_start)
+
+	/* Set our initial stack to L1 scratch space */
+	sp.l = LO(L1_SRAM_SCRATCH_END - 20);
+	sp.h = HI(L1_SRAM_SCRATCH_END - 20);
+
+#ifdef CONFIG_HW_WATCHDOG
+# ifndef CONFIG_HW_WATCHDOG_TIMEOUT_START
+#  define CONFIG_HW_WATCHDOG_TIMEOUT_START 5000
+# endif
+	/* Program the watchdog with an initial timeout of ~5 seconds.
+	 * That should be long enough to bootstrap ourselves up and
+	 * then the common u-boot code can take over.
+	 */
+	P0.L = LO(WDOG_CNT);
+	P0.H = HI(WDOG_CNT);
+	R0.L = 0;
+	R0.H = HI(MSEC_TO_SCLK(CONFIG_HW_WATCHDOG_TIMEOUT_START));
+	[P0] = R0;
+	/* fire up the watchdog - R0.L above needs to be 0x0000 */
+	W[P0 + (WDOG_CTL - WDOG_CNT)] = R0;
+#endif
+
+	/* Turn on the serial for debugging the init process */
+	serial_early_init
+	serial_early_set_baud
+
+	serial_early_puts("Init Registers");
+
+	/* Disable self-nested interrupts and enable CYCLES for udelay() */
+	R0 = CCEN | 0x30;
+	SYSCFG = R0;
+
+	/* Zero out registers required by Blackfin ABI.
+	 * http://docs.blackfin.uclinux.org/doku.php?id=application_binary_interface
+	 */
+	r1 = 0 (x);
+	/* Disable circular buffers */
+	l0 = r1;
+	l1 = r1;
+	l2 = r1;
+	l3 = r1;
+	/* Disable hardware loops in case we were started by 'go' */
+	lc0 = r1;
+	lc1 = r1;
+
+	/* Save RETX so we can pass it while booting Linux */
+	r7 = RETX;
+
+#if CONFIG_MEM_SIZE
+	/* Figure out where we are currently executing so that we can decide
+	 * how to best reprogram and relocate things.  We'll pass below:
+	 *  R4: load address of _start
+	 *  R5: current (not load) address of _start
+	 */
+	serial_early_puts("Find ourselves");
+
+	call _get_pc;
+.Loffset:
+	r1.l = .Loffset;
+	r1.h = .Loffset;
+	r4.l = _start;
+	r4.h = _start;
+	r3 = r1 - r4;
+	r5 = r0 - r3;
+
+	/* Inform upper layers if we had to do the relocation ourselves.
+	 * This allows us to detect whether we were loaded by 'go 0x1000'
+	 * or by the bootrom from an LDR.  "R6" is "loaded_from_ldr".
+	 */
+	r6 = 1 (x);
+	cc = r4 == r5;
+	if cc jump .Lnorelocate;
+	r6 = 0 (x);
+
+	/* In bypass mode, we don't have an LDR with an init block
+	 * so we need to explicitly call it ourselves.  This will
+	 * reprogram our clocks, memory, and setup our async banks.
+	 */
+	serial_early_puts("Program Clocks");
+
+	/* if we're executing >=0x20000000, then we dont need to dma */
+	r3 = 0x0;
+	r3.h = 0x2000;
+	cc = r5 < r3 (iu);
+	if cc jump .Ldma_and_reprogram;
+#else
+	r6 = 1 (x);	/* fake loaded_from_ldr = 1 */
+#endif
+	r0 = 0 (x);	/* set bootstruct to NULL */
+	call _initcode;
+	jump .Lprogrammed;
+
+	/* we're sitting in external memory, so dma into L1 and reprogram */
+.Ldma_and_reprogram:
+	r0.l = LO(L1_INST_SRAM);
+	r0.h = HI(L1_INST_SRAM);
+	r1.l = __initcode_lma;
+	r1.h = __initcode_lma;
+	r2.l = __initcode_len;
+	r2.h = __initcode_len;
+	r1 = r1 - r4;	/* convert r1 from load address of initcode ... */
+	r1 = r1 + r5;	/* ... to current (not load) address of initcode */
+	p3 = r0;
+	call _dma_memcpy_nocache;
+	r0 = 0 (x);	/* set bootstruct to NULL */
+	call (p3);
+
+	/* Since we reprogrammed SCLK, we need to update the serial divisor */
+.Lprogrammed:
+	serial_early_set_baud
+
+#if CONFIG_MEM_SIZE
+	/* Relocate from wherever we are (FLASH/RAM/etc...) to the hardcoded
+	 * monitor location in the end of RAM.  We know that memcpy() only
+	 * uses registers, so it is safe to call here.  Note that this only
+	 * copies to external memory ... we do not start executing out of
+	 * it yet (see "lower to 15" below).
+	 */
+	serial_early_puts("Relocate");
+	r0 = r4;
+	r1 = r5;
+	r2.l = LO(CONFIG_SYS_MONITOR_LEN);
+	r2.h = HI(CONFIG_SYS_MONITOR_LEN);
+	call _memcpy_ASM;
+#endif
+
+	/* Initialize BSS section ... we know that memset() does not
+	 * use the BSS, so it is safe to call here.  The bootrom LDR
+	 * takes care of clearing things for us.
+	 */
+	serial_early_puts("Zero BSS");
+	r0.l = __bss_vma;
+	r0.h = __bss_vma;
+	r1 = 0 (x);
+	r2.l = __bss_len;
+	r2.h = __bss_len;
+	call _memset;
+
+.Lnorelocate:
+
+	/* Setup the actual stack in external memory */
+	sp.h = HI(CONFIG_STACKBASE);
+	sp.l = LO(CONFIG_STACKBASE);
+	fp = sp;
+
+	/* Now lower ourselves from the highest interrupt level to
+	 * the lowest.  We do this by masking all interrupts but 15,
+	 * setting the 15 handler to ".Lenable_nested", raising the 15
+	 * interrupt, and then returning from the highest interrupt
+	 * level to the dummy "jump" until the interrupt controller
+	 * services the pending 15 interrupt.  If executing out of
+	 * flash, these steps also changes the code flow from flash
+	 * to external memory.
+	 */
+	serial_early_puts("Lower to 15");
+	r0 = r7;
+	r1 = r6;
+	p0.l = LO(EVT15);
+	p0.h = HI(EVT15);
+	p1.l = .Lenable_nested;
+	p1.h = .Lenable_nested;
+	[p0] = p1;
+	r7 = EVT_IVG15 (z);
+	sti r7;
+	raise 15;
+	p4.l = .LWAIT_HERE;
+	p4.h = .LWAIT_HERE;
+	reti = p4;
+	rti;
+
+	/* Enable nested interrupts before continuing with cpu init */
+.Lenable_nested:
+	cli r7;
+	[--sp] = reti;
+	jump.l _cpu_init_f;
+
+.LWAIT_HERE:
+	jump .LWAIT_HERE;
+ENDPROC(_start)
+
+LENTRY(_get_pc)
+	r0 = rets;
+#if ANOMALY_05000371
+	NOP;
+	NOP;
+	NOP;
+#endif
+	rts;
+ENDPROC(_get_pc)
diff --git a/arch/blackfin/cpu/traps.c b/arch/blackfin/cpu/traps.c
new file mode 100644
index 0000000..caaea94
--- /dev/null
+++ b/arch/blackfin/cpu/traps.c
@@ -0,0 +1,410 @@
+/*
+ * U-boot - traps.c Routines related to interrupts and exceptions
+ *
+ * Copyright (c) 2005-2008 Analog Devices Inc.
+ *
+ * This file is based on
+ * No original Copyright holder listed,
+ * Probabily original (C) Roman Zippel (assigned DJD, 1999)
+ *
+ * Copyright 2003 Metrowerks - for Blackfin
+ * Copyright 2000-2001 Lineo, Inc. D. Jeff Dionne <jeff@lineo.ca>
+ * Copyright 1999-2000 D. Jeff Dionne, <jeff@uclinux.org>
+ *
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <kgdb.h>
+#include <linux/types.h>
+#include <asm/traps.h>
+#include <asm/cplb.h>
+#include <asm/io.h>
+#include <asm/mach-common/bits/core.h>
+#include <asm/mach-common/bits/mpu.h>
+#include <asm/mach-common/bits/trace.h>
+#include <asm/deferred.h>
+#include "cpu.h"
+
+#define trace_buffer_save(x) \
+	do { \
+		(x) = bfin_read_TBUFCTL(); \
+		bfin_write_TBUFCTL((x) & ~TBUFEN); \
+	} while (0)
+
+#define trace_buffer_restore(x) \
+	bfin_write_TBUFCTL((x))
+
+/* The purpose of this map is to provide a mapping of address<->cplb settings
+ * rather than an exact map of what is actually addressable on the part.  This
+ * map covers all current Blackfin parts.  If you try to access an address that
+ * is in this map but not actually on the part, you won't get an exception and
+ * reboot, you'll get an external hardware addressing error and reboot.  Since
+ * only the ends matter (you did something wrong and the board reset), the means
+ * are largely irrelevant.
+ */
+struct memory_map {
+	uint32_t start, end;
+	uint32_t data_flags, inst_flags;
+};
+const struct memory_map const bfin_memory_map[] = {
+	{	/* external memory */
+		.start = 0x00000000,
+		.end   = 0x20000000,
+		.data_flags = SDRAM_DGENERIC,
+		.inst_flags = SDRAM_IGENERIC,
+	},
+	{	/* async banks */
+		.start = 0x20000000,
+		.end   = 0x30000000,
+		.data_flags = SDRAM_EBIU,
+		.inst_flags = SDRAM_INON_CHBL,
+	},
+	{	/* everything on chip */
+		.start = 0xE0000000,
+		.end   = 0xFFFFFFFF,
+		.data_flags = L1_DMEMORY,
+		.inst_flags = L1_IMEMORY,
+	}
+};
+
+#ifdef CONFIG_EXCEPTION_DEFER
+unsigned int deferred_regs[deferred_regs_last];
+#endif
+
+/*
+ * Handle all exceptions while running in EVT3 or EVT5
+ */
+int trap_c(struct pt_regs *regs, uint32_t level)
+{
+	uint32_t ret = 0;
+	uint32_t trapnr = (regs->seqstat & EXCAUSE);
+	bool data = false;
+
+	switch (trapnr) {
+	/* 0x26 - Data CPLB Miss */
+	case VEC_CPLB_M:
+
+		if (ANOMALY_05000261) {
+			static uint32_t last_cplb_fault_retx;
+			/*
+			 * Work around an anomaly: if we see a new DCPLB fault,
+			 * return without doing anything. Then,
+			 * if we get the same fault again, handle it.
+			 */
+			if (last_cplb_fault_retx != regs->retx) {
+				last_cplb_fault_retx = regs->retx;
+				return ret;
+			}
+		}
+
+		data = true;
+		/* fall through */
+
+	/* 0x27 - Instruction CPLB Miss */
+	case VEC_CPLB_I_M: {
+		volatile uint32_t *CPLB_ADDR_BASE, *CPLB_DATA_BASE, *CPLB_ADDR, *CPLB_DATA;
+		uint32_t new_cplb_addr = 0, new_cplb_data = 0;
+		static size_t last_evicted;
+		size_t i;
+		unsigned long tflags;
+
+#ifdef CONFIG_EXCEPTION_DEFER
+		/* This should never happen */
+		if (level == 5)
+			bfin_panic(regs);
+#endif
+
+		/*
+		 * Keep the trace buffer so that a miss here points people
+		 * to the right place (their code).  Crashes here rarely
+		 * happen.  If they do, only the Blackfin maintainer cares.
+		 */
+		trace_buffer_save(tflags);
+
+		new_cplb_addr = (data ? bfin_read_DCPLB_FAULT_ADDR() : bfin_read_ICPLB_FAULT_ADDR()) & ~(4 * 1024 * 1024 - 1);
+
+		for (i = 0; i < ARRAY_SIZE(bfin_memory_map); ++i) {
+			/* if the exception is inside this range, lets use it */
+			if (new_cplb_addr >= bfin_memory_map[i].start &&
+			    new_cplb_addr < bfin_memory_map[i].end)
+				break;
+		}
+		if (i == ARRAY_SIZE(bfin_memory_map)) {
+			printf("%cCPLB exception outside of memory map at 0x%p\n",
+				(data ? 'D' : 'I'), (void *)new_cplb_addr);
+			bfin_panic(regs);
+		} else
+			debug("CPLB addr %p matches map 0x%p - 0x%p\n", new_cplb_addr, bfin_memory_map[i].start, bfin_memory_map[i].end);
+		new_cplb_data = (data ? bfin_memory_map[i].data_flags : bfin_memory_map[i].inst_flags);
+
+		if (data) {
+			CPLB_ADDR_BASE = (uint32_t *)DCPLB_ADDR0;
+			CPLB_DATA_BASE = (uint32_t *)DCPLB_DATA0;
+		} else {
+			CPLB_ADDR_BASE = (uint32_t *)ICPLB_ADDR0;
+			CPLB_DATA_BASE = (uint32_t *)ICPLB_DATA0;
+		}
+
+		/* find the next unlocked entry and evict it */
+		i = last_evicted & 0xF;
+		debug("last evicted = %i\n", i);
+		CPLB_DATA = CPLB_DATA_BASE + i;
+		while (*CPLB_DATA & CPLB_LOCK) {
+			debug("skipping %i %p - %08X\n", i, CPLB_DATA, *CPLB_DATA);
+			i = (i + 1) & 0xF;	/* wrap around */
+			CPLB_DATA = CPLB_DATA_BASE + i;
+		}
+		CPLB_ADDR = CPLB_ADDR_BASE + i;
+
+		debug("evicting entry %i: 0x%p 0x%08X\n", i, *CPLB_ADDR, *CPLB_DATA);
+		last_evicted = i + 1;
+
+		/* need to turn off cplbs whenever we muck with the cplb table */
+#if ENDCPLB != ENICPLB
+# error cplb enable bit violates my sanity
+#endif
+		uint32_t mem_control = (data ? DMEM_CONTROL : IMEM_CONTROL);
+		bfin_write32(mem_control, bfin_read32(mem_control) & ~ENDCPLB);
+		*CPLB_ADDR = new_cplb_addr;
+		*CPLB_DATA = new_cplb_data;
+		bfin_write32(mem_control, bfin_read32(mem_control) | ENDCPLB);
+		SSYNC();
+
+		/* dump current table for debugging purposes */
+		CPLB_ADDR = CPLB_ADDR_BASE;
+		CPLB_DATA = CPLB_DATA_BASE;
+		for (i = 0; i < 16; ++i)
+			debug("%2i 0x%p 0x%08X\n", i, *CPLB_ADDR++, *CPLB_DATA++);
+
+		trace_buffer_restore(tflags);
+		break;
+	}
+#ifdef CONFIG_CMD_KGDB
+	/* Single step
+	 * if we are in IRQ5, just ignore, otherwise defer, and handle it in kgdb
+	 */
+	case VEC_STEP:
+		if (level == 3) {
+			/* If we just returned from an interrupt, the single step
+			 * event is for the RTI instruction.
+			 */
+			if (regs->retx == regs->pc)
+				break;
+			/* we just return if we are single stepping through IRQ5 */
+			if (regs->ipend & 0x20)
+				break;
+			/* Otherwise, turn single stepping off & fall through,
+			 * which defers to IRQ5
+			 */
+			regs->syscfg &= ~1;
+		}
+		/* fall through */
+#endif
+	default:
+#ifdef CONFIG_CMD_KGDB
+		if (level == 3) {
+			/* We need to handle this at EVT5, so try again */
+			ret = 1;
+			break;
+		}
+		if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+			return 0;
+#endif
+		bfin_panic(regs);
+	}
+	return ret;
+}
+
+#ifdef CONFIG_DEBUG_DUMP
+# define ENABLE_DUMP 1
+#else
+# define ENABLE_DUMP 0
+#endif
+
+#ifndef CONFIG_KALLSYMS
+const char *symbol_lookup(unsigned long addr, unsigned long *caddr)
+{
+	*caddr = addr;
+	return "N/A";
+}
+#endif
+
+static void decode_address(char *buf, unsigned long address)
+{
+	unsigned long sym_addr;
+	void *paddr = (void *)address;
+	const char *sym = symbol_lookup(address, &sym_addr);
+
+	if (sym) {
+		sprintf(buf, "<0x%p> { %s + 0x%lx }", paddr, sym, address - sym_addr);
+		return;
+	}
+
+	if (!address)
+		sprintf(buf, "<0x%p> /* Maybe null pointer? */", paddr);
+	else if (address >= CONFIG_SYS_MONITOR_BASE &&
+	         address < CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN)
+		sprintf(buf, "<0x%p> /* somewhere in u-boot */", paddr);
+	else
+		sprintf(buf, "<0x%p> /* unknown address */", paddr);
+}
+
+static char *strhwerrcause(uint16_t hwerrcause)
+{
+	switch (hwerrcause) {
+		case 0x02: return "system mmr error";
+		case 0x03: return "external memory addressing error";
+		case 0x12: return "performance monitor overflow";
+		case 0x18: return "raise 5 instruction";
+		default:   return "undef";
+	}
+}
+
+static char *strexcause(uint16_t excause)
+{
+	switch (excause) {
+		case 0x00 ... 0xf: return "custom exception";
+		case 0x10: return "single step";
+		case 0x11: return "trace buffer full";
+		case 0x21: return "undef inst";
+		case 0x22: return "illegal inst";
+		case 0x23: return "dcplb prot violation";
+		case 0x24: return "misaligned data";
+		case 0x25: return "unrecoverable event";
+		case 0x26: return "dcplb miss";
+		case 0x27: return "multiple dcplb hit";
+		case 0x28: return "emulation watchpoint";
+		case 0x2a: return "misaligned inst";
+		case 0x2b: return "icplb prot violation";
+		case 0x2c: return "icplb miss";
+		case 0x2d: return "multiple icplb hit";
+		case 0x2e: return "illegal use of supervisor resource";
+		default:   return "undef";
+	}
+}
+
+void dump(struct pt_regs *fp)
+{
+	char buf[150];
+	int i;
+	uint16_t hwerrcause, excause;
+
+	if (!ENABLE_DUMP)
+		return;
+
+#ifndef CONFIG_CMD_KGDB
+	/* fp->ipend is normally garbage, so load it ourself */
+	fp->ipend = bfin_read_IPEND();
+#endif
+
+	hwerrcause = (fp->seqstat & HWERRCAUSE) >> HWERRCAUSE_P;
+	excause = (fp->seqstat & EXCAUSE) >> EXCAUSE_P;
+
+	printf("SEQUENCER STATUS:\n");
+	printf(" SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n",
+		fp->seqstat, fp->ipend, fp->syscfg);
+	printf("  HWERRCAUSE: 0x%x: %s\n", hwerrcause, strhwerrcause(hwerrcause));
+	printf("  EXCAUSE   : 0x%x: %s\n", excause, strexcause(excause));
+	for (i = 6; i <= 15; ++i) {
+		if (fp->ipend & (1 << i)) {
+			decode_address(buf, bfin_read32(EVT0 + 4*i));
+			printf("  physical IVG%i asserted : %s\n", i, buf);
+		}
+	}
+	decode_address(buf, fp->rete);
+	printf(" RETE: %s\n", buf);
+	decode_address(buf, fp->retn);
+	printf(" RETN: %s\n", buf);
+	decode_address(buf, fp->retx);
+	printf(" RETX: %s\n", buf);
+	decode_address(buf, fp->rets);
+	printf(" RETS: %s\n", buf);
+	/* we lie and store RETI in "pc" */
+	decode_address(buf, fp->pc);
+	printf(" RETI: %s\n", buf);
+
+	if (fp->seqstat & EXCAUSE) {
+		decode_address(buf, bfin_read_DCPLB_FAULT_ADDR());
+		printf("DCPLB_FAULT_ADDR: %s\n", buf);
+		decode_address(buf, bfin_read_ICPLB_FAULT_ADDR());
+		printf("ICPLB_FAULT_ADDR: %s\n", buf);
+	}
+
+	printf("\nPROCESSOR STATE:\n");
+	printf(" R0 : %08lx    R1 : %08lx    R2 : %08lx    R3 : %08lx\n",
+		fp->r0, fp->r1, fp->r2, fp->r3);
+	printf(" R4 : %08lx    R5 : %08lx    R6 : %08lx    R7 : %08lx\n",
+		fp->r4, fp->r5, fp->r6, fp->r7);
+	printf(" P0 : %08lx    P1 : %08lx    P2 : %08lx    P3 : %08lx\n",
+		fp->p0, fp->p1, fp->p2, fp->p3);
+	printf(" P4 : %08lx    P5 : %08lx    FP : %08lx    SP : %08lx\n",
+		fp->p4, fp->p5, fp->fp, (unsigned long)fp);
+	printf(" LB0: %08lx    LT0: %08lx    LC0: %08lx\n",
+		fp->lb0, fp->lt0, fp->lc0);
+	printf(" LB1: %08lx    LT1: %08lx    LC1: %08lx\n",
+		fp->lb1, fp->lt1, fp->lc1);
+	printf(" B0 : %08lx    L0 : %08lx    M0 : %08lx    I0 : %08lx\n",
+		fp->b0, fp->l0, fp->m0, fp->i0);
+	printf(" B1 : %08lx    L1 : %08lx    M1 : %08lx    I1 : %08lx\n",
+		fp->b1, fp->l1, fp->m1, fp->i1);
+	printf(" B2 : %08lx    L2 : %08lx    M2 : %08lx    I2 : %08lx\n",
+		fp->b2, fp->l2, fp->m2, fp->i2);
+	printf(" B3 : %08lx    L3 : %08lx    M3 : %08lx    I3 : %08lx\n",
+		fp->b3, fp->l3, fp->m3, fp->i3);
+	printf("A0.w: %08lx   A0.x: %08lx   A1.w: %08lx   A1.x: %08lx\n",
+		fp->a0w, fp->a0x, fp->a1w, fp->a1x);
+
+	printf("USP : %08lx  ASTAT: %08lx\n",
+		fp->usp, fp->astat);
+
+	printf("\n");
+}
+
+void dump_bfin_trace_buffer(void)
+{
+	char buf[150];
+	unsigned long tflags;
+	int i = 0;
+
+	if (!ENABLE_DUMP)
+		return;
+
+	trace_buffer_save(tflags);
+
+	printf("Hardware Trace:\n");
+
+	if (bfin_read_TBUFSTAT() & TBUFCNT) {
+		for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
+			decode_address(buf, bfin_read_TBUF());
+			printf("%4i Target : %s\n", i, buf);
+			decode_address(buf, bfin_read_TBUF());
+			printf("     Source : %s\n", buf);
+		}
+	}
+
+	trace_buffer_restore(tflags);
+}
+
+void bfin_panic(struct pt_regs *regs)
+{
+	if (ENABLE_DUMP) {
+		unsigned long tflags;
+		trace_buffer_save(tflags);
+	}
+
+	puts(
+		"\n"
+		"\n"
+		"\n"
+		"Ack! Something bad happened to the Blackfin!\n"
+		"\n"
+	);
+	dump(regs);
+	dump_bfin_trace_buffer();
+	puts("\n");
+	bfin_reset_or_hang();
+}
diff --git a/arch/blackfin/cpu/watchdog.c b/arch/blackfin/cpu/watchdog.c
new file mode 100644
index 0000000..1886bda
--- /dev/null
+++ b/arch/blackfin/cpu/watchdog.c
@@ -0,0 +1,23 @@
+/*
+ * watchdog.c - driver for Blackfin on-chip watchdog
+ *
+ * Copyright (c) 2007-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <asm/blackfin.h>
+
+void hw_watchdog_reset(void)
+{
+	bfin_write_WDOG_STAT(0);
+}
+
+void hw_watchdog_init(void)
+{
+	bfin_write_WDOG_CNT(5 * get_sclk());	/* 5 second timeout */
+	hw_watchdog_reset();
+	bfin_write_WDOG_CTL(0x0);
+}
diff --git a/arch/blackfin/lib/u-boot.lds.S b/arch/blackfin/lib/u-boot.lds.S
index 2b23d8b..9163d20 100644
--- a/arch/blackfin/lib/u-boot.lds.S
+++ b/arch/blackfin/lib/u-boot.lds.S
@@ -73,14 +73,14 @@
 {
 	.text.pre :
 	{
-		cpu/blackfin/start.o (.text .text.*)
+		arch/blackfin/cpu/start.o (.text .text.*)
 
 		LDS_BOARD_TEXT
 	} >ram_code
 
 	.text.init :
 	{
-		cpu/blackfin/initcode.o (.text .text.*)
+		arch/blackfin/cpu/initcode.o (.text .text.*)
 	} >ram_code
 	__initcode_lma = LOADADDR(.text.init);
 	__initcode_len = SIZEOF(.text.init);