summaryrefslogtreecommitdiff
path: root/src/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/arm')
-rw-r--r--src/arch/arm/Kconfig28
-rw-r--r--src/arch/arm/Makefile.inc130
-rw-r--r--src/arch/arm/armv7/Kconfig11
-rw-r--r--src/arch/arm/armv7/Makefile.inc71
-rw-r--r--src/arch/arm/armv7/bootblock.S113
-rw-r--r--src/arch/arm/armv7/bootblock_simple.c63
-rw-r--r--src/arch/arm/armv7/cache.c328
-rw-r--r--src/arch/arm/armv7/exception.c180
-rw-r--r--src/arch/arm/armv7/exception_asm.S116
-rw-r--r--src/arch/arm/armv7/mmu.c144
-rw-r--r--src/arch/arm/armv7/thread.c127
-rw-r--r--src/arch/arm/boot.c28
-rw-r--r--src/arch/arm/bootblock.ld57
-rw-r--r--src/arch/arm/cpu.c42
-rw-r--r--src/arch/arm/div0.c33
-rw-r--r--src/arch/arm/eabi_compat.c31
-rw-r--r--src/arch/arm/id.S20
-rw-r--r--src/arch/arm/include/arch/boot/boot.h8
-rw-r--r--src/arch/arm/include/arch/byteorder.h27
-rw-r--r--src/arch/arm/include/arch/early_variables.h59
-rw-r--r--src/arch/arm/include/arch/exception.h38
-rw-r--r--src/arch/arm/include/arch/hlt.h9
-rw-r--r--src/arch/arm/include/arch/io.h94
-rw-r--r--src/arch/arm/include/arch/pci_ops.h25
-rw-r--r--src/arch/arm/include/arch/stages.h28
-rw-r--r--src/arch/arm/include/armv7.h76
-rw-r--r--src/arch/arm/include/armv7/arch/arch_io.h68
-rw-r--r--src/arch/arm/include/armv7/arch/cache.h341
-rw-r--r--src/arch/arm/include/armv7/arch/cpu.h108
-rw-r--r--src/arch/arm/include/armv7/arch/types.h46
-rw-r--r--src/arch/arm/include/assembler.h62
-rw-r--r--src/arch/arm/include/bootblock_common.h15
-rw-r--r--src/arch/arm/include/clocks.h43
-rw-r--r--src/arch/arm/include/smp/spinlock.h52
-rw-r--r--src/arch/arm/include/stdint.h93
-rw-r--r--src/arch/arm/include/utils.h56
-rw-r--r--src/arch/arm/memcpy.S244
-rw-r--r--src/arch/arm/memmove.S197
-rw-r--r--src/arch/arm/memset.S127
-rw-r--r--src/arch/arm/ramstage.ld134
-rw-r--r--src/arch/arm/romstage.ld109
-rw-r--r--src/arch/arm/stages.c61
-rw-r--r--src/arch/arm/tables.c77
43 files changed, 3719 insertions, 0 deletions
diff --git a/src/arch/arm/Kconfig b/src/arch/arm/Kconfig
new file mode 100644
index 0000000000..050cd62a20
--- /dev/null
+++ b/src/arch/arm/Kconfig
@@ -0,0 +1,28 @@
+config ARCH_BOOTBLOCK_ARM
+ bool
+ default n
+ select ARCH_ARM
+
+config ARCH_ROMSTAGE_ARM
+ bool
+ default n
+
+config ARCH_RAMSTAGE_ARM
+ bool
+ default n
+
+source src/arch/arm/armv7/Kconfig
+
+# If a custom bootblock is necessary, this option should be "select"-ed by
+# the thing that needs it, probably the CPU.
+config ARM_BOOTBLOCK_CUSTOM
+ bool
+ default n
+
+config CPU_HAS_BOOTBLOCK_INIT
+ bool
+ default n
+
+config MAINBOARD_HAS_BOOTBLOCK_INIT
+ bool
+ default n \ No newline at end of file
diff --git a/src/arch/arm/Makefile.inc b/src/arch/arm/Makefile.inc
new file mode 100644
index 0000000000..8838edfd46
--- /dev/null
+++ b/src/arch/arm/Makefile.inc
@@ -0,0 +1,130 @@
+################################################################################
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2012 The ChromiumOS Authors
+## Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+## Copyright (C) 2009-2010 coresystems GmbH
+## Copyright (C) 2009 Ronald G. Minnich
+##
+## 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; version 2 of the License.
+##
+## 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
+##
+###############################################################################
+# Take care of subdirectories
+###############################################################################
+subdirs-y += armv7/
+
+###############################################################################
+# ARM specific options
+###############################################################################
+
+ifeq ($(CONFIG_ARCH_ROMSTAGE_ARM),y)
+CBFSTOOL_PRE1_OPTS = -m arm -b $(CONFIG_BOOTBLOCK_ROM_OFFSET) -H $(CONFIG_CBFS_HEADER_ROM_OFFSET) -o $(CONFIG_CBFS_ROM_OFFSET)
+CBFSTOOL_PRE_OPTS = -b 0
+endif
+
+ifeq ($(CONFIG_ARCH_ARM),y)
+stages_c = $(src)/arch/arm/stages.c
+stages_o = $(obj)/arch/arm/stages.o
+
+$(stages_o): $(stages_c) $(obj)/config.h
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ $(CC_arm) -I. $(CPPFLAGS_arm) -c -o $@ $< -marm
+
+endif # CONFIG_ARCH_ARM
+
+###############################################################################
+# bootblock
+###############################################################################
+
+ifeq ($(CONFIG_ARCH_BOOTBLOCK_ARM),y)
+
+bootblock-y += id.S
+$(obj)/arch/arm/id.bootblock.o: $(obj)/build.h
+
+bootblock-y += stages.c
+bootblock-y += eabi_compat.c
+bootblock-y += memset.S
+bootblock-y += memcpy.S
+bootblock-y += memmove.S
+
+$(objcbfs)/bootblock.debug: $(src)/arch/arm/bootblock.ld $(obj)/ldoptions $$(bootblock-objs) $(obj)/config.h
+ @printf " LINK $(subst $(obj)/,,$(@))\n"
+ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
+ $(LD_bootblock) -m armelf_linux_eabi -static -o $@ -L$(obj) $< -T $(src)/arch/arm/bootblock.ld
+else
+ $(CC_bootblock) $(CFLAGS_bootblock) -nostartfiles -include $(obj)/config.h -static -o $@ -L$(obj) -T $(src)/arch/arm/bootblock.ld -Wl,--start-group $(bootblock-objs) $(LIBGCC_FILE_NAME_bootblock) -Wl,--end-group
+endif
+
+endif # CONFIG_ARCH_BOOTBLOCK_ARM
+
+###############################################################################
+# romstage
+###############################################################################
+
+ifeq ($(CONFIG_ARCH_ROMSTAGE_ARM),y)
+
+romstage-y += stages.c
+romstage-y += div0.c
+romstage-y += eabi_compat.c
+romstage-y += memset.S
+romstage-y += memcpy.S
+romstage-y += memmove.S
+
+VBOOT_STUB_DEPS += $(obj)/arch/arm/eabi_compat.rmodules_arm.o
+
+$(objcbfs)/romstage.debug: $$(romstage-objs) $(src)/arch/arm/romstage.ld $(obj)/ldoptions
+ @printf " LINK $(subst $(obj)/,,$(@))\n"
+ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
+ $(LD_romstage) -nostdlib -nostartfiles -static -o $@ -L$(obj) $(romstage-objs) -T $(src)/arch/arm/romstage.ld
+else
+ $(CC_romstage) $(CFLAGS_romstage) -nostartfiles -static -o $@ -L$(obj) -T $(src)/arch/arm/romstage.ld -Wl,--start-group $(romstage-objs) $(LIBGCC_FILE_NAME_romstage) -Wl,--end-group
+endif
+
+endif # CONFIG_ARCH_ROMSTAGE_ARM
+
+###############################################################################
+# ramstage
+###############################################################################
+
+ifeq ($(CONFIG_ARCH_RAMSTAGE_ARM),y)
+
+ramstage-y += stages.c
+ramstage-y += div0.c
+ramstage-y += cpu.c
+ramstage-y += eabi_compat.c
+ramstage-y += boot.c
+ramstage-y += tables.c
+ramstage-y += memset.S
+ramstage-y += memcpy.S
+ramstage-y += memmove.S
+ramstage-srcs += $(wildcard src/mainboard/$(MAINBOARDDIR)/mainboard.c)
+
+$(objcbfs)/ramstage.debug: $$(ramstage-objs) $(LIBGCC_FILE_NAME_ramstage) $(src)/arch/arm/ramstage.ld $(obj)/ldoptions
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
+ $(LD_ramstage) -m armelf_linux_eabi -o $@ -L$(obj) $< -T $(src)/arch/arm/ramstage.ld
+else
+ $(CC_ramstage) $(CFLAGS_ramstage) -nostdlib -nostartfiles -static -o $@ -L$(obj) -Wl,--start-group $(ramstage-objs) $(LIBGCC_FILE_NAME_ramstage) -Wl,--end-group -T $(src)/arch/arm/ramstage.ld
+endif
+
+$(objgenerated)/ramstage.o: $(stages_o) $$(ramstage-objs) $(LIBGCC_FILE_NAME_ramstage)
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y)
+ $(LD_ramstage) -m -m armelf_linux_eabi -r -o $@ --wrap __divdi3 --wrap __udivdi3 --wrap __moddi3 --wrap __umoddi3 --wrap __uidiv --start-group $(ramstage-objs) $(LIBGCC_FILE_NAME_ramstage) --end-group
+else
+ $(CC_ramstage) $(CFLAGS_ramstage) $(CPPFLAGS_ramstage) -nostdlib -r -o $@ -Wl,--start-group $(stages_o) $(ramstage-objs) $(LIBGCC_FILE_NAME_ramstage) -Wl,--end-group
+endif
+
+endif # CONFIG_ARCH_RAMSTAGE_ARM
diff --git a/src/arch/arm/armv7/Kconfig b/src/arch/arm/armv7/Kconfig
new file mode 100644
index 0000000000..f8e0205c40
--- /dev/null
+++ b/src/arch/arm/armv7/Kconfig
@@ -0,0 +1,11 @@
+config ARCH_BOOTBLOCK_ARMV7
+ def_bool n
+ select ARCH_BOOTBLOCK_ARM
+
+config ARCH_ROMSTAGE_ARMV7
+ def_bool n
+ select ARCH_ROMSTAGE_ARM
+
+config ARCH_RAMSTAGE_ARMV7
+ def_bool n
+ select ARCH_RAMSTAGE_ARM
diff --git a/src/arch/arm/armv7/Makefile.inc b/src/arch/arm/armv7/Makefile.inc
new file mode 100644
index 0000000000..bcd7d9e46d
--- /dev/null
+++ b/src/arch/arm/armv7/Makefile.inc
@@ -0,0 +1,71 @@
+################################################################################
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2013 The ChromiumOS Authors
+##
+## 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; version 2 of the License.
+##
+## 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
+##
+###############################################################################
+
+armv7_flags = -march=armv7-a -mthumb -mthumb-interwork \
+ -I$(src)/arch/arm/include/armv7/
+
+###############################################################################
+# bootblock
+###############################################################################
+
+ifeq ($(CONFIG_ARCH_BOOTBLOCK_ARMV7),y)
+
+ifneq ($(CONFIG_ARM_BOOTBLOCK_CUSTOM),y)
+bootblock-y += bootblock.S
+bootblock-$(CONFIG_BOOTBLOCK_SIMPLE) += bootblock_simple.c
+endif
+
+bootblock-y += cache.c
+bootblock-y += mmu.c
+
+CFLAGS_bootblock += $(armv7_flags)
+CPPFLAGS_bootblock += $(armv7_flags)
+
+endif # CONFIG_ARCH_BOOTBLOCK_ARMV7
+
+###############################################################################
+# romstage
+###############################################################################
+
+ifeq ($(CONFIG_ARCH_ROMSTAGE_ARMV7),y)
+
+romstage-y += cache.c
+
+CFLAGS_romstage += $(armv7_flags)
+CPPFLAGS_romstage += $(armv7_flags)
+
+endif # CONFIG_ARCH_ROMSTAGE_ARMV7
+
+###############################################################################
+# ramstage
+###############################################################################
+
+ifeq ($(CONFIG_ARCH_RAMSTAGE_ARMV7),y)
+
+ramstage-y += cache.c
+ramstage-y += exception.c
+ramstage-y += exception_asm.S
+ramstage-y += mmu.c
+
+CFLAGS_ramstage += $(armv7_flags)
+CPPFLAGS_ramstage += $(armv7_flags)
+
+endif # CONFIG_ARCH_RAMSTAGE_ARMV7
diff --git a/src/arch/arm/armv7/bootblock.S b/src/arch/arm/armv7/bootblock.S
new file mode 100644
index 0000000000..b28a787839
--- /dev/null
+++ b/src/arch/arm/armv7/bootblock.S
@@ -0,0 +1,113 @@
+/*
+ * Early initialization code for ARMv7 architecture.
+ *
+ * This file is based off of the OMAP3530/ARM Cortex start.S file from Das
+ * U-Boot, which itself got the file from armboot.
+ *
+ * Copyright (c) 2004 Texas Instruments <r-woodruff2@ti.com>
+ * Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
+ * Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
+ * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
+ * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com>
+ * Copyright (c) 2003 Kshitij <kshitij@ti.com>
+ * Copyright (c) 2006-2008 Syed Mohammed Khasim <x0khasim@ti.com>
+ * Copyright (c) 2013 The Chromium OS Authors
+ *
+ * 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; version 2 of
+ * the License.
+ *
+ * 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
+ */
+
+.section ".start", "a", %progbits
+.globl _start
+_start: b reset
+ .balignl 16,0xdeadbeef
+
+_cbfs_master_header:
+ /* The CBFS master header is inserted by cbfstool at the first
+ * aligned offset after the above anchor string is found.
+ * Hence, we leave some space for it.
+ */
+ .skip 128 @ Assumes 64-byte alignment
+
+reset:
+ /*
+ * Set the cpu to System mode with IRQ and FIQ disabled. Prefetch/Data
+ * aborts may happen early and crash before the abort handlers are
+ * installed, but at least the problem will show up near the code that
+ * causes it.
+ */
+ msr cpsr_cxf, #0xdf
+
+ /*
+ * From Cortex-A Series Programmer's Guide:
+ * Only CPU 0 performs initialization. Other CPUs go into WFI
+ * to do this, first work out which CPU this is
+ * this code typically is run before any other initialization step
+ */
+ mrc p15, 0, r1, c0, c0, 5 @ Read Multiprocessor Affinity Register
+ and r1, r1, #0x3 @ Extract CPU ID bits
+ cmp r1, #0
+ bne wait_for_interrupt @ If this is not core0, wait
+
+ /*
+ * Initialize the stack to a known value. This is used to check for
+ * stack overflow later in the boot process.
+ */
+ ldr r0, .Stack
+ ldr r1, .Stack_size
+ sub r0, r0, r1
+ ldr r1, .Stack
+ ldr r2, =0xdeadbeef
+init_stack_loop:
+ str r2, [r0]
+ add r0, #4
+ cmp r0, r1
+ bne init_stack_loop
+
+/* Set stackpointer in internal RAM to call board_init_f */
+call_bootblock:
+ ldr sp, .Stack /* Set up stack pointer */
+ ldr r0,=0x00000000
+ /*
+ * The current design of cpu_info places the
+ * struct at the top of the stack. The number of
+ * words pushed must be at least as large as that
+ * struct.
+ */
+ push {r0-r2}
+ bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
+ /*
+ * Use "bl" instead of "b" even though we do not intend to return.
+ * "bl" gets compiled to "blx" if we're transitioning from ARM to
+ * Thumb. However, "b" will not and GCC may attempt to create a
+ * wrapper which is currently broken.
+ */
+ bl main
+
+wait_for_interrupt:
+ wfi
+ mov pc, lr @ back to my caller
+
+/* we do it this way because it's a 32-bit constant and
+ * in some cases too far away to be loaded as just an offset
+ * from IP
+ */
+.align 2
+.Stack:
+ .word CONFIG_STACK_TOP
+.align 2
+/* create this size the same way we do in coreboot_ram.ld: top-bottom */
+.Stack_size:
+ .word CONFIG_STACK_TOP - CONFIG_STACK_BOTTOM
diff --git a/src/arch/arm/armv7/bootblock_simple.c b/src/arch/arm/armv7/bootblock_simple.c
new file mode 100644
index 0000000000..f447034029
--- /dev/null
+++ b/src/arch/arm/armv7/bootblock_simple.c
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2010 Google Inc.
+ *
+ * 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; version 2 of
+ * the License.
+ *
+ * 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 <arch/cache.h>
+#include <arch/hlt.h>
+#include <arch/stages.h>
+#include <bootblock_common.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <smp/node.h>
+
+void main(void)
+{
+ const char *stage_name = "fallback/romstage";
+ void *entry;
+ uint32_t sctlr;
+
+ /* Globally disable MMU, caches, and branch prediction (these should
+ * be disabled by default on reset) */
+ sctlr = read_sctlr();
+ sctlr &= ~(SCTLR_M | SCTLR_C | SCTLR_Z | SCTLR_I);
+ write_sctlr(sctlr);
+
+ arm_invalidate_caches();
+
+ /*
+ * Re-enable icache and branch prediction. MMU and dcache will be
+ * set up later.
+ */
+ sctlr = read_sctlr();
+ sctlr |= SCTLR_Z | SCTLR_I;
+ write_sctlr(sctlr);
+
+ bootblock_cpu_init();
+ bootblock_mainboard_init();
+
+#if CONFIG_BOOTBLOCK_CONSOLE
+ console_init();
+#endif
+
+ entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, stage_name);
+
+ if (entry) stage_exit(entry);
+ hlt();
+}
diff --git a/src/arch/arm/armv7/cache.c b/src/arch/arm/armv7/cache.c
new file mode 100644
index 0000000000..acd1f9aefa
--- /dev/null
+++ b/src/arch/arm/armv7/cache.c
@@ -0,0 +1,328 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * cache.c: Cache maintenance routines for ARMv7-A and ARMv7-R
+ *
+ * Reference: ARM Architecture Reference Manual, ARMv7-A and ARMv7-R edition
+ */
+
+#include <stdint.h>
+
+#include <arch/cache.h>
+
+#define bitmask(high, low) ((1UL << (high)) + \
+ ((1UL << (high)) - 1) - ((1UL << (low)) - 1))
+
+/* Basic log2() implementation. Note: log2(0) is 0 for our purposes. */
+/* FIXME: src/include/lib.h is difficult to work with due to romcc */
+static unsigned long log2(unsigned long u)
+{
+ int i = 0;
+
+ while (u >>= 1)
+ i++;
+
+ return i;
+}
+
+void tlb_invalidate_all(void)
+{
+ /*
+ * FIXME: ARMv7 Architecture Ref. Manual claims that the distinction
+ * instruction vs. data TLBs is deprecated in ARMv7, however this does
+ * not seem to be the case as of Cortex-A15.
+ */
+ tlbiall();
+ dtlbiall();
+ itlbiall();
+ isb();
+ dsb();
+}
+
+void icache_invalidate_all(void)
+{
+ /*
+ * icache can be entirely invalidated with one operation.
+ * Note: If branch predictors are architecturally-visible, ICIALLU
+ * also performs a BPIALL operation (B2-1283 in arch manual)
+ */
+ iciallu();
+ isb();
+}
+
+enum dcache_op {
+ OP_DCCSW,
+ OP_DCCISW,
+ OP_DCISW,
+ OP_DCCIMVAC,
+ OP_DCCMVAC,
+ OP_DCIMVAC,
+};
+
+/*
+ * Do a dcache operation on entire cache by set/way. This is done for
+ * portability because mapping of memory address to cache location is
+ * implementation defined (See note on "Requirements for operations by
+ * set/way" in arch ref. manual).
+ */
+static void dcache_op_set_way(enum dcache_op op)
+{
+ uint32_t ccsidr;
+ unsigned int associativity, num_sets, linesize_bytes;
+ unsigned int set, way;
+ unsigned int level;
+
+ level = (read_csselr() >> 1) & 0x7;
+
+ /*
+ * dcache must be invalidated by set/way for portability since virtual
+ * memory mapping is system-defined. The number of sets and
+ * associativity is given by CCSIDR. We'll use DCISW to invalidate the
+ * dcache.
+ */
+ ccsidr = read_ccsidr();
+
+ /* FIXME: rounding up required here? */
+ num_sets = ((ccsidr & bitmask(27, 13)) >> 13) + 1;
+ associativity = ((ccsidr & bitmask(12, 3)) >> 3) + 1;
+ /* FIXME: do we need to use CTR.DminLine here? */
+ linesize_bytes = (1 << ((ccsidr & 0x7) + 2)) * 4;
+
+ dsb();
+
+ /*
+ * Set/way operations require an interesting bit packing. See section
+ * B4-35 in the ARMv7 Architecture Reference Manual:
+ *
+ * A: Log2(associativity)
+ * B: L+S
+ * L: Log2(linesize)
+ * S: Log2(num_sets)
+ *
+ * The bits are packed as follows:
+ * 31 31-A B B-1 L L-1 4 3 1 0
+ * |---|-------------|--------|-------|-----|-|
+ * |Way| zeros | Set | zeros |level|0|
+ * |---|-------------|--------|-------|-----|-|
+ */
+ for (way = 0; way < associativity; way++) {
+ for (set = 0; set < num_sets; set++) {
+ uint32_t val = 0;
+ val |= way << (32 - log2(associativity));
+ val |= set << log2(linesize_bytes);
+ val |= level << 1;
+ switch(op) {
+ case OP_DCCISW:
+ dccisw(val);
+ break;
+ case OP_DCISW:
+ dcisw(val);
+ break;
+ case OP_DCCSW:
+ dccsw(val);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ isb();
+}
+
+static void dcache_foreach(enum dcache_op op)
+{
+ uint32_t clidr;
+ int level;
+
+ clidr = read_clidr();
+ for (level = 0; level < 7; level++) {
+ unsigned int ctype = (clidr >> (level * 3)) & 0x7;
+ uint32_t csselr;
+
+ switch(ctype) {
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ csselr = level << 1;
+ write_csselr(csselr);
+ dcache_op_set_way(op);
+ break;
+ default:
+ /* no cache, icache only, or reserved */
+ break;
+ }
+ }
+}
+
+void dcache_clean_all(void)
+{
+ dcache_foreach(OP_DCCSW);
+}
+
+void dcache_clean_invalidate_all(void)
+{
+ dcache_foreach(OP_DCCISW);
+}
+
+void dcache_invalidate_all(void)
+{
+ dcache_foreach(OP_DCISW);
+}
+
+static unsigned int line_bytes(void)
+{
+ uint32_t ccsidr;
+ unsigned int size;
+
+ ccsidr = read_ccsidr();
+ /* [2:0] - Indicates (Log2(number of words in cache line)) - 2 */
+ size = 1 << ((ccsidr & 0x7) + 2); /* words per line */
+ size *= sizeof(unsigned int); /* bytes per line */
+
+ return size;
+}
+
+/*
+ * Do a dcache operation by modified virtual address. This is useful for
+ * maintaining coherency in drivers which do DMA transfers and only need to
+ * perform cache maintenance on a particular memory range rather than the
+ * entire cache.
+ */
+static void dcache_op_mva(void const *addr, size_t len, enum dcache_op op)
+{
+ unsigned long line, linesize;
+
+ linesize = line_bytes();
+ line = (uint32_t)addr & ~(linesize - 1);
+
+ dsb();
+ while ((void *)line < addr + len) {
+ switch(op) {
+ case OP_DCCIMVAC:
+ dccimvac(line);
+ break;
+ case OP_DCCMVAC:
+ dccmvac(line);
+ break;
+ case OP_DCIMVAC:
+ dcimvac(line);
+ break;
+ default:
+ break;
+ }
+ line += linesize;
+ }
+ isb();
+}
+
+void dcache_clean_by_mva(void const *addr, size_t len)
+{
+ dcache_op_mva(addr, len, OP_DCCMVAC);
+}
+
+void dcache_clean_invalidate_by_mva(void const *addr, size_t len)
+{
+ dcache_op_mva(addr, len, OP_DCCIMVAC);
+}
+
+void dcache_invalidate_by_mva(void const *addr, size_t len)
+{
+ dcache_op_mva(addr, len, OP_DCIMVAC);
+}
+
+void dcache_mmu_disable(void)
+{
+ uint32_t sctlr;
+
+ dcache_clean_invalidate_all();
+ sctlr = read_sctlr();
+ sctlr &= ~(SCTLR_C | SCTLR_M);
+ write_sctlr(sctlr);
+}
+
+
+void dcache_mmu_enable(void)
+{
+ uint32_t sctlr;
+
+ sctlr = read_sctlr();
+ dcache_clean_invalidate_all();
+ sctlr |= SCTLR_C | SCTLR_M;
+ write_sctlr(sctlr);
+}
+
+void arm_invalidate_caches(void)
+{
+ uint32_t clidr;
+ int level;
+
+ /* Invalidate branch predictor */
+ bpiall();
+
+ /* Iterate thru each cache identified in CLIDR and invalidate */
+ clidr = read_clidr();
+ for (level = 0; level < 7; level++) {
+ unsigned int ctype = (clidr >> (level * 3)) & 0x7;
+ uint32_t csselr;
+
+ switch(ctype) {
+ case 0x0:
+ /* no cache */
+ break;
+ case 0x1:
+ /* icache only */
+ csselr = (level << 1) | 1;
+ write_csselr(csselr);
+ icache_invalidate_all();
+ break;
+ case 0x2:
+ case 0x4:
+ /* dcache only or unified cache */
+ csselr = level << 1;
+ write_csselr(csselr);
+ dcache_invalidate_all();
+ break;
+ case 0x3:
+ /* separate icache and dcache */
+ csselr = (level << 1) | 1;
+ write_csselr(csselr);
+ icache_invalidate_all();
+
+ csselr = level << 1;
+ write_csselr(csselr);
+ dcache_invalidate_all();
+ break;
+ default:
+ /* reserved */
+ break;
+ }
+ }
+
+ /* Invalidate TLB */
+ tlb_invalidate_all();
+}
diff --git a/src/arch/arm/armv7/exception.c b/src/arch/arm/armv7/exception.c
new file mode 100644
index 0000000000..3b32e8bbb1
--- /dev/null
+++ b/src/arch/arm/armv7/exception.c
@@ -0,0 +1,180 @@
+/*
+ * This file is part of the libpayload project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <types.h>
+#include <arch/exception.h>
+#include <console/console.h>
+
+void exception_test(void);
+
+static int test_abort;
+
+void exception_undefined_instruction(uint32_t *);
+void exception_software_interrupt(uint32_t *);
+void exception_prefetch_abort(uint32_t *);
+void exception_data_abort(uint32_t *);
+void exception_not_used(uint32_t *);
+void exception_irq(uint32_t *);
+void exception_fiq(uint32_t *);
+
+static void dump_stack(uintptr_t addr, size_t bytes)
+{
+ int i, j;
+ const int line = 8;
+ uint32_t *ptr = (uint32_t *)(addr & ~(line * sizeof(*ptr) - 1));
+
+ printk(BIOS_ERR, "Dumping stack:\n");
+ for (i = bytes / sizeof(*ptr); i >= 0; i -= line) {
+ printk(BIOS_ERR, "%p: ", ptr + i);
+ for (j = i; j < i + line; j++)
+ printk(BIOS_ERR, "%08x ", *(ptr + j));
+ printk(BIOS_ERR, "\n");
+ }
+}
+
+static void print_regs(uint32_t *regs)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ if (i == 15)
+ printk(BIOS_ERR, "PC");
+ else if (i == 14)
+ printk(BIOS_ERR, "LR");
+ else if (i == 13)
+ printk(BIOS_ERR, "SP");
+ else if (i == 12)
+ printk(BIOS_ERR, "IP");
+ else
+ printk(BIOS_ERR, "R%d", i);
+ printk(BIOS_ERR, " = 0x%08x\n", regs[i]);
+ }
+}
+
+void exception_undefined_instruction(uint32_t *regs)
+{
+ printk(BIOS_ERR, "exception _undefined_instruction\n");
+ print_regs(regs);
+ dump_stack(regs[13], 512);
+ die("exception");
+}
+
+void exception_software_interrupt(uint32_t *regs)
+{
+ printk(BIOS_ERR, "exception _software_interrupt\n");
+ print_regs(regs);
+ dump_stack(regs[13], 512);
+ die("exception");
+}
+
+void exception_prefetch_abort(uint32_t *regs)
+{
+ printk(BIOS_ERR, "exception _prefetch_abort\n");
+ print_regs(regs);
+ dump_stack(regs[13], 512);
+ die("exception");
+}
+
+void exception_data_abort(uint32_t *regs)
+{
+ if (test_abort) {
+ regs[15] = regs[0];
+ return;
+ } else {
+ printk(BIOS_ERR, "exception _data_abort\n");
+ print_regs(regs);
+ dump_stack(regs[13], 512);
+ }
+ die("exception");
+}
+
+void exception_not_used(uint32_t *regs)
+{
+ printk(BIOS_ERR, "exception _not_used\n");
+ print_regs(regs);
+ dump_stack(regs[13], 512);
+ die("exception");
+}
+
+void exception_irq(uint32_t *regs)
+{
+ printk(BIOS_ERR, "exception _irq\n");
+ print_regs(regs);
+ dump_stack(regs[13], 512);
+ die("exception");
+}
+
+void exception_fiq(uint32_t *regs)
+{
+ printk(BIOS_ERR, "exception _fiq\n");
+ print_regs(regs);
+ dump_stack(regs[13], 512);
+ die("exception");
+}
+
+static inline uint32_t get_sctlr(void)
+{
+ uint32_t val;
+ asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (val));
+ return val;
+}
+
+static inline void set_sctlr(uint32_t val)
+{
+ asm volatile("mcr p15, 0, %0, c1, c0, 0" :: "r" (val));
+ asm volatile("" ::: "memory");
+}
+
+void exception_init(void)
+{
+ static const uint32_t sctlr_te = (0x1 << 30);
+ static const uint32_t sctlr_v = (0x1 << 13);
+ static const uint32_t sctlr_a = (0x1 << 1);
+
+ uint32_t sctlr = get_sctlr();
+ /* Handle exceptions in ARM mode. */
+ sctlr &= ~sctlr_te;
+ /* Set V=0 in SCTLR so VBAR points to the exception vector table. */
+ sctlr &= ~sctlr_v;
+ /* Enforce alignment temporarily. */
+ set_sctlr(sctlr | sctlr_a);
+
+ extern uint32_t exception_table[];
+ set_vbar((uintptr_t)exception_table);
+
+ test_abort = 1;
+ printk(BIOS_ERR, "Testing exceptions\n");
+ exception_test();
+ test_abort = 0;
+ printk(BIOS_ERR, "Testing exceptions: DONE\n");
+
+ /* Restore original alignment settings. */
+ set_sctlr(sctlr);
+}
diff --git a/src/arch/arm/armv7/exception_asm.S b/src/arch/arm/armv7/exception_asm.S
new file mode 100644
index 0000000000..163fdbd52a
--- /dev/null
+++ b/src/arch/arm/armv7/exception_asm.S
@@ -0,0 +1,116 @@
+/*
+ * This file is part of the libpayload project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+exception_stack:
+ .align 5
+ .skip 0x2000, 0xa5
+exception_stack_end:
+ .word exception_stack_end
+
+exception_handler:
+ .word 0
+
+
+ .align 6
+ .arm
+ .global exception_table
+exception_table:
+ b 1f
+ b 2f
+ b 3f
+ b 4f
+ b 5f
+ b 6f
+ b 7f
+ b 8f
+
+1:
+ ldr sp, _not_used
+ b exception_common
+2:
+ ldr sp, _undefined_instruction
+ b exception_common
+3:
+ ldr sp, _software_interrupt
+ b exception_common
+4:
+ ldr sp, _prefetch_abort
+ b exception_common
+5:
+ ldr sp, _data_abort
+ b exception_common
+6:
+ ldr sp, _not_used
+ b exception_common
+7:
+ ldr sp, _irq
+ b exception_common
+8:
+ ldr sp, _fiq
+ b exception_common
+
+exception_common:
+ str sp, exception_handler
+ ldr sp, exception_stack_end
+ push { lr }
+ stmfd sp, { sp, lr }^
+ sub sp, sp, $8
+ push { r0 - r12 }
+ mov r0, sp
+ mov lr, pc
+ ldr pc, exception_handler
+ pop { r0 - r12 }
+ add sp, sp, $8
+ ldmfd sp!, { pc }^
+
+
+_undefined_instruction: .word exception_undefined_instruction
+_software_interrupt: .word exception_software_interrupt
+_prefetch_abort: .word exception_prefetch_abort
+_data_abort: .word exception_data_abort
+_not_used: .word exception_not_used
+_irq: .word exception_irq
+_fiq: .word exception_fiq
+
+ .thumb
+ .global set_vbar
+ .thumb_func
+set_vbar:
+ mcr p15, 0, r0, c12, c0, 0
+ bx lr
+
+ .global exception_test
+ .thumb_func
+exception_test:
+ mov r1, $1
+ mov r0, pc
+ add r0, $3
+ ldr r1, [r1]
+ bx lr
+
diff --git a/src/arch/arm/armv7/mmu.c b/src/arch/arm/armv7/mmu.c
new file mode 100644
index 0000000000..cc915a6a33
--- /dev/null
+++ b/src/arch/arm/armv7/mmu.c
@@ -0,0 +1,144 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <cbmem.h>
+#include <console/console.h>
+
+#include <arch/cache.h>
+#include <arch/io.h>
+
+static void *const ttb_buff = (void *)CONFIG_TTB_BUFFER;
+
+void mmu_disable_range(unsigned long start_mb, unsigned long size_mb)
+{
+ unsigned int i;
+ uint32_t *ttb_entry = ttb_buff;
+ printk(BIOS_DEBUG, "Disabling: 0x%08lx:0x%08lx\n",
+ start_mb*MiB, start_mb*MiB + size_mb*MiB - 1);
+
+ for (i = start_mb; i < start_mb + size_mb; i++)
+ writel(0, &ttb_entry[i]);
+
+ for (i = start_mb; i < start_mb + size_mb; i++) {
+ dccmvac((uintptr_t)&ttb_entry[i]);
+ tlbimvaa(i*MiB);
+ }
+}
+
+void mmu_config_range(unsigned long start_mb, unsigned long size_mb,
+ enum dcache_policy policy)
+{
+ unsigned int i;
+ uint32_t attr;
+ uint32_t *ttb_entry = ttb_buff;
+ const char *str = NULL;
+
+ /*
+ * Section entry bits:
+ * 31:20 - section base address
+ * 18 - 0 to indicate normal section (versus supersection)
+ * 17 - nG, 0 to indicate page is global
+ * 16 - S, 0 for non-shareable (?)
+ * 15 - APX, 0 for full access
+ * 14:12 - TEX, 0b000 for outer and inner write-back
+ * 11:10 - AP, 0b11 for full access
+ * 9 - P, ? (FIXME: not described or possibly obsolete?)
+ * 8: 5 - Domain
+ * 4 - XN, 1 to set execute-never (and also avoid prefetches)
+ * 3 - C, 1 for cacheable
+ * 2 - B, 1 for bufferable
+ * 1: 0 - 0b10 to indicate section entry
+ */
+
+ switch(policy) {
+ case DCACHE_OFF:
+ /* XN set to avoid prefetches to uncached/unbuffered regions */
+ attr = (0x3 << 10) | (1 << 4) | 0x2;
+ str = "off";
+ break;
+ case DCACHE_WRITEBACK:
+ attr = (0x3 << 10) | (1 << 3) | (1 << 2) | 0x2;
+ str = "writeback";
+ break;
+ case DCACHE_WRITETHROUGH:
+ attr = (0x3 << 10) | (1 << 3) | 0x2;
+ str = "writethrough";
+ break;
+ default:
+ printk(BIOS_ERR, "unknown dcache policy: %02x\n", policy);
+ return;
+ }
+
+ printk(BIOS_DEBUG, "Setting dcache policy: 0x%08lx:0x%08lx [%s]\n",
+ start_mb << 20, ((start_mb + size_mb) << 20) - 1, str);
+
+ /* Write out page table entries. */
+ for (i = start_mb; i < start_mb + size_mb; i++)
+ writel((i << 20) | attr, &ttb_entry[i]);
+
+ /* Flush the page table entries, and old translations from the TLB. */
+ for (i = start_mb; i < start_mb + size_mb; i++) {
+ dccmvac((uintptr_t)&ttb_entry[i]);
+ tlbimvaa(i*MiB);
+ }
+}
+
+void mmu_init(void)
+{
+ /*
+ * For coreboot's purposes, we will create a simple L1 page table
+ * in RAM with 1MB section translation entries over the 4GB address
+ * space.
+ * (ref: section 10.2 and example 15-4 in Cortex-A series
+ * programmer's guide)
+ */
+ printk(BIOS_DEBUG, "Translation table is @ %p\n", ttb_buff);
+
+ /*
+ * Disable TTBR1 by setting TTBCR.N to 0b000, which means the TTBR0
+ * table size is 16KB and has indices VA[31:20].
+ *
+ * ref: Arch Ref. Manual for ARMv7-A, B3.5.4,
+ */
+ write_ttbcr(read_ttbcr() & ~0x3);
+
+ /*
+ * Translation table base 0 address is in bits 31:14-N, where N is given
+ * by bits 2:0 in TTBCR (which we set to 0). All lower bits in this
+ * register should be zero for coreboot.
+ */
+ write_ttbr0((uintptr_t)ttb_buff);
+
+ /* disable domain-level checking of permissions */
+ write_dacr(~0);
+}
diff --git a/src/arch/arm/armv7/thread.c b/src/arch/arm/armv7/thread.c
new file mode 100644
index 0000000000..d0c23ff92d
--- /dev/null
+++ b/src/arch/arm/armv7/thread.c
@@ -0,0 +1,127 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 <console/console.h>
+#include <thread.h>
+
+/* The stack frame looks like the following. */
+struct pushed_regs {
+ u32 r4;
+ u32 r5;
+ u32 r6;
+ u32 r7;
+ u32 r8;
+ u32 r9;
+ u32 r10;
+ u32 r11;
+ u32 lr;
+};
+
+static inline uintptr_t push_stack(uintptr_t cur_stack, uintptr_t value)
+{
+ uintptr_t *addr;
+
+ cur_stack -= sizeof(value);
+ addr = (uintptr_t *)cur_stack;
+ *addr = value;
+ return cur_stack;
+}
+
+void arch_prepare_thread(struct thread *t,
+ void asmlinkage (*thread_entry)(void *), void *arg)
+{
+ uintptr_t stack = t->stack_current;
+ int i;
+ uintptr_t poison = 0xdeadbeef;
+
+ /* Push the LR. thread_entry()
+ * is assumed to never return.
+ */
+ stack = push_stack(stack, (uintptr_t)thread_entry);
+ /* Make room for the registers.
+ * Poison the initial stack. This is good hygiene and finds bugs.
+ * Poisoning the stack with different values helps when you're
+ * hunting for (e.g.) misaligned stacks or other such
+ * weirdness. The -1 is because we already pushed lr.
+ */
+ for(i = 0; i < sizeof(struct pushed_regs)/sizeof(u32)-1; i++)
+ stack = push_stack(stack, poison++);
+
+ t->stack_current = stack;
+}
+
+/* We could write this as a .S and the first time around that's how we
+ * did it. But there's always the question of matching our ARM
+ * directives in the .S with how gcc is doing things. It seems best
+ * to follow the pattern of the rest of the ARM port and just use
+ * inline assembly and let gcc get all the ELF magic right.
+ */
+void __attribute__((naked))
+switch_to_thread(uintptr_t new_stack, uintptr_t *saved_stack)
+{
+ /* Defintions for those of us not totally familiar with ARM:
+ * R15 -- PC, R14 -- LR, R13 -- SP
+ * R0-R3 need not be saved, nor R12.
+ * on entry, the only saved state is in LR -- the old PC.
+ * The args are in R0,R1.
+ * R0 is the new stack
+ * R1 is a pointer to the old stack save location
+ * Push R4-R11 and LR
+ * then switch stacks
+ * then pop R0-R12 and LR
+ * then mov PC,LR
+ *
+ * stack layout
+ * +------------+
+ * | LR | <-- sp + 0x20
+ * +------------+
+ * | R11 | <-- sp + 0x1c
+ * +------------+
+ * | R10 | <-- sp + 0x18
+ * +------------+
+ * | R9 | <-- sp + 0x14
+ * +------------+
+ * | R8 | <-- sp + 0x10
+ * +------------+
+ * | R7 | <-- sp + 0x0c
+ * +------------+
+ * | R6 | <-- sp + 0x08
+ * +------------+
+ * | R5 | <-- sp + 0x04
+ * +------------+
+ * | R4 | <-- sp + 0x00
+ * +------------+
+ */
+ asm volatile (
+ /* save context. */
+ "push {r4-r11,lr}\n\t"
+ /* Save the current stack */
+ "str sp,[r1]\n\t"
+ /* switch to the new stack */
+ "mov sp,r0\n\t"
+ /* restore the registers */
+ "pop {r4-r11,lr}\n\t"
+ /* resume other thread. */
+ "mov pc,lr\n\t"
+ );
+}
+
+void *arch_get_thread_stackbase(void)
+{
+ return (void *)CONFIG_STACK_BOTTOM;
+}
diff --git a/src/arch/arm/boot.c b/src/arch/arm/boot.c
new file mode 100644
index 0000000000..d872a79151
--- /dev/null
+++ b/src/arch/arm/boot.c
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 <console/console.h>
+#include <arch/stages.h>
+#include <payload_loader.h>
+
+void arch_payload_run(const struct payload *payload)
+{
+ printk(BIOS_SPEW, "entry = %p\n", payload->entry);
+ stage_exit(payload->entry);
+}
diff --git a/src/arch/arm/bootblock.ld b/src/arch/arm/bootblock.ld
new file mode 100644
index 0000000000..706f0a2c2e
--- /dev/null
+++ b/src/arch/arm/bootblock.ld
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2006 Advanced Micro Devices, Inc.
+ * Copyright (C) 2008-2010 coresystems GmbH
+ *
+ * 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; version 2 of the License.
+ *
+ * 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
+ */
+
+/* We use ELF as output format. So that we can debug the code in some form. */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+INCLUDE ldoptions
+
+PHDRS
+{
+ to_load PT_LOAD;
+}
+
+TARGET(binary)
+SECTIONS
+{
+ ROMLOC = CONFIG_BOOTBLOCK_BASE;
+
+ /* This section might be better named .setup */
+ .rom ROMLOC : {
+ _rom = .;
+ *(.start);
+ *(.id);
+ *(.text);
+ *(.text.*);
+ *(.rom.text);
+ *(.rom.data);
+ *(.rom.data.*);
+ *(.rodata.*);
+ _erom = .;
+ } : to_load = 0xff
+
+ /DISCARD/ : {
+ *(.comment)
+ *(.note)
+ *(.comment.*)
+ *(.note.*)
+ *(.ARM.*)
+ }
+}
diff --git a/src/arch/arm/cpu.c b/src/arch/arm/cpu.c
new file mode 100644
index 0000000000..f90c759559
--- /dev/null
+++ b/src/arch/arm/cpu.c
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <stdlib.h>
+#include <arch/cpu.h>
+
+/* Return the cpu struct which is at the high memory address of the stack.
+ */
+struct cpu_info *cpu_info(void)
+{
+ uintptr_t addr = ALIGN((uintptr_t)__builtin_frame_address(0),
+ CONFIG_STACK_SIZE);
+ addr -= sizeof(struct cpu_info);
+ return (void *)addr;
+}
+
diff --git a/src/arch/arm/div0.c b/src/arch/arm/div0.c
new file mode 100644
index 0000000000..ab06ad3bee
--- /dev/null
+++ b/src/arch/arm/div0.c
@@ -0,0 +1,33 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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 <console/console.h>
+
+void __div0(void); // called from asm so no need for a prototype in a header
+
+/* Replacement (=dummy) for GNU/Linux division-by zero handler */
+/* recursion is ok here because we have no formats ... */
+void __div0 (void)
+{
+ printk(BIOS_EMERG, "DIVIDE BY ZERO! continuing ... \n");
+}
diff --git a/src/arch/arm/eabi_compat.c b/src/arch/arm/eabi_compat.c
new file mode 100644
index 0000000000..0c79cd51d3
--- /dev/null
+++ b/src/arch/arm/eabi_compat.c
@@ -0,0 +1,31 @@
+/*
+ * Utility functions needed for (some) EABI conformant tool chains.
+ *
+ * (C) Copyright 2009 Wolfgang Denk <wd@denx.de>
+ *
+ * This program is Free Software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <console/console.h>
+
+/* FIXME(dhendrix): prototypes added for assembler */
+int raise (int signum) __attribute__((used));
+int raise (int signum)
+{
+ printk(BIOS_CRIT, "raise: Signal # %d caught\n", signum);
+ return 0;
+}
+
+/* Dummy function to avoid linker complaints */
+void __aeabi_unwind_cpp_pr0(void) __attribute__((used));
+void __aeabi_unwind_cpp_pr0(void)
+{
+};
+
+void __aeabi_unwind_cpp_pr1(void) __attribute__((used));
+void __aeabi_unwind_cpp_pr1(void)
+{
+};
diff --git a/src/arch/arm/id.S b/src/arch/arm/id.S
new file mode 100644
index 0000000000..a588f1e1da
--- /dev/null
+++ b/src/arch/arm/id.S
@@ -0,0 +1,20 @@
+#include <build.h>
+
+ .section ".id", "a", %progbits
+
+ .globl __id_start
+__id_start:
+ver:
+ .asciz COREBOOT_VERSION
+vendor:
+ .asciz CONFIG_MAINBOARD_VENDOR
+part:
+ .asciz CONFIG_MAINBOARD_PART_NUMBER
+.long __id_end - ver /* Reverse offset to the vendor id */
+.long __id_end - vendor /* Reverse offset to the vendor id */
+.long __id_end - part /* Reverse offset to the part number */
+.long CONFIG_ROM_SIZE /* Size of this romimage */
+ .globl __id_end
+
+__id_end:
+.previous
diff --git a/src/arch/arm/include/arch/boot/boot.h b/src/arch/arm/include/arch/boot/boot.h
new file mode 100644
index 0000000000..08651cd1a8
--- /dev/null
+++ b/src/arch/arm/include/arch/boot/boot.h
@@ -0,0 +1,8 @@
+#ifndef ASM_ARM_BOOT_H
+#define ASM_ARM_BOOT_H
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_ARM
+
+#endif /* ASM_ARM_BOOT_H */
diff --git a/src/arch/arm/include/arch/byteorder.h b/src/arch/arm/include/arch/byteorder.h
new file mode 100644
index 0000000000..8dc069f486
--- /dev/null
+++ b/src/arch/arm/include/arch/byteorder.h
@@ -0,0 +1,27 @@
+#ifndef _BYTEORDER_H
+#define _BYTEORDER_H
+
+#define __LITTLE_ENDIAN 1234
+
+#include <stdint.h>
+#include <swab.h>
+
+#define cpu_to_le64(x) ((uint64_t)(x))
+#define le64_to_cpu(x) ((uint64_t)(x))
+#define cpu_to_le32(x) ((uint32_t)(x))
+#define le32_to_cpu(x) ((uint32_t)(x))
+#define cpu_to_le16(x) ((uint16_t)(x))
+#define le16_to_cpu(x) ((uint16_t)(x))
+#define cpu_to_be64(x) swab64(x)
+#define be64_to_cpu(x) swab64(x)
+#define cpu_to_be32(x) swab32((x))
+#define be32_to_cpu(x) swab32((x))
+#define cpu_to_be16(x) swab16((x))
+#define be16_to_cpu(x) swab16((x))
+
+#define ntohll(x) be64_to_cpu(x)
+#define htonll(x) cpu_to_be64(x)
+#define ntohl(x) be32_to_cpu(x)
+#define htonl(x) cpu_to_be32(x)
+
+#endif /* _BYTEORDER_H */
diff --git a/src/arch/arm/include/arch/early_variables.h b/src/arch/arm/include/arch/early_variables.h
new file mode 100644
index 0000000000..cec0a46239
--- /dev/null
+++ b/src/arch/arm/include/arch/early_variables.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 ARCH_EARLY_VARIABLES_H
+#define ARCH_EARLY_VARIABLES_H
+
+#ifdef __PRE_RAM__
+#define CAR_GLOBAL __attribute__((section(".car.global_data")))
+#define CAR_CBMEM __attribute__((section(".car.cbmem_console")))
+#else
+#define CAR_GLOBAL
+#define CAR_CBMEM
+#endif
+
+#if defined(__PRE_RAM__)
+#define CAR_MIGRATE_ATTR __attribute__ ((used,section (".car.migrate")))
+
+/* Call migrate_fn_() when CAR globals are migrated. */
+#define CAR_MIGRATE(migrate_fn_) \
+ static void (* const migrate_fn_ ## _ptr)(void) CAR_MIGRATE_ATTR = \
+ migrate_fn_;
+
+/* Get the correct pointer for the CAR global variable. */
+void *car_get_var_ptr(void *var);
+
+/* Get and set a primitive type global variable. */
+#define car_get_var(var) \
+ *(typeof(var) *)car_get_var_ptr(&(var))
+#define car_set_var(var, val) \
+ do { car_get_var(var) = (val); } while(0)
+
+/* Migrate the CAR variables to memory. */
+void car_migrate_variables(void);
+
+#else
+#define CAR_MIGRATE(migrate_fn_)
+static inline void *car_get_var_ptr(void *var) { return var; }
+#define car_get_var(var) (var)
+#define car_set_var(var, val) do { (var) = (val); } while (0)
+static inline void car_migrate_variables(void) { }
+#endif
+
+#endif
diff --git a/src/arch/arm/include/arch/exception.h b/src/arch/arm/include/arch/exception.h
new file mode 100644
index 0000000000..57076bd57b
--- /dev/null
+++ b/src/arch/arm/include/arch/exception.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the libpayload project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ARCH_EXCEPTION_H
+#define _ARCH_EXCEPTION_H
+
+#include <stdint.h>
+
+void exception_init(void);
+void set_vbar(uint32_t vbar);
+
+#endif
diff --git a/src/arch/arm/include/arch/hlt.h b/src/arch/arm/include/arch/hlt.h
new file mode 100644
index 0000000000..285b6f8786
--- /dev/null
+++ b/src/arch/arm/include/arch/hlt.h
@@ -0,0 +1,9 @@
+#ifndef ARCH_HLT_H
+#define ARCH_HLT_H
+
+static inline __attribute__((always_inline)) void hlt(void)
+{
+ for (;;) ;
+}
+
+#endif /* ARCH_HLT_H */
diff --git a/src/arch/arm/include/arch/io.h b/src/arch/arm/include/arch/io.h
new file mode 100644
index 0000000000..e53729708d
--- /dev/null
+++ b/src/arch/arm/include/arch/io.h
@@ -0,0 +1,94 @@
+/*
+ * Originally imported from linux/include/asm-arm/io.h. This file has changed
+ * substantially since then.
+ *
+ * Copyright 2013 Google Inc.
+ * Copyright (C) 1996-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Modifications:
+ * 08-Apr-2013 G Replaced several macros with inlines for type safety.
+ * 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both
+ * constant addresses and variable addresses.
+ * 04-Dec-1997 RMK Moved a lot of this stuff to the new architecture
+ * specific IO header files.
+ * 27-Mar-1999 PJB Second parameter of memcpy_toio is const..
+ * 04-Apr-1999 PJB Added check_signature.
+ * 12-Dec-1999 RMK More cleanups
+ * 18-Jun-2000 RMK Removed virt_to_* and friends definitions
+ */
+#ifndef __ASM_ARM_IO_H
+#define __ASM_ARM_IO_H
+
+#include <arch/byteorder.h>
+#include <arch/arch_io.h>
+#include <stdint.h>
+
+/*
+ * FIXME: These are to avoid breaking existing ARM code. We should eventually
+ * re-factor all code to specify the data length intended.
+ */
+#define readb(a) read8(a)
+#define writeb(v,a) write8(v,a)
+#define readl(a) read32(a)
+#define writel(v,a) write32(v,a)
+
+/*
+ * Clear and set bits in one shot. These macros can be used to clear and
+ * set multiple bits in a register using a single call. These macros can
+ * also be used to set a multiple-bit bit pattern using a mask, by
+ * specifying the mask in the 'clear' parameter and the new bit pattern
+ * in the 'set' parameter.
+ */
+
+#define out_arch(type,endian,a,v) write##type(cpu_to_##endian(v),a)
+#define in_arch(type,endian,a) endian##_to_cpu(read##type(a))
+
+#define out_le32(a,v) out_arch(l,le32,a,v)
+#define out_le16(a,v) out_arch(w,le16,a,v)
+
+#define in_le32(a) in_arch(l,le32,a)
+#define in_le16(a) in_arch(w,le16,a)
+
+#define out_be32(a,v) out_arch(l,be32,a,v)
+#define out_be16(a,v) out_arch(w,be16,a,v)
+
+#define in_be32(a) in_arch(l,be32,a)
+#define in_be16(a) in_arch(w,be16,a)
+
+#define out_8(a,v) writeb(v,a)
+#define in_8(a) readb(a)
+
+#define clrbits(type, addr, clear) \
+ out_##type((addr), in_##type(addr) & ~(clear))
+
+#define setbits(type, addr, set) \
+ out_##type((addr), in_##type(addr) | (set))
+
+#define clrsetbits(type, addr, clear, set) \
+ out_##type((addr), (in_##type(addr) & ~(clear)) | (set))
+
+#define clrbits_be32(addr, clear) clrbits(be32, addr, clear)
+#define setbits_be32(addr, set) setbits(be32, addr, set)
+#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set)
+
+#define clrbits_le32(addr, clear) clrbits(le32, addr, clear)
+#define setbits_le32(addr, set) setbits(le32, addr, set)
+#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set)
+
+#define clrbits_be16(addr, clear) clrbits(be16, addr, clear)
+#define setbits_be16(addr, set) setbits(be16, addr, set)
+#define clrsetbits_be16(addr, clear, set) clrsetbits(be16, addr, clear, set)
+
+#define clrbits_le16(addr, clear) clrbits(le16, addr, clear)
+#define setbits_le16(addr, set) setbits(le16, addr, set)
+#define clrsetbits_le16(addr, clear, set) clrsetbits(le16, addr, clear, set)
+
+#define clrbits_8(addr, clear) clrbits(8, addr, clear)
+#define setbits_8(addr, set) setbits(8, addr, set)
+#define clrsetbits_8(addr, clear, set) clrsetbits(8, addr, clear, set)
+
+#endif /* __ASM_ARM_IO_H */
diff --git a/src/arch/arm/include/arch/pci_ops.h b/src/arch/arm/include/arch/pci_ops.h
new file mode 100644
index 0000000000..faa77012d3
--- /dev/null
+++ b/src/arch/arm/include/arch/pci_ops.h
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 ARCH_ARM_PCI_OPS_H
+#define ARCH_ARM_PCI_OPS_H
+
+/* Empty stub until PCI includes are properly fixed. */
+
+#endif
diff --git a/src/arch/arm/include/arch/stages.h b/src/arch/arm/include/arch/stages.h
new file mode 100644
index 0000000000..39fed990c5
--- /dev/null
+++ b/src/arch/arm/include/arch/stages.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 The ChromiumOS Authors
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 __ARCH_STAGES_H
+#define __ARCH_STAGES_H
+
+extern void main(void);
+
+void stage_entry(void) __attribute__((section(".text.stage_entry.arm")));
+void stage_exit(void *);
+
+#endif
diff --git a/src/arch/arm/include/armv7.h b/src/arch/arm/include/armv7.h
new file mode 100644
index 0000000000..147323457a
--- /dev/null
+++ b/src/arch/arm/include/armv7.h
@@ -0,0 +1,76 @@
+/*
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ * Aneesh V <aneesh@ti.com>
+ *
+ * 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
+ */
+#ifndef ARMV7_H
+#define ARMV7_H
+#include <types.h>
+
+/* Cortex-A9 revisions */
+#define MIDR_CORTEX_A9_R0P1 0x410FC091
+#define MIDR_CORTEX_A9_R1P2 0x411FC092
+#define MIDR_CORTEX_A9_R1P3 0x411FC093
+#define MIDR_CORTEX_A9_R2P10 0x412FC09A
+
+/* Cortex-A15 revisions */
+#define MIDR_CORTEX_A15_R0P0 0x410FC0F0
+
+/* CCSIDR */
+#define CCSIDR_LINE_SIZE_OFFSET 0
+#define CCSIDR_LINE_SIZE_MASK 0x7
+#define CCSIDR_ASSOCIATIVITY_OFFSET 3
+#define CCSIDR_ASSOCIATIVITY_MASK (0x3FF << 3)
+#define CCSIDR_NUM_SETS_OFFSET 13
+#define CCSIDR_NUM_SETS_MASK (0x7FFF << 13)
+
+/*
+ * Values for InD field in CSSELR
+ * Selects the type of cache
+ */
+#define ARMV7_CSSELR_IND_DATA_UNIFIED 0
+#define ARMV7_CSSELR_IND_INSTRUCTION 1
+
+/* Values for Ctype fields in CLIDR */
+#define ARMV7_CLIDR_CTYPE_NO_CACHE 0
+#define ARMV7_CLIDR_CTYPE_INSTRUCTION_ONLY 1
+#define ARMV7_CLIDR_CTYPE_DATA_ONLY 2
+#define ARMV7_CLIDR_CTYPE_INSTRUCTION_DATA 3
+#define ARMV7_CLIDR_CTYPE_UNIFIED 4
+
+/*
+ * CP15 Barrier instructions
+ * Please note that we have separate barrier instructions in ARMv7
+ * However, we use the CP15 based instructions because we use
+ * -march=armv5 in U-Boot
+ */
+#define CP15ISB asm volatile ("mcr p15, 0, %0, c7, c5, 4" : : "r" (0))
+#define CP15DSB asm volatile ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0))
+#define CP15DMB asm volatile ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0))
+
+void v7_outer_cache_enable(void);
+void v7_outer_cache_disable(void);
+void v7_outer_cache_flush_all(void);
+void v7_outer_cache_inval_all(void);
+void v7_outer_cache_flush_range(u32 start, u32 end);
+void v7_outer_cache_inval_range(u32 start, u32 end);
+
+#endif
diff --git a/src/arch/arm/include/armv7/arch/arch_io.h b/src/arch/arm/include/armv7/arch/arch_io.h
new file mode 100644
index 0000000000..360fa6425a
--- /dev/null
+++ b/src/arch/arm/include/armv7/arch/arch_io.h
@@ -0,0 +1,68 @@
+/*
+ * Originally imported from linux/include/asm-arm/io.h. This file has changed
+ * substantially since then.
+ *
+ * Copyright 2013 Google Inc.
+ * Copyright (C) 1996-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Modifications:
+ * 08-Apr-2013 G Replaced several macros with inlines for type safety.
+ * 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both
+ * constant addresses and variable addresses.
+ * 04-Dec-1997 RMK Moved a lot of this stuff to the new architecture
+ * specific IO header files.
+ * 27-Mar-1999 PJB Second parameter of memcpy_toio is const..
+ * 04-Apr-1999 PJB Added check_signature.
+ * 12-Dec-1999 RMK More cleanups
+ * 18-Jun-2000 RMK Removed virt_to_* and friends definitions
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#include <arch/cache.h> /* for dmb() */
+#include <stdint.h>
+
+static inline uint8_t read8(const void *addr)
+{
+ dmb();
+ return *(volatile uint8_t *)addr;
+}
+
+static inline uint16_t read16(const void *addr)
+{
+ dmb();
+ return *(volatile uint16_t *)addr;
+}
+
+static inline uint32_t read32(const void *addr)
+{
+ dmb();
+ return *(volatile uint32_t *)addr;
+}
+
+static inline void write8(uint8_t val, void *addr)
+{
+ dmb();
+ *(volatile uint8_t *)addr = val;
+ dmb();
+}
+
+static inline void write16(uint16_t val, void *addr)
+{
+ dmb();
+ *(volatile uint16_t *)addr = val;
+ dmb();
+}
+
+static inline void write32(uint32_t val, void *addr)
+{
+ dmb();
+ *(volatile uint32_t *)addr = val;
+ dmb();
+}
+
+#endif /* __ASM_ARM_ARCH_IO_H */
diff --git a/src/arch/arm/include/armv7/arch/cache.h b/src/arch/arm/include/armv7/arch/cache.h
new file mode 100644
index 0000000000..ffdb55a706
--- /dev/null
+++ b/src/arch/arm/include/armv7/arch/cache.h
@@ -0,0 +1,341 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * cache.h: Cache maintenance API for ARM
+ */
+
+#ifndef ARM_CACHE_H
+#define ARM_CACHE_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* SCTLR bits */
+#define SCTLR_M (1 << 0) /* MMU enable */
+#define SCTLR_A (1 << 1) /* Alignment check enable */
+#define SCTLR_C (1 << 2) /* Data/unified cache enable */
+/* Bits 4:3 are reserved */
+#define SCTLR_CP15BEN (1 << 5) /* CP15 barrier enable */
+/* Bit 6 is reserved */
+#define SCTLR_B (1 << 7) /* Endianness */
+/* Bits 9:8 */
+#define SCTLR_SW (1 << 10) /* SWP and SWPB enable */
+#define SCTLR_Z (1 << 11) /* Branch prediction enable */
+#define SCTLR_I (1 << 12) /* Instruction cache enable */
+#define SCTLR_V (1 << 13) /* Low/high exception vectors */
+#define SCTLR_RR (1 << 14) /* Round Robin select */
+/* Bits 16:15 are reserved */
+#define SCTLR_HA (1 << 17) /* Hardware Access flag enable */
+/* Bit 18 is reserved */
+/* Bits 20:19 reserved virtualization not supported */
+#define SCTLR_WXN (1 << 19) /* Write permission implies XN */
+#define SCTLR_UWXN (1 << 20) /* Unprivileged write permission
+ implies PL1 XN */
+#define SCTLR_FI (1 << 21) /* Fast interrupt config enable */
+#define SCTLR_U (1 << 22) /* Unaligned access behavior */
+#define SCTLR_VE (1 << 24) /* Interrupt vectors enable */
+#define SCTLR_EE (1 << 25) /* Exception endianness */
+/* Bit 26 is reserved */
+#define SCTLR_NMFI (1 << 27) /* Non-maskable FIQ support */
+#define SCTLR_TRE (1 << 28) /* TEX remap enable */
+#define SCTLR_AFE (1 << 29) /* Access flag enable */
+#define SCTLR_TE (1 << 30) /* Thumb exception enable */
+/* Bit 31 is reserved */
+
+/*
+ * Sync primitives
+ */
+
+/* data memory barrier */
+static inline void dmb(void)
+{
+ asm volatile ("dmb" : : : "memory");
+}
+
+/* data sync barrier */
+static inline void dsb(void)
+{
+ asm volatile ("dsb" : : : "memory");
+}
+
+/* instruction sync barrier */
+static inline void isb(void)
+{
+ asm volatile ("isb" : : : "memory");
+}
+
+/*
+ * Low-level TLB maintenance operations
+ */
+
+/* invalidate entire data TLB */
+static inline void dtlbiall(void)
+{
+ asm volatile ("mcr p15, 0, %0, c8, c6, 0" : : "r" (0) : "memory");
+}
+
+/* invalidate entire instruction TLB */
+static inline void itlbiall(void)
+{
+ asm volatile ("mcr p15, 0, %0, c8, c5, 0" : : "r" (0));
+}
+
+/* invalidate entire unified TLB */
+static inline void tlbiall(void)
+{
+ asm volatile ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0) : "memory");
+}
+
+/* invalidate unified TLB by MVA, all ASID */
+static inline void tlbimvaa(unsigned long mva)
+{
+ asm volatile ("mcr p15, 0, %0, c8, c7, 3" : : "r" (mva) : "memory");
+}
+
+/* write data access control register (DACR) */
+static inline void write_dacr(uint32_t val)
+{
+ asm volatile ("mcr p15, 0, %0, c3, c0, 0" : : "r" (val));
+}
+
+/* write translation table base register 0 (TTBR0) */
+static inline void write_ttbr0(uint32_t val)
+{
+ asm volatile ("mcr p15, 0, %0, c2, c0, 0" : : "r" (val) : "memory");
+}
+
+/* read translation table base control register (TTBCR) */
+static inline uint32_t read_ttbcr(void)
+{
+ uint32_t val = 0;
+ asm volatile ("mrc p15, 0, %0, c2, c0, 2" : "=r" (val));
+ return val;
+}
+
+/* write translation table base control register (TTBCR) */
+static inline void write_ttbcr(uint32_t val)
+{
+ asm volatile ("mcr p15, 0, %0, c2, c0, 2" : : "r" (val) : "memory");
+}
+
+/*
+ * Low-level cache maintenance operations
+ */
+
+/* branch predictor invalidate all */
+static inline void bpiall(void)
+{
+ asm volatile ("mcr p15, 0, %0, c7, c5, 6" : : "r" (0));
+}
+
+/* data cache clean and invalidate by MVA to PoC */
+static inline void dccimvac(unsigned long mva)
+{
+ asm volatile ("mcr p15, 0, %0, c7, c14, 1" : : "r" (mva) : "memory");
+}
+
+/* data cache invalidate by set/way */
+static inline void dccisw(uint32_t val)
+{
+ asm volatile ("mcr p15, 0, %0, c7, c14, 2" : : "r" (val) : "memory");
+}
+
+/* data cache clean by MVA to PoC */
+static inline void dccmvac(unsigned long mva)
+{
+ asm volatile ("mcr p15, 0, %0, c7, c10, 1" : : "r" (mva) : "memory");
+}
+
+/* data cache clean by set/way */
+static inline void dccsw(uint32_t val)
+{
+ asm volatile ("mcr p15, 0, %0, c7, c10, 2" : : "r" (val) : "memory");
+}
+
+/* data cache invalidate by MVA to PoC */
+static inline void dcimvac(unsigned long mva)
+{
+ asm volatile ("mcr p15, 0, %0, c7, c6, 1" : : "r" (mva) : "memory");
+}
+
+/* data cache invalidate by set/way */
+static inline void dcisw(uint32_t val)
+{
+ asm volatile ("mcr p15, 0, %0, c7, c6, 2" : : "r" (val) : "memory");
+}
+
+/* instruction cache invalidate all by PoU */
+static inline void iciallu(void)
+{
+ asm volatile ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
+}
+
+/*
+ * Cache co-processor (CP15) access functions
+ */
+
+/* read cache level ID register (CLIDR) */
+static inline uint32_t read_clidr(void)
+{
+ uint32_t val = 0;
+ asm volatile ("mrc p15, 1, %0, c0, c0, 1" : "=r" (val));
+ return val;
+}
+
+/* read cache size ID register register (CCSIDR) */
+static inline uint32_t read_ccsidr(void)
+{
+ uint32_t val = 0;
+ asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (val));
+ return val;
+}
+
+/* read cache size selection register (CSSELR) */
+static inline uint32_t read_csselr(void)
+{
+ uint32_t val = 0;
+ asm volatile ("mrc p15, 2, %0, c0, c0, 0" : "=r" (val));
+ return val;
+}
+
+/* write to cache size selection register (CSSELR) */
+static inline void write_csselr(uint32_t val)
+{
+ /*
+ * Bits [3:1] - Cache level + 1 (0b000 = L1, 0b110 = L7, 0b111 is rsvd)
+ * Bit 0 - 0 = data or unified cache, 1 = instruction cache
+ */
+ asm volatile ("mcr p15, 2, %0, c0, c0, 0" : : "r" (val));
+ isb(); /* ISB to sync the change to CCSIDR */
+}
+
+/* read L2 control register (L2CTLR) */
+static inline uint32_t read_l2ctlr(void)
+{
+ uint32_t val = 0;
+ asm volatile ("mrc p15, 1, %0, c9, c0, 2" : "=r" (val));
+ return val;
+}
+
+/* write L2 control register (L2CTLR) */
+static inline void write_l2ctlr(uint32_t val)
+{
+ /*
+ * Note: L2CTLR can only be written when the L2 memory system
+ * is idle, ie before the MMU is enabled.
+ */
+ asm volatile("mcr p15, 1, %0, c9, c0, 2" : : "r" (val) : "memory" );
+ isb();
+}
+
+/* read L2 Auxiliary Control Register (L2ACTLR) */
+static inline uint32_t read_l2actlr(void)
+{
+ uint32_t val = 0;
+ asm volatile ("mrc p15, 1, %0, c15, c0, 0" : "=r" (val));
+ return val;
+}
+
+/* write L2 Auxiliary Control Register (L2ACTLR) */
+static inline void write_l2actlr(uint32_t val)
+{
+ asm volatile ("mcr p15, 1, %0, c15, c0, 0" : : "r" (val) : "memory" );
+ isb();
+}
+
+/* read system control register (SCTLR) */
+static inline uint32_t read_sctlr(void)
+{
+ uint32_t val;
+ asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (val));
+ return val;
+}
+
+/* write system control register (SCTLR) */
+static inline void write_sctlr(uint32_t val)
+{
+ asm volatile ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val) : "cc");
+ isb();
+}
+
+/*
+ * Cache maintenance API
+ */
+
+/* dcache clean and invalidate all (on current level given by CCSELR) */
+void dcache_clean_invalidate_all(void);
+
+/* dcache clean by modified virtual address to PoC */
+void dcache_clean_by_mva(void const *addr, size_t len);
+
+/* dcache clean and invalidate by modified virtual address to PoC */
+void dcache_clean_invalidate_by_mva(void const *addr, size_t len);
+
+/* dcache invalidate by modified virtual address to PoC */
+void dcache_invalidate_by_mva(void const *addr, size_t len);
+
+void dcache_clean_all(void);
+
+/* dcache invalidate all (on current level given by CCSELR) */
+void dcache_invalidate_all(void);
+
+/* dcache and MMU disable */
+void dcache_mmu_disable(void);
+
+/* dcache and MMU enable */
+void dcache_mmu_enable(void);
+
+/* icache invalidate all (on current level given by CSSELR) */
+void icache_invalidate_all(void);
+
+/* tlb invalidate all */
+void tlb_invalidate_all(void);
+
+/*
+ * Generalized setup/init functions
+ */
+
+/* invalidate all caches on ARM */
+void arm_invalidate_caches(void);
+
+/* mmu initialization (set page table address, set permissions, etc) */
+void mmu_init(void);
+
+enum dcache_policy {
+ DCACHE_OFF,
+ DCACHE_WRITEBACK,
+ DCACHE_WRITETHROUGH,
+};
+
+/* disable the mmu for a range. Primarily useful to lock out address 0. */
+void mmu_disable_range(unsigned long start_mb, unsigned long size_mb);
+/* mmu range configuration (set dcache policy) */
+void mmu_config_range(unsigned long start_mb, unsigned long size_mb,
+ enum dcache_policy policy);
+
+#endif /* ARM_CACHE_H */
diff --git a/src/arch/arm/include/armv7/arch/cpu.h b/src/arch/arm/include/armv7/arch/cpu.h
new file mode 100644
index 0000000000..52cc8a3f50
--- /dev/null
+++ b/src/arch/arm/include/armv7/arch/cpu.h
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2012 Google Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 __ARCH_CPU_H__
+#define __ARCH_CPU_H__
+
+#define asmlinkage
+
+#if !defined(__PRE_RAM__)
+#include <device/device.h>
+
+struct cpu_driver {
+ struct device_operations *ops;
+ struct cpu_device_id *id_table;
+};
+
+struct thread;
+
+struct cpu_info {
+ device_t cpu;
+ unsigned long index;
+#if CONFIG_COOP_MULTITASKING
+ struct thread *thread;
+#endif
+};
+
+struct cpuinfo_arm {
+ uint8_t arm; /* CPU family */
+ uint8_t arm_vendor; /* CPU vendor */
+ uint8_t arm_model;
+};
+
+#endif
+
+/* Primitives for CPU and MP cores. */
+
+/* read Main Id register (MIDR) */
+inline static uint32_t read_midr(void)
+{
+ uint32_t value;
+ asm volatile ("mrc p15, 0, %0, c0, c0, 0" : "=r"(value));
+ return value;
+}
+
+/* read Multiprocessor Affinity Register (MPIDR) */
+inline static uint32_t read_mpidr(void)
+{
+ uint32_t value;
+ asm volatile ("mrc p15, 0, %0, c0, c0, 5" : "=r"(value));
+ return value;
+}
+
+/* read Auxiliary Control Register (ACTLR) */
+inline static uint32_t read_actlr(void)
+{
+ uint32_t val = 0;
+ asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r"(val));
+ return val;
+}
+
+/* write Auxiliary Control Register (ACTLR) */
+inline static void write_actlr(uint32_t val)
+{
+ asm volatile ("mcr p15, 0, %0, c1, c0, 1" : : "r" (val));
+}
+
+/* wait for interrupt. */
+inline static void wfi(void)
+{
+ asm volatile ("wfi" : : : "memory");
+}
+
+/* wait for event. */
+inline static void wfe(void)
+{
+ asm volatile ("wfe");
+}
+
+/* set event (to bring up cores in WFE state). */
+inline static void sev(void)
+{
+ asm volatile ("sev");
+}
+
+/* puts CPU into System mode and disable interrupts. */
+inline static void set_system_mode(void)
+{
+ asm volatile("msr cpsr_c, %0" :: "r"(0x1f | 0xc0));
+}
+
+struct cpu_info *cpu_info(void);
+#endif /* __ARCH_CPU_H__ */
diff --git a/src/arch/arm/include/armv7/arch/types.h b/src/arch/arm/include/armv7/arch/types.h
new file mode 100644
index 0000000000..be7e76c5ab
--- /dev/null
+++ b/src/arch/arm/include/armv7/arch/types.h
@@ -0,0 +1,46 @@
+#ifndef __ASM_ARM_TYPES_H
+#define __ASM_ARM_TYPES_H
+
+typedef unsigned short umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+#if defined(__GNUC__)
+__extension__ typedef __signed__ long long __s64;
+__extension__ typedef unsigned long long __u64;
+#endif
+
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+#define BITS_PER_LONG 32
+
+/* Dma addresses are 32-bits wide. */
+
+typedef u32 dma_addr_t;
+
+typedef unsigned long phys_addr_t;
+typedef unsigned long phys_size_t;
+
+#endif
diff --git a/src/arch/arm/include/assembler.h b/src/arch/arm/include/assembler.h
new file mode 100644
index 0000000000..10363c4e4e
--- /dev/null
+++ b/src/arch/arm/include/assembler.h
@@ -0,0 +1,62 @@
+/*
+ * arch/arm/include/asm/assembler.h
+ *
+ * Copyright (C) 1996-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains arm architecture specific defines
+ * for the different processors.
+ *
+ * Do not include any C declarations in this file - it is included by
+ * assembler source.
+ */
+
+/*
+ * Endian independent macros for shifting bytes within registers.
+ */
+#ifndef __ARMEB__
+#define pull lsr
+#define push lsl
+#define get_byte_0 lsl #0
+#define get_byte_1 lsr #8
+#define get_byte_2 lsr #16
+#define get_byte_3 lsr #24
+#define put_byte_0 lsl #0
+#define put_byte_1 lsl #8
+#define put_byte_2 lsl #16
+#define put_byte_3 lsl #24
+#else
+#define pull lsl
+#define push lsr
+#define get_byte_0 lsr #24
+#define get_byte_1 lsr #16
+#define get_byte_2 lsr #8
+#define get_byte_3 lsl #0
+#define put_byte_0 lsl #24
+#define put_byte_1 lsl #16
+#define put_byte_2 lsl #8
+#define put_byte_3 lsl #0
+#endif
+
+/*
+ * Data preload for architectures that support it
+ */
+#if defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) || \
+ defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
+ defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || \
+ defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_7A__) || \
+ defined(__ARM_ARCH_7R__)
+#define PLD(code...) code
+#else
+#define PLD(code...)
+#endif
+
+/*
+ * Cache aligned
+ */
+#define CALGN(code...) code
+
+#define W(instr) instr
diff --git a/src/arch/arm/include/bootblock_common.h b/src/arch/arm/include/bootblock_common.h
new file mode 100644
index 0000000000..034a12bc36
--- /dev/null
+++ b/src/arch/arm/include/bootblock_common.h
@@ -0,0 +1,15 @@
+#if CONFIG_CPU_HAS_BOOTBLOCK_INIT
+void bootblock_cpu_init(void);
+#else
+static void __attribute__((unused)) bootblock_cpu_init(void)
+{
+}
+#endif
+
+#if CONFIG_MAINBOARD_HAS_BOOTBLOCK_INIT
+void bootblock_mainboard_init(void);
+#else
+static void __attribute__((unused)) bootblock_mainboard_init(void)
+{
+}
+#endif
diff --git a/src/arch/arm/include/clocks.h b/src/arch/arm/include/clocks.h
new file mode 100644
index 0000000000..58cf838621
--- /dev/null
+++ b/src/arch/arm/include/clocks.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * 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
+ */
+
+/* Standard clock speeds */
+
+/*
+ * We define some commonly-used clock speeds to avoid error since long
+ * numbers are hard to read.
+ *
+ * The format of the label is
+ * CLK_x_yU where:
+ * x is the integer speed
+ * y is the fractional part which can be omitted if 0
+ * U is the units (blank for Hz, K or M for KHz and MHz)
+ *
+ * Please order the items by increasing Hz
+ */
+enum {
+ CLK_32768 = 32768,
+ CLK_20M = 20000000,
+ CLK_24M = 24000000,
+ CLK_144M = 144000000,
+ CLK_216M = 216000000,
+ CLK_300M = 300000000,
+};
diff --git a/src/arch/arm/include/smp/spinlock.h b/src/arch/arm/include/smp/spinlock.h
new file mode 100644
index 0000000000..1dc397c19c
--- /dev/null
+++ b/src/arch/arm/include/smp/spinlock.h
@@ -0,0 +1,52 @@
+#ifndef ARCH_SMP_SPINLOCK_H
+#define ARCH_SMP_SPINLOCK_H
+
+/* FIXME: implement this for ARM */
+#error "implement this for ARM"
+#if 0
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+typedef struct {
+ volatile unsigned int lock;
+} spinlock_t;
+
+
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
+#define DECLARE_SPIN_LOCK(x) static spinlock_t x = SPIN_LOCK_UNLOCKED;
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) != 0)
+#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
+
+static inline __attribute__((always_inline)) void spin_lock(spinlock_t *lock)
+{
+ unsigned long tmp;
+ __asm__ __volatile__ (
+ "1: ldrex %0, [%1]\n"
+ " teq %0, #0\n"
+ " strexeq %0, %2, [%1]\n"
+ " teqeq %0, #0\n"
+ " bne 1b\n"
+ : "=&r" (tmp)
+ : "r" (&lock->lock), "r" (1)
+ : "cc"
+ );
+ barrier();
+}
+
+static inline __attribute__((always_inline)) void spin_unlock(spinlock_t *lock)
+{
+ __asm__ __volatile__(
+ " str %1, [%0]\n"
+ :
+ : "r" (&lock->lock), "r" (0)
+ : "cc"
+ );
+}
+
+#define cpu_relax() barrier()
+
+#endif
+#endif /* ARCH_SMP_SPINLOCK_H */
diff --git a/src/arch/arm/include/stdint.h b/src/arch/arm/include/stdint.h
new file mode 100644
index 0000000000..9d41e6359a
--- /dev/null
+++ b/src/arch/arm/include/stdint.h
@@ -0,0 +1,93 @@
+#ifndef ARM_STDINT_H
+#define ARM_STDINT_H
+
+#if defined(__GNUC__)
+#define __HAVE_LONG_LONG__ 1
+#else
+#define __HAVE_LONG_LONG__ 0
+#endif
+
+/* Exact integral types */
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+
+#if __HAVE_LONG_LONG__
+typedef unsigned long long uint64_t;
+typedef signed long long int64_t;
+#endif
+
+/* Small types */
+typedef unsigned char uint_least8_t;
+typedef signed char int_least8_t;
+
+typedef unsigned short uint_least16_t;
+typedef signed short int_least16_t;
+
+typedef unsigned int uint_least32_t;
+typedef signed int int_least32_t;
+
+#if __HAVE_LONG_LONG__
+typedef unsigned long long uint_least64_t;
+typedef signed long long int_least64_t;
+#endif
+
+/* Fast Types */
+typedef unsigned char uint_fast8_t;
+typedef signed char int_fast8_t;
+
+typedef unsigned int uint_fast16_t;
+typedef signed int int_fast16_t;
+
+typedef unsigned int uint_fast32_t;
+typedef signed int int_fast32_t;
+
+#if __HAVE_LONG_LONG__
+typedef unsigned long long uint_fast64_t;
+typedef signed long long int_fast64_t;
+#endif
+
+/* Types for `void *' pointers. */
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+
+/* Largest integral types */
+#if __HAVE_LONG_LONG__
+typedef long long int intmax_t;
+typedef unsigned long long uintmax_t;
+#else
+typedef long int intmax_t;
+typedef unsigned long int uintmax_t;
+#endif
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+#if __HAVE_LONG_LONG__
+typedef uint64_t u64;
+#endif
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+#ifndef UINT64_MAX
+# define UINT64_MAX (18446744073709551615ULL)
+#endif
+#ifndef UINT64_C
+#define UINT64_C(c) c ## ULL
+#endif
+#ifndef PRIu64
+#define PRIu64 "llu"
+#endif
+
+#undef __HAVE_LONG_LONG__
+
+#endif /* ARM_STDINT_H */
diff --git a/src/arch/arm/include/utils.h b/src/arch/arm/include/utils.h
new file mode 100644
index 0000000000..828b86cb36
--- /dev/null
+++ b/src/arch/arm/include/utils.h
@@ -0,0 +1,56 @@
+/*
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ * Aneesh V <aneesh@ti.com>
+ *
+ * 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
+ */
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+static inline s32 log_2_n_round_up(u32 n)
+{
+ s32 log2n = -1;
+ u32 temp = n;
+
+ while (temp) {
+ log2n++;
+ temp >>= 1;
+ }
+
+ if (n & (n - 1))
+ return log2n + 1; /* not power of 2 - round up */
+ else
+ return log2n; /* power of 2 */
+}
+
+static inline s32 log_2_n_round_down(u32 n)
+{
+ s32 log2n = -1;
+ u32 temp = n;
+
+ while (temp) {
+ log2n++;
+ temp >>= 1;
+ }
+
+ return log2n;
+}
+
+#endif
diff --git a/src/arch/arm/memcpy.S b/src/arch/arm/memcpy.S
new file mode 100644
index 0000000000..921fc2a6bc
--- /dev/null
+++ b/src/arch/arm/memcpy.S
@@ -0,0 +1,244 @@
+/*
+ * linux/arch/arm/lib/memcpy.S
+ *
+ * Author: Nicolas Pitre
+ * Created: Sep 28, 2005
+ * Copyright: MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <assembler.h>
+
+#define W(instr) instr
+
+#define LDR1W_SHIFT 0
+#define STR1W_SHIFT 0
+
+ .macro ldr1w ptr reg abort
+ W(ldr) \reg, [\ptr], #4
+ .endm
+
+ .macro ldr4w ptr reg1 reg2 reg3 reg4 abort
+ ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
+ .endm
+
+ .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+ .endm
+
+ .macro ldr1b ptr reg cond=al abort
+ ldr\cond\()b \reg, [\ptr], #1
+ .endm
+
+ .macro str1w ptr reg abort
+ W(str) \reg, [\ptr], #4
+ .endm
+
+ .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+ .endm
+
+ .macro str1b ptr reg cond=al abort
+ str\cond\()b \reg, [\ptr], #1
+ .endm
+
+ .macro enter reg1 reg2
+ stmdb sp!, {r0, \reg1, \reg2}
+ .endm
+
+ .macro exit reg1 reg2
+ ldmfd sp!, {r0, \reg1, \reg2}
+ .endm
+
+ .text
+
+/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
+
+.type memcpy, function
+.globl memcpy
+memcpy:
+
+ cmp r0, r1
+ moveq pc, lr
+
+ enter r4, lr
+
+ subs r2, r2, #4
+ blt 8f
+ ands ip, r0, #3
+ PLD( pld [r1, #0] )
+ bne 9f
+ ands ip, r1, #3
+ bne 10f
+
+1: subs r2, r2, #(28)
+ stmfd sp!, {r5 - r8}
+ blt 5f
+
+ CALGN( ands ip, r0, #31 )
+ CALGN( rsb r3, ip, #32 )
+ CALGN( sbcnes r4, r3, r2 ) @ C is always set here
+ CALGN( bcs 2f )
+ CALGN( adr r4, 6f )
+ CALGN( subs r2, r2, r3 ) @ C gets set
+ CALGN( add pc, r4, ip )
+
+ PLD( pld [r1, #0] )
+2: PLD( subs r2, r2, #96 )
+ PLD( pld [r1, #28] )
+ PLD( blt 4f )
+ PLD( pld [r1, #60] )
+ PLD( pld [r1, #92] )
+
+3: PLD( pld [r1, #124] )
+4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
+ subs r2, r2, #32
+ str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
+ bge 3b
+ PLD( cmn r2, #96 )
+ PLD( bge 4b )
+
+5: ands ip, r2, #28
+ rsb ip, ip, #32
+#if LDR1W_SHIFT > 0
+ lsl ip, ip, #LDR1W_SHIFT
+#endif
+ addne pc, pc, ip @ C is always clear here
+ b 7f
+6:
+ .rept (1 << LDR1W_SHIFT)
+ W(nop)
+ .endr
+ ldr1w r1, r3, abort=20f
+ ldr1w r1, r4, abort=20f
+ ldr1w r1, r5, abort=20f
+ ldr1w r1, r6, abort=20f
+ ldr1w r1, r7, abort=20f
+ ldr1w r1, r8, abort=20f
+ ldr1w r1, lr, abort=20f
+
+#if LDR1W_SHIFT < STR1W_SHIFT
+ lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT
+#elif LDR1W_SHIFT > STR1W_SHIFT
+ lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT
+#endif
+ add pc, pc, ip
+ nop
+ .rept (1 << STR1W_SHIFT)
+ W(nop)
+ .endr
+ str1w r0, r3, abort=20f
+ str1w r0, r4, abort=20f
+ str1w r0, r5, abort=20f
+ str1w r0, r6, abort=20f
+ str1w r0, r7, abort=20f
+ str1w r0, r8, abort=20f
+ str1w r0, lr, abort=20f
+
+ CALGN( bcs 2b )
+
+7: ldmfd sp!, {r5 - r8}
+
+8: movs r2, r2, lsl #31
+ ldr1b r1, r3, ne, abort=21f
+ ldr1b r1, r4, cs, abort=21f
+ ldr1b r1, ip, cs, abort=21f
+ str1b r0, r3, ne, abort=21f
+ str1b r0, r4, cs, abort=21f
+ str1b r0, ip, cs, abort=21f
+
+ exit r4, pc
+
+9: rsb ip, ip, #4
+ cmp ip, #2
+ ldr1b r1, r3, gt, abort=21f
+ ldr1b r1, r4, ge, abort=21f
+ ldr1b r1, lr, abort=21f
+ str1b r0, r3, gt, abort=21f
+ str1b r0, r4, ge, abort=21f
+ subs r2, r2, ip
+ str1b r0, lr, abort=21f
+ blt 8b
+ ands ip, r1, #3
+ beq 1b
+
+10: bic r1, r1, #3
+ cmp ip, #2
+ ldr1w r1, lr, abort=21f
+ beq 17f
+ bgt 18f
+
+
+ .macro forward_copy_shift pull push
+
+ subs r2, r2, #28
+ blt 14f
+
+ CALGN( ands ip, r0, #31 )
+ CALGN( rsb ip, ip, #32 )
+ CALGN( sbcnes r4, ip, r2 ) @ C is always set here
+ CALGN( subcc r2, r2, ip )
+ CALGN( bcc 15f )
+
+11: stmfd sp!, {r5 - r9}
+
+ PLD( pld [r1, #0] )
+ PLD( subs r2, r2, #96 )
+ PLD( pld [r1, #28] )
+ PLD( blt 13f )
+ PLD( pld [r1, #60] )
+ PLD( pld [r1, #92] )
+
+12: PLD( pld [r1, #124] )
+13: ldr4w r1, r4, r5, r6, r7, abort=19f
+ mov r3, lr, pull #\pull
+ subs r2, r2, #32
+ ldr4w r1, r8, r9, ip, lr, abort=19f
+ orr r3, r3, r4, push #\push
+ mov r4, r4, pull #\pull
+ orr r4, r4, r5, push #\push
+ mov r5, r5, pull #\pull
+ orr r5, r5, r6, push #\push
+ mov r6, r6, pull #\pull
+ orr r6, r6, r7, push #\push
+ mov r7, r7, pull #\pull
+ orr r7, r7, r8, push #\push
+ mov r8, r8, pull #\pull
+ orr r8, r8, r9, push #\push
+ mov r9, r9, pull #\pull
+ orr r9, r9, ip, push #\push
+ mov ip, ip, pull #\pull
+ orr ip, ip, lr, push #\push
+ str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f
+ bge 12b
+ PLD( cmn r2, #96 )
+ PLD( bge 13b )
+
+ ldmfd sp!, {r5 - r9}
+
+14: ands ip, r2, #28
+ beq 16f
+
+15: mov r3, lr, pull #\pull
+ ldr1w r1, lr, abort=21f
+ subs ip, ip, #4
+ orr r3, r3, lr, push #\push
+ str1w r0, r3, abort=21f
+ bgt 15b
+ CALGN( cmp r2, #0 )
+ CALGN( bge 11b )
+
+16: sub r1, r1, #(\push / 8)
+ b 8b
+
+ .endm
+
+
+ forward_copy_shift pull=8 push=24
+
+17: forward_copy_shift pull=16 push=16
+
+18: forward_copy_shift pull=24 push=8
diff --git a/src/arch/arm/memmove.S b/src/arch/arm/memmove.S
new file mode 100644
index 0000000000..a2f9ea18ae
--- /dev/null
+++ b/src/arch/arm/memmove.S
@@ -0,0 +1,197 @@
+/*
+ * linux/arch/arm/lib/memmove.S
+ *
+ * Author: Nicolas Pitre
+ * Created: Sep 28, 2005
+ * Copyright: (C) MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <assembler.h>
+
+ .text
+
+/*
+ * Prototype: void *memmove(void *dest, const void *src, size_t n);
+ *
+ * Note:
+ *
+ * If the memory regions don't overlap, we simply branch to memcpy which is
+ * normally a bit faster. Otherwise the copy is done going downwards. This
+ * is a transposition of the code from copy_template.S but with the copy
+ * occurring in the opposite direction.
+ */
+
+.type memmove, function
+.globl memmove
+memmove:
+ subs ip, r0, r1
+ cmphi r2, ip
+ bls memcpy
+
+ stmfd sp!, {r0, r4, lr}
+ add r1, r1, r2
+ add r0, r0, r2
+ subs r2, r2, #4
+ blt 8f
+ ands ip, r0, #3
+ PLD( pld [r1, #-4] )
+ bne 9f
+ ands ip, r1, #3
+ bne 10f
+
+1: subs r2, r2, #(28)
+ stmfd sp!, {r5 - r8}
+ blt 5f
+
+ CALGN( ands ip, r0, #31 )
+ CALGN( sbcnes r4, ip, r2 ) @ C is always set here
+ CALGN( bcs 2f )
+ CALGN( adr r4, 6f )
+ CALGN( subs r2, r2, ip ) @ C is set here
+ CALGN( rsb ip, ip, #32 )
+ CALGN( add pc, r4, ip )
+
+ PLD( pld [r1, #-4] )
+2: PLD( subs r2, r2, #96 )
+ PLD( pld [r1, #-32] )
+ PLD( blt 4f )
+ PLD( pld [r1, #-64] )
+ PLD( pld [r1, #-96] )
+
+3: PLD( pld [r1, #-128] )
+4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
+ subs r2, r2, #32
+ stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
+ bge 3b
+ PLD( cmn r2, #96 )
+ PLD( bge 4b )
+
+5: ands ip, r2, #28
+ rsb ip, ip, #32
+ addne pc, pc, ip @ C is always clear here
+ b 7f
+6: W(nop)
+ W(ldr) r3, [r1, #-4]!
+ W(ldr) r4, [r1, #-4]!
+ W(ldr) r5, [r1, #-4]!
+ W(ldr) r6, [r1, #-4]!
+ W(ldr) r7, [r1, #-4]!
+ W(ldr) r8, [r1, #-4]!
+ W(ldr) lr, [r1, #-4]!
+
+ add pc, pc, ip
+ nop
+ W(nop)
+ W(str) r3, [r0, #-4]!
+ W(str) r4, [r0, #-4]!
+ W(str) r5, [r0, #-4]!
+ W(str) r6, [r0, #-4]!
+ W(str) r7, [r0, #-4]!
+ W(str) r8, [r0, #-4]!
+ W(str) lr, [r0, #-4]!
+
+ CALGN( bcs 2b )
+
+7: ldmfd sp!, {r5 - r8}
+
+8: movs r2, r2, lsl #31
+ ldrneb r3, [r1, #-1]!
+ ldrcsb r4, [r1, #-1]!
+ ldrcsb ip, [r1, #-1]
+ strneb r3, [r0, #-1]!
+ strcsb r4, [r0, #-1]!
+ strcsb ip, [r0, #-1]
+ ldmfd sp!, {r0, r4, pc}
+
+9: cmp ip, #2
+ ldrgtb r3, [r1, #-1]!
+ ldrgeb r4, [r1, #-1]!
+ ldrb lr, [r1, #-1]!
+ strgtb r3, [r0, #-1]!
+ strgeb r4, [r0, #-1]!
+ subs r2, r2, ip
+ strb lr, [r0, #-1]!
+ blt 8b
+ ands ip, r1, #3
+ beq 1b
+
+10: bic r1, r1, #3
+ cmp ip, #2
+ ldr r3, [r1, #0]
+ beq 17f
+ blt 18f
+
+
+ .macro backward_copy_shift push pull
+
+ subs r2, r2, #28
+ blt 14f
+
+ CALGN( ands ip, r0, #31 )
+ CALGN( sbcnes r4, ip, r2 ) @ C is always set here
+ CALGN( subcc r2, r2, ip )
+ CALGN( bcc 15f )
+
+11: stmfd sp!, {r5 - r9}
+
+ PLD( pld [r1, #-4] )
+ PLD( subs r2, r2, #96 )
+ PLD( pld [r1, #-32] )
+ PLD( blt 13f )
+ PLD( pld [r1, #-64] )
+ PLD( pld [r1, #-96] )
+
+12: PLD( pld [r1, #-128] )
+13: ldmdb r1!, {r7, r8, r9, ip}
+ mov lr, r3, push #\push
+ subs r2, r2, #32
+ ldmdb r1!, {r3, r4, r5, r6}
+ orr lr, lr, ip, pull #\pull
+ mov ip, ip, push #\push
+ orr ip, ip, r9, pull #\pull
+ mov r9, r9, push #\push
+ orr r9, r9, r8, pull #\pull
+ mov r8, r8, push #\push
+ orr r8, r8, r7, pull #\pull
+ mov r7, r7, push #\push
+ orr r7, r7, r6, pull #\pull
+ mov r6, r6, push #\push
+ orr r6, r6, r5, pull #\pull
+ mov r5, r5, push #\push
+ orr r5, r5, r4, pull #\pull
+ mov r4, r4, push #\push
+ orr r4, r4, r3, pull #\pull
+ stmdb r0!, {r4 - r9, ip, lr}
+ bge 12b
+ PLD( cmn r2, #96 )
+ PLD( bge 13b )
+
+ ldmfd sp!, {r5 - r9}
+
+14: ands ip, r2, #28
+ beq 16f
+
+15: mov lr, r3, push #\push
+ ldr r3, [r1, #-4]!
+ subs ip, ip, #4
+ orr lr, lr, r3, pull #\pull
+ str lr, [r0, #-4]!
+ bgt 15b
+ CALGN( cmp r2, #0 )
+ CALGN( bge 11b )
+
+16: add r1, r1, #(\pull / 8)
+ b 8b
+
+ .endm
+
+
+ backward_copy_shift push=8 pull=24
+
+17: backward_copy_shift push=16 pull=16
+
+18: backward_copy_shift push=24 pull=8
diff --git a/src/arch/arm/memset.S b/src/arch/arm/memset.S
new file mode 100644
index 0000000000..a3cc9477f8
--- /dev/null
+++ b/src/arch/arm/memset.S
@@ -0,0 +1,127 @@
+/*
+ * linux/arch/arm/lib/memset.S
+ *
+ * Copyright (C) 1995-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ASM optimised string functions
+ */
+#include <assembler.h>
+
+ .text
+ .align 5
+ .word 0
+
+1: subs r2, r2, #4 @ 1 do we have enough
+ blt 5f @ 1 bytes to align with?
+ cmp r3, #2 @ 1
+ strltb r1, [r0], #1 @ 1
+ strleb r1, [r0], #1 @ 1
+ strb r1, [r0], #1 @ 1
+ add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
+/*
+ * The pointer is now aligned and the length is adjusted. Try doing the
+ * memset again.
+ */
+
+.type memset, function
+.globl memset
+memset:
+ ands r3, r0, #3 @ 1 unaligned?
+ bne 1b @ 1
+/*
+ * we know that the pointer in r0 is aligned to a word boundary.
+ */
+ orr r1, r1, r1, lsl #8
+ orr r1, r1, r1, lsl #16
+ mov r3, r1
+ cmp r2, #16
+ blt 4f
+
+#if ! CALGN(1)+0
+
+/*
+ * We need an extra register for this loop - save the return address and
+ * use the LR
+ */
+ str lr, [sp, #-4]!
+ mov ip, r1
+ mov lr, r1
+
+2: subs r2, r2, #64
+ stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time.
+ stmgeia r0!, {r1, r3, ip, lr}
+ stmgeia r0!, {r1, r3, ip, lr}
+ stmgeia r0!, {r1, r3, ip, lr}
+ bgt 2b
+ ldmeqfd sp!, {pc} @ Now <64 bytes to go.
+/*
+ * No need to correct the count; we're only testing bits from now on
+ */
+ tst r2, #32
+ stmneia r0!, {r1, r3, ip, lr}
+ stmneia r0!, {r1, r3, ip, lr}
+ tst r2, #16
+ stmneia r0!, {r1, r3, ip, lr}
+ ldr lr, [sp], #4
+
+#else
+
+/*
+ * This version aligns the destination pointer in order to write
+ * whole cache lines at once.
+ */
+
+ stmfd sp!, {r4-r7, lr}
+ mov r4, r1
+ mov r5, r1
+ mov r6, r1
+ mov r7, r1
+ mov ip, r1
+ mov lr, r1
+
+ cmp r2, #96
+ tstgt r0, #31
+ ble 3f
+
+ and ip, r0, #31
+ rsb ip, ip, #32
+ sub r2, r2, ip
+ movs ip, ip, lsl #(32 - 4)
+ stmcsia r0!, {r4, r5, r6, r7}
+ stmmiia r0!, {r4, r5}
+ tst ip, #(1 << 30)
+ mov ip, r1
+ strne r1, [r0], #4
+
+3: subs r2, r2, #64
+ stmgeia r0!, {r1, r3-r7, ip, lr}
+ stmgeia r0!, {r1, r3-r7, ip, lr}
+ bgt 3b
+ ldmeqfd sp!, {r4-r7, pc}
+
+ tst r2, #32
+ stmneia r0!, {r1, r3-r7, ip, lr}
+ tst r2, #16
+ stmneia r0!, {r4-r7}
+ ldmfd sp!, {r4-r7, lr}
+
+#endif
+
+4: tst r2, #8
+ stmneia r0!, {r1, r3}
+ tst r2, #4
+ strne r1, [r0], #4
+/*
+ * When we get here, we've got less than 4 bytes to zero. We
+ * may have an unaligned pointer as well.
+ */
+5: tst r2, #2
+ strneb r1, [r0], #1
+ strneb r1, [r0], #1
+ tst r2, #1
+ strneb r1, [r0], #1
+ mov pc, lr
diff --git a/src/arch/arm/ramstage.ld b/src/arch/arm/ramstage.ld
new file mode 100644
index 0000000000..cab512e99d
--- /dev/null
+++ b/src/arch/arm/ramstage.ld
@@ -0,0 +1,134 @@
+/*
+ * Memory map:
+ *
+ * CONFIG_RAMSTAGE_BASE : text segment
+ * : rodata segment
+ * : data segment
+ * : bss segment
+ * : stack
+ * : heap
+ */
+/*
+ * Bootstrap code for the STPC Consumer
+ * Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
+ */
+
+/*
+ * Written by Johan Rydberg, based on work by Daniel Kahlin.
+ * Rewritten by Eric Biederman
+ * 2005.12 yhlu add ramstage cross the vga font buffer handling
+ */
+
+/* We use ELF as output format. So that we can debug the code in some form. */
+INCLUDE ldoptions
+
+ENTRY(stage_entry)
+
+PHDRS
+{
+ to_load PT_LOAD;
+}
+
+SECTIONS
+{
+ . = CONFIG_RAMSTAGE_BASE;
+ /* First we place the code and read only data (typically const declared).
+ * This could theoretically be placed in rom.
+ */
+ .text : {
+ _text = .;
+ _start = .;
+ *(.text.stage_entry.arm);
+ *(.text);
+ *(.text.*);
+ . = ALIGN(16);
+ _etext = .;
+ } : to_load
+
+ .ctors : {
+ . = ALIGN(0x100);
+ __CTOR_LIST__ = .;
+ *(.ctors);
+ LONG(0);
+ __CTOR_END__ = .;
+ }
+
+ .rodata : {
+ _rodata = .;
+ . = ALIGN(4);
+ pci_drivers = . ;
+ *(.rodata.pci_driver)
+ epci_drivers = . ;
+ cpu_drivers = . ;
+ *(.rodata.cpu_driver)
+ ecpu_drivers = . ;
+ _bs_init_begin = .;
+ *(.bs_init)
+ _bs_init_end = .;
+ *(.rodata)
+ *(.rodata.*)
+ /* kevinh/Ispiri - Added an align, because the objcopy tool
+ * incorrectly converts sections that are not long word aligned.
+ */
+ . = ALIGN(4);
+
+ _erodata = .;
+ }
+ /* After the code we place initialized data (typically initialized
+ * global variables). This gets copied into ram by startup code.
+ * __data_start and __data_end shows where in ram this should be placed,
+ * whereas __data_loadstart and __data_loadend shows where in rom to
+ * copy from.
+ */
+ .data : {
+ _data = .;
+ *(.data)
+ _edata = .;
+ }
+
+ /* bss does not contain data, it is just a space that should be zero
+ * initialized on startup. (typically uninitialized global variables)
+ * crt0.S fills between _bss and _ebss with zeroes.
+ */
+ _bss = .;
+ .bss . : {
+ *(.bss)
+ *(.sbss)
+ *(COMMON)
+ }
+ _ebss = .;
+ _end = .;
+
+ /* coreboot really "ends" here. Only heap and stack are placed after
+ * this line.
+ */
+
+ _heap = .;
+ .heap . : {
+ /* Reserve CONFIG_HEAP_SIZE bytes for the heap */
+ . = CONFIG_HEAP_SIZE ;
+ . = ALIGN(4);
+ }
+ _eheap = .;
+
+ /* The ram segment. This includes all memory used by the memory
+ * resident copy of coreboot, except the tables that are produced on
+ * the fly, but including stack and heap.
+ */
+ _ram_seg = _text;
+ _eram_seg = _eheap;
+
+ /* The stack lives in SRAM in a different location, so keep
+ * it out of ram_seg
+ */
+ _stack = CONFIG_STACK_BOTTOM;
+ _estack = CONFIG_STACK_TOP;
+
+ /* Discard the sections we don't need/want */
+
+ /DISCARD/ : {
+ *(.comment)
+ *(.note)
+ *(.note.*)
+ }
+}
diff --git a/src/arch/arm/romstage.ld b/src/arch/arm/romstage.ld
new file mode 100644
index 0000000000..65b133ad2c
--- /dev/null
+++ b/src/arch/arm/romstage.ld
@@ -0,0 +1,109 @@
+/*
+ * Memory map:
+ *
+ * CONFIG_ROMSTAGE_BASE : text segment
+ * : rodata segment
+ * : data segment
+ * : bss segment
+ * : stack
+ * : heap
+ */
+/*
+ * Bootstrap code for the STPC Consumer
+ * Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
+ */
+
+/*
+ * Written by Johan Rydberg, based on work by Daniel Kahlin.
+ * Rewritten by Eric Biederman
+ * 2005.12 yhlu add ramstage cross the vga font buffer handling
+ */
+
+/* We use ELF as output format. So that we can debug the code in some form. */
+
+/* We use ELF as output format. So that we can debug the code in some form. */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+INCLUDE ldoptions
+
+ENTRY(stage_entry)
+
+PHDRS
+{
+ to_load PT_LOAD;
+}
+
+SECTIONS
+{
+ /* TODO make this a configurable option (per chipset). */
+ . = CONFIG_ROMSTAGE_BASE;
+
+ .romtext . : {
+ _rom = .;
+ _start = .;
+ *(.text.stage_entry.arm);
+ *(.text.startup);
+ *(.text);
+ } : to_load
+
+ .romdata . : {
+ *(.rodata);
+ *(.machine_param);
+ *(.data);
+ . = ALIGN(16);
+ _car_migrate_start = .;
+ *(.car.migrate);
+ _car_migrate_end = .;
+ . = ALIGN(16);
+ _erom = .;
+ }
+
+ /* bss does not contain data, it is just a space that should be zero
+ * initialized on startup. (typically uninitialized global variables)
+ * crt0.S fills between _bss and _ebss with zeroes.
+ */
+ .bss . : {
+ . = ALIGN(8);
+ _bss = .;
+ *(.bss)
+ *(.sbss)
+ *(COMMON)
+ }
+
+ _ebss = .;
+
+ .car.data . : {
+ . = ALIGN(8);
+ _car_data_start = .;
+ *(.car.global_data);
+ . = ALIGN(8);
+ /* The cbmem_console section comes last to take advantage of
+ * a zero-sized array to hold the memconsole contents that
+ * grows to a bound of CONFIG_CONSOLE_CAR_BUFFER_SIZE. However,
+ * collisions within the cache-as-ram region cannot be
+ * statically checked because the cache-as-ram region usage is
+ * cpu/chipset dependent. */
+ *(.car.cbmem_console);
+ _car_data_end = .;
+ }
+
+ _end = .;
+
+ /* TODO: check if we are running out of SRAM. Below check is not good
+ * enough though because SRAM has different size on different CPUs
+ * and not all SRAM is available to the romstage. On Exynos, some is
+ * used for BL1, the bootblock and the stack.
+ *
+ * _bogus = ASSERT((_end - _start + EXPECTED_CBMEM_CONSOLE_SIZE <= \
+ * 0x54000), "SRAM area is too full");
+ */
+
+ /* Discard the sections we don't need/want */
+ /DISCARD/ : {
+ *(.comment)
+ *(.note)
+ *(.comment.*)
+ *(.note.*)
+ *(.eh_frame);
+ }
+}
diff --git a/src/arch/arm/stages.c b/src/arch/arm/stages.c
new file mode 100644
index 0000000000..38d1b1928a
--- /dev/null
+++ b/src/arch/arm/stages.c
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2012 Google Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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
+ */
+
+/*
+ * This file contains entry/exit functions for each stage during coreboot
+ * execution (bootblock entry and ramstage exit will depend on external
+ * loading.
+ *
+ * Unlike other files, this one should be compiled with a -m option to
+ * specify a pre-determined instruction set. This is to ensure consistency
+ * in the CPU operating mode (ARM or Thumb) when hand-off between stages
+ * occurs.
+ *
+ * Entry points must be placed at the location the previous stage jumps
+ * to (the lowest address in the stage image). This is done by giving
+ * stage_entry() its own section in .text and placing it first in the
+ * linker script.
+ */
+
+#include <arch/stages.h>
+#include <arch/cache.h>
+
+void stage_entry(void)
+{
+ main();
+}
+
+/* we had marked 'doit' as 'noreturn'.
+ * There is no apparent harm in leaving it as something we can return from, and in the one
+ * case where we call a payload, the payload is allowed to return.
+ * Hence, leave it as something we can return from.
+ */
+void stage_exit(void *addr)
+{
+ void (*doit)(void) = addr;
+ /* make sure any code we installed is written to memory. Not all ARM have
+ * unified caches.
+ */
+ dcache_clean_all();
+ /* Because most stages copy code to memory, it's a safe and hygienic thing
+ * to flush the icache here.
+ */
+ icache_invalidate_all();
+ doit();
+}
diff --git a/src/arch/arm/tables.c b/src/arch/arm/tables.c
new file mode 100644
index 0000000000..20c5a9f7a8
--- /dev/null
+++ b/src/arch/arm/tables.c
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2003 Eric Biederman
+ * Copyright (C) 2005 Steve Magnani
+ * Copyright (C) 2008-2009 coresystems GmbH
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 <console/console.h>
+#include <cpu/cpu.h>
+#include <boot/tables.h>
+#include <boot/coreboot_tables.h>
+#include <string.h>
+#include <cbmem.h>
+#include <lib.h>
+
+#define MAX_COREBOOT_TABLE_SIZE (8 * 1024)
+
+#if !CONFIG_DYNAMIC_CBMEM
+void __attribute__((weak)) get_cbmem_table(uint64_t *base, uint64_t *size)
+{
+ printk(BIOS_WARNING, "WARNING: you need to define get_cbmem_table for your board\n");
+ *base = 0;
+ *size = 0;
+}
+#endif
+
+void cbmem_arch_init(void)
+{
+}
+
+void cbmem_fail_resume(void)
+{
+}
+
+void write_tables(void)
+{
+ unsigned long table_pointer, new_table_pointer;
+
+ post_code(0x9d);
+
+ table_pointer = (unsigned long)cbmem_add(CBMEM_ID_CBTABLE,
+ MAX_COREBOOT_TABLE_SIZE);
+ if (!table_pointer) {
+ printk(BIOS_ERR, "Could not add CBMEM for coreboot table.\n");
+ return;
+ }
+
+ new_table_pointer = write_coreboot_table(0UL, 0UL,
+ table_pointer, table_pointer);
+
+ if (new_table_pointer > (table_pointer + MAX_COREBOOT_TABLE_SIZE)) {
+ printk(BIOS_ERR, "coreboot table didn't fit (%lx/%x bytes)\n",
+ new_table_pointer - table_pointer, MAX_COREBOOT_TABLE_SIZE);
+ }
+
+ printk(BIOS_DEBUG, "coreboot table: %ld bytes.\n",
+ new_table_pointer - table_pointer);
+
+ post_code(0x9e);
+
+ /* Print CBMEM sections */
+ cbmem_list();
+}