]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
ARM: Add ARMv7-M support
authorrev13@wp.pl <rev13@wp.pl>
Sun, 1 Mar 2015 11:44:39 +0000 (12:44 +0100)
committerLothar Waßmann <LW@KARO-electronics.de>
Tue, 8 Sep 2015 20:30:06 +0000 (22:30 +0200)
Signed-off-by: Kamil Lulko <rev13@wp.pl>
arch/arm/Kconfig
arch/arm/cpu/armv7m/Makefile [new file with mode: 0644]
arch/arm/cpu/armv7m/config.mk [new file with mode: 0644]
arch/arm/cpu/armv7m/cpu.c [new file with mode: 0644]
arch/arm/cpu/armv7m/start.S [new file with mode: 0644]
arch/arm/include/asm/armv7m.h [new file with mode: 0644]
arch/arm/lib/Makefile
arch/arm/lib/crt0.S
arch/arm/lib/interrupts_m.c [new file with mode: 0644]
arch/arm/lib/relocate.S
arch/arm/lib/vectors_m.S [new file with mode: 0644]

index b3039b96097b7d7bdd8ff48d09422482855c4d14..83764e345883a25c153457ef01e1fecb8b6a2cdd 100644 (file)
@@ -33,6 +33,9 @@ config CPU_V7
         bool
         select HAS_VBAR
 
+config CPU_V7M
+       bool
+
 config CPU_PXA
         bool
 
@@ -47,6 +50,7 @@ config SYS_CPU
         default "arm1136" if CPU_ARM1136
         default "arm1176" if CPU_ARM1176
         default "armv7" if CPU_V7
+        default "armv7m" if CPU_V7M
         default "pxa" if CPU_PXA
         default "sa1100" if CPU_SA1100
        default "armv8" if ARM64
diff --git a/arch/arm/cpu/armv7m/Makefile b/arch/arm/cpu/armv7m/Makefile
new file mode 100644 (file)
index 0000000..aff60e8
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+extra-y := start.o
+obj-y += cpu.o
diff --git a/arch/arm/cpu/armv7m/config.mk b/arch/arm/cpu/armv7m/config.mk
new file mode 100644 (file)
index 0000000..0b31e44
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2015
+# Kamil Lulko, <rev13@wp.pl>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+PLATFORM_CPPFLAGS += -march=armv7-m -mthumb
diff --git a/arch/arm/cpu/armv7m/cpu.c b/arch/arm/cpu/armv7m/cpu.c
new file mode 100644 (file)
index 0000000..d3ab862
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * (C) Copyright 2010,2011
+ * Vladimir Khusainov, Emcraft Systems, vlad@emcraft.com
+ *
+ * (C) Copyright 2015
+ * Kamil Lulko, <rev13@wp.pl>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/armv7m.h>
+
+/*
+ * This is called right before passing control to
+ * the Linux kernel point.
+ */
+int cleanup_before_linux(void)
+{
+       return 0;
+}
+
+/*
+ * Perform the low-level reset.
+ */
+void reset_cpu(ulong addr)
+{
+       /*
+        * Perform reset but keep priority group unchanged.
+        */
+       writel((V7M_AIRCR_VECTKEY << V7M_AIRCR_VECTKEY_SHIFT)
+               | (V7M_SCB->aircr & V7M_AIRCR_PRIGROUP_MSK)
+               | V7M_AIRCR_SYSRESET, &V7M_SCB->aircr);
+}
diff --git a/arch/arm/cpu/armv7m/start.S b/arch/arm/cpu/armv7m/start.S
new file mode 100644 (file)
index 0000000..e05e984
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2015
+ * Kamil Lulko, <rev13@wp.pl>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+.globl reset
+.type reset, %function
+reset:
+       b       _main
+
+.globl c_runtime_cpu_setup
+c_runtime_cpu_setup:
+       mov     pc, lr
diff --git a/arch/arm/include/asm/armv7m.h b/arch/arm/include/asm/armv7m.h
new file mode 100644 (file)
index 0000000..d2aa1c4
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright 2010,2011
+ * Vladimir Khusainov, Emcraft Systems, vlad@emcraft.com
+ *
+ * (C) Copyright 2015
+ * Kamil Lulko, <rev13@wp.pl>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef ARMV7M_H
+#define ARMV7M_H
+
+#if defined(__ASSEMBLY__)
+.syntax unified
+.thumb
+#endif
+
+#define V7M_SCB_BASE           0xE000ED00
+#define V7M_MPU_BASE           0xE000ED90
+
+#define V7M_SCB_VTOR           0x08
+
+#if !defined(__ASSEMBLY__)
+struct v7m_scb {
+       uint32_t cpuid;         /* CPUID Base Register */
+       uint32_t icsr;          /* Interrupt Control and State Register */
+       uint32_t vtor;          /* Vector Table Offset Register */
+       uint32_t aircr;         /* App Interrupt and Reset Control Register */
+};
+#define V7M_SCB                                ((struct v7m_scb *)V7M_SCB_BASE)
+
+#define V7M_AIRCR_VECTKEY              0x5fa
+#define V7M_AIRCR_VECTKEY_SHIFT                16
+#define V7M_AIRCR_ENDIAN               (1 << 15)
+#define V7M_AIRCR_PRIGROUP_SHIFT       8
+#define V7M_AIRCR_PRIGROUP_MSK         (0x7 << V7M_AIRCR_PRIGROUP_SHIFT)
+#define V7M_AIRCR_SYSRESET             (1 << 2)
+
+#define V7M_ICSR_VECTACT_MSK           0xFF
+
+struct v7m_mpu {
+       uint32_t type;          /* Type Register */
+       uint32_t ctrl;          /* Control Register */
+       uint32_t rnr;           /* Region Number Register */
+       uint32_t rbar;          /* Region Base Address Register */
+       uint32_t rasr;          /* Region Attribute and Size Register */
+};
+#define V7M_MPU                                ((struct v7m_mpu *)V7M_MPU_BASE)
+
+#define V7M_MPU_CTRL_ENABLE            (1 << 0)
+#define V7M_MPU_CTRL_HFNMIENA          (1 << 1)
+
+#define V7M_MPU_RASR_EN                        (1 << 0)
+#define V7M_MPU_RASR_SIZE_BITS         1
+#define V7M_MPU_RASR_SIZE_4GB          (31 << V7M_MPU_RASR_SIZE_BITS)
+#define V7M_MPU_RASR_AP_RW_RW          (3 << 24)
+
+#endif /* !defined(__ASSEMBLY__) */
+#endif /* ARMV7M_H */
index da8ed72a11e52e350ec3031a37c4755760cb589a..0e1ad0e3ddf134e59ef8888833e2e28259275433 100644 (file)
@@ -8,7 +8,9 @@
 lib-$(CONFIG_USE_PRIVATE_LIBGCC) += _ashldi3.o _ashrdi3.o _divsi3.o \
                        _lshrdi3.o _modsi3.o _udivsi3.o _umodsi3.o div0.o
 
-ifdef CONFIG_ARM64
+ifdef CONFIG_CPU_V7M
+obj-y  += vectors_m.o crt0.o
+else ifdef CONFIG_ARM64
 obj-y  += crt0_64.o
 else
 obj-y  += vectors.o crt0.o
@@ -36,7 +38,9 @@ obj-$(CONFIG_SEMIHOSTING) += semihosting.o
 
 obj-y  += sections.o
 obj-y  += stack.o
-ifdef CONFIG_ARM64
+ifdef CONFIG_CPU_V7M
+obj-y  += interrupts_m.o
+else ifdef CONFIG_ARM64
 obj-y  += gic_64.o
 obj-y  += interrupts_64.o
 else
index a3aa2cd654915bc4b453f8d575a41f814966d60c..6686d97cb2dc44b5699fb48d25eb5e182598ef7c 100644 (file)
@@ -9,6 +9,9 @@
 #include <config.h>
 #include <asm-offsets.h>
 #include <linux/linkage.h>
+#ifdef CONFIG_CPU_V7M
+#include <asm/armv7m.h>
+#endif
 
 /*
  * This file handles the target-independent stages of the U-Boot
@@ -66,15 +69,30 @@ ENTRY(_main)
 #else
        ldr     sp, =CONFIG_SYS_INIT_SP_ADDR
 #endif
+#if defined(CONFIG_CPU_V7M)    /* v7M forbids using SP as BIC destination */
+       mov     r3, sp
+       bic     r3, r3, #7
+       mov     sp, r3
+#else
        bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */
+#endif
        mov     r2, sp
        sub     sp, sp, #GD_SIZE        /* allocate one GD above SP */
+#if defined(CONFIG_CPU_V7M)    /* v7M forbids using SP as BIC destination */
+       mov     r3, sp
+       bic     r3, r3, #7
+       mov     sp, r3
+#else
        bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */
+#endif
        mov     r9, sp          /* GD is above SP */
        mov     r1, sp
        mov     r0, #0
 clr_gd:
        cmp     r1, r2                  /* while not at end of GD */
+#if defined(CONFIG_CPU_V7M)
+       itt     lo
+#endif
        strlo   r0, [r1]                /* clear 32-bit GD word */
        addlo   r1, r1, #4              /* move to next */
        blo     clr_gd
@@ -94,13 +112,22 @@ clr_gd:
  */
 
        ldr     sp, [r9, #GD_START_ADDR_SP]     /* sp = gd->start_addr_sp */
+#if defined(CONFIG_CPU_V7M)    /* v7M forbids using SP as BIC destination */
+       mov     r3, sp
+       bic     r3, r3, #7
+       mov     sp, r3
+#else
        bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */
+#endif
        ldr     r9, [r9, #GD_BD]                /* r9 = gd->bd */
        sub     r9, r9, #GD_SIZE                /* new GD is below bd */
 
        adr     lr, here
        ldr     r0, [r9, #GD_RELOC_OFF]         /* r0 = gd->reloc_off */
        add     lr, lr, r0
+#if defined(CONFIG_CPU_V7M)
+       orr     lr, #1                          /* As required by Thumb-only */
+#endif
        ldr     r0, [r9, #GD_RELOCADDR]         /* r0 = gd->relocaddr */
        b       relocate_code
 here:
@@ -134,6 +161,9 @@ here:
        mov     r2, #0x00000000         /* prepare zero to clear BSS */
 
 clbss_l:cmp    r0, r1                  /* while not at end of BSS */
+#if defined(CONFIG_CPU_V7M)
+       itt     lo
+#endif
        strlo   r2, [r0]                /* clear 32-bit BSS word */
        addlo   r0, r0, #4              /* move to next */
        blo     clbss_l
diff --git a/arch/arm/lib/interrupts_m.c b/arch/arm/lib/interrupts_m.c
new file mode 100644 (file)
index 0000000..89ce493
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * (C) Copyright 2015
+ * Kamil Lulko, <rev13@wp.pl>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+
+/*
+ * Upon exception entry ARMv7-M processors automatically save stack
+ * frames containing some registers. For simplicity initial
+ * implementation uses only this auto-saved stack frame.
+ * This does not contain complete register set dump,
+ * only R0-R3, R12, LR, PC and xPSR are saved.
+ */
+
+struct autosave_regs {
+       long uregs[8];
+};
+
+#define ARM_XPSR       uregs[7]
+#define ARM_PC         uregs[6]
+#define ARM_LR         uregs[5]
+#define ARM_R12                uregs[4]
+#define ARM_R3         uregs[3]
+#define ARM_R2         uregs[2]
+#define ARM_R1         uregs[1]
+#define ARM_R0         uregs[0]
+
+int interrupt_init(void)
+{
+       return 0;
+}
+
+void enable_interrupts(void)
+{
+       return;
+}
+
+int disable_interrupts(void)
+{
+       return 0;
+}
+
+void dump_regs(struct autosave_regs *regs)
+{
+       printf("pc : %08lx    lr : %08lx    xPSR : %08lx\n",
+              regs->ARM_PC, regs->ARM_LR, regs->ARM_XPSR);
+       printf("r12 : %08lx   r3 : %08lx    r2 : %08lx\n"
+               "r1 : %08lx    r0 : %08lx\n",
+               regs->ARM_R12, regs->ARM_R3, regs->ARM_R2,
+               regs->ARM_R1, regs->ARM_R0);
+}
+
+void bad_mode(void)
+{
+       panic("Resetting CPU ...\n");
+       reset_cpu(0);
+}
+
+void do_hard_fault(struct autosave_regs *autosave_regs)
+{
+       printf("Hard fault\n");
+       dump_regs(autosave_regs);
+       bad_mode();
+}
+
+void do_mm_fault(struct autosave_regs *autosave_regs)
+{
+       printf("Memory management fault\n");
+       dump_regs(autosave_regs);
+       bad_mode();
+}
+
+void do_bus_fault(struct autosave_regs *autosave_regs)
+{
+       printf("Bus fault\n");
+       dump_regs(autosave_regs);
+       bad_mode();
+}
+
+void do_usage_fault(struct autosave_regs *autosave_regs)
+{
+       printf("Usage fault\n");
+       dump_regs(autosave_regs);
+       bad_mode();
+}
+
+void do_invalid_entry(struct autosave_regs *autosave_regs)
+{
+       printf("Exception\n");
+       dump_regs(autosave_regs);
+       bad_mode();
+}
index 92f531452d5435c1adbfce9d4bc80a0e572cdb3f..475d503dd9df63fda046d225c47205a1bc9c80af 100644 (file)
@@ -9,6 +9,9 @@
 #include <asm-offsets.h>
 #include <config.h>
 #include <linux/linkage.h>
+#ifdef CONFIG_CPU_V7M
+#include <asm/armv7m.h>
+#endif
 
 /*
  * Default/weak exception vectors relocation routine
 
 ENTRY(relocate_vectors)
 
+#ifdef CONFIG_CPU_V7M
+       /*
+        * On ARMv7-M we only have to write the new vector address
+        * to VTOR register.
+        */
+       ldr     r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
+       ldr     r1, =V7M_SCB_BASE
+       str     r0, [r1, V7M_SCB_VTOR]
+#else
 #ifdef CONFIG_HAS_VBAR
        /*
         * If the ARM processor has the security extensions,
@@ -46,6 +58,7 @@ ENTRY(relocate_vectors)
        stmia   r1!, {r2-r8,r10}
        ldmia   r0!, {r2-r8,r10}
        stmia   r1!, {r2-r8,r10}
+#endif
 #endif
        bx      lr
 
diff --git a/arch/arm/lib/vectors_m.S b/arch/arm/lib/vectors_m.S
new file mode 100644 (file)
index 0000000..abc7f88
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * (C) Copyright 2015
+ * Kamil Lulko, <rev13@wp.pl>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <config.h>
+#include <asm/armv7m.h>
+#include <linux/linkage.h>
+
+.type __hard_fault_entry, %function
+__hard_fault_entry:
+       mov     r0, sp  @ pass auto-saved registers as argument
+       b       do_hard_fault
+
+.type __mm_fault_entry, %function
+__mm_fault_entry:
+       mov     r0, sp  @ pass auto-saved registers as argument
+       b       do_mm_fault
+
+.type __bus_fault_entry, %function
+__bus_fault_entry:
+       mov     r0, sp  @ pass auto-saved registers as argument
+       b       do_bus_fault
+
+.type __usage_fault_entry, %function
+__usage_fault_entry:
+       mov     r0, sp  @ pass auto-saved registers as argument
+       b       do_usage_fault
+
+.type __invalid_entry, %function
+__invalid_entry:
+       mov     r0, sp  @ pass auto-saved registers as argument
+       b       do_invalid_entry
+
+   .section  .vectors
+ENTRY(_start)
+       .long   CONFIG_SYS_INIT_SP_ADDR         @ 0 - Reset stack pointer
+       .long   reset                           @ 1 - Reset
+       .long   __invalid_entry                 @ 2 - NMI
+       .long   __hard_fault_entry              @ 3 - HardFault
+       .long   __mm_fault_entry                @ 4 - MemManage
+       .long   __bus_fault_entry               @ 5 - BusFault
+       .long   __usage_fault_entry             @ 6 - UsageFault
+       .long   __invalid_entry                 @ 7 - Reserved
+       .long   __invalid_entry                 @ 8 - Reserved
+       .long   __invalid_entry                 @ 9 - Reserved
+       .long   __invalid_entry                 @ 10 - Reserved
+       .long   __invalid_entry                 @ 11 - SVCall
+       .long   __invalid_entry                 @ 12 - Debug Monitor
+       .long   __invalid_entry                 @ 13 - Reserved
+       .long   __invalid_entry                 @ 14 - PendSV
+       .long   __invalid_entry                 @ 15 - SysTick
+       .rept   255 - 16
+       .long   __invalid_entry                 @ 16..255 - External Interrupts
+       .endr