[U-Boot] [RFC 1/1] ARM: Add ARMv7-M support

rev13 at wp.pl rev13 at wp.pl
Wed Jan 7 00:57:27 CET 2015


From: Kamil Lulko <rev13 at wp.pl>

I am working on STM32F429-Discovery board support for U-Boot. This is a low-cost and fun board boasting LCD screen, bells and whistles for just under 24$. This board seems to be popular in commercial environments for evaluating ARM in deeply embedded applications. I would like to add support for this board in the mainline U-Boot but "new" architecture support is needed first (ARMv7-M variant is slightly different from other ARMs). This patch implements basic architecture support which I am already using for my own Linux booting setup with this board. I would really appreciate your opinion on feasibility of this board in mainline U-Boot tree and correctness (or not) of this patch. I tried to re-use as much as possible from existing ARM code.

Signed-off-by: Kamil Lulko <rev13 at wp.pl>
---
 arch/arm/cpu/armv7m/Makefile  |  9 ++++
 arch/arm/cpu/armv7m/config.mk |  8 ++++
 arch/arm/cpu/armv7m/cpu.c     | 51 +++++++++++++++++++++++
 arch/arm/cpu/armv7m/start.S   | 18 ++++++++
 arch/arm/include/asm/armv7m.h | 60 +++++++++++++++++++++++++++
 arch/arm/lib/Makefile         |  8 ++++
 arch/arm/lib/crt0.S           | 33 +++++++++++++++
 arch/arm/lib/interrupts_m.c   | 95 +++++++++++++++++++++++++++++++++++++++++++
 arch/arm/lib/relocate.S       |  4 ++
 arch/arm/lib/vectors_m.S      | 58 ++++++++++++++++++++++++++
 10 files changed, 344 insertions(+)
 create mode 100644 arch/arm/cpu/armv7m/Makefile
 create mode 100644 arch/arm/cpu/armv7m/config.mk
 create mode 100644 arch/arm/cpu/armv7m/cpu.c
 create mode 100644 arch/arm/cpu/armv7m/start.S
 create mode 100644 arch/arm/include/asm/armv7m.h
 create mode 100644 arch/arm/lib/interrupts_m.c
 create mode 100644 arch/arm/lib/vectors_m.S

diff --git a/arch/arm/cpu/armv7m/Makefile b/arch/arm/cpu/armv7m/Makefile
new file mode 100644
index 0000000..3279f12
--- /dev/null
+++ b/arch/arm/cpu/armv7m/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at 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
index 0000000..37cfff9
--- /dev/null
+++ b/arch/arm/cpu/armv7m/config.mk
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2014
+# Kamil Lulko, <rev13 at 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
index 0000000..ee4240a
--- /dev/null
+++ b/arch/arm/cpu/armv7m/cpu.c
@@ -0,0 +1,51 @@
+/*
+ * (C) Copyright 2010,2011
+ * Vladimir Khusainov, Emcraft Systems, vlad at emcraft.com
+ *
+ * (C) Copyright 2014
+ * Kamil Lulko, <rev13 at wp.pl>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/armv7m.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * This is called right before passing control to
+ * the Linux kernel point.
+ */
+int cleanup_before_linux(void)
+{
+	return 0;
+}
+
+/*
+ * H/w WDT strobe routine
+ */
+#if defined (CONFIG_HW_WATCHDOG)
+void hw_watchdog_reset(void)
+{
+	/*
+	 * Call the h/w-specific WDT strobe.
+	 */
+	wdt_strobe();
+}
+#endif
+
+/*
+ * Perform the low-level reset.
+ */
+void reset_cpu(ulong addr)
+{
+	/*
+	 * Perform reset but keep priority group unchanged.
+	 */
+	V7M_SCB->aircr = (V7M_AIRCR_VECTKEY << V7M_AIRCR_VECTKEY_SHIFT) |
+			  (V7M_SCB->aircr &
+			  (V7M_AIRCR_PRIGROUP_MSK << V7M_AIRCR_PRIGROUP_SHIFT))
+			  | V7M_AIRCR_SYSRESET;
+}
diff --git a/arch/arm/cpu/armv7m/start.S b/arch/arm/cpu/armv7m/start.S
new file mode 100644
index 0000000..730c775
--- /dev/null
+++ b/arch/arm/cpu/armv7m/start.S
@@ -0,0 +1,18 @@
+/*
+ * (C) Copyright 2014
+ * Kamil Lulko, <rev13 at wp.pl>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <linux/linkage.h>
+
+.globl	reset
+.type reset, %function
+reset:
+	bl	_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
index 0000000..786ce3c
--- /dev/null
+++ b/arch/arm/include/asm/armv7m.h
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright 2010,2011
+ * Vladimir Khusainov, Emcraft Systems, vlad at emcraft.com
+ *
+ * (C) Copyright 2014
+ * Kamil Lulko, <rev13 at 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
+
+#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		((volatile 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_MSK		0x7
+#define V7M_AIRCR_PRIGROUP_SHIFT		8
+#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		((volatile 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
+
+#endif /* ARMV7M_H */
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index d74e4b8..dd3afb8 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -8,11 +8,15 @@
 lib-$(CONFIG_USE_PRIVATE_LIBGCC) += _ashldi3.o _ashrdi3.o _divsi3.o \
 			_lshrdi3.o _modsi3.o _udivsi3.o _umodsi3.o div0.o
 
+ifdef CONFIG_ARMV7M
+obj-y	+= vectors_m.o crt0.o
+else
 ifdef CONFIG_ARM64
 obj-y	+= crt0_64.o
 else
 obj-y	+= vectors.o crt0.o
 endif
+endif
 
 ifndef CONFIG_SPL_BUILD
 ifdef CONFIG_ARM64
@@ -35,12 +39,16 @@ endif
 obj-$(CONFIG_SEMIHOSTING) += semihosting.o
 
 obj-y	+= sections.o
+ifdef CONFIG_ARMV7M
+obj-y	+= interrupts_m.o
+else
 ifdef CONFIG_ARM64
 obj-y	+= gic_64.o
 obj-y	+= interrupts_64.o
 else
 obj-y	+= interrupts.o
 endif
+endif
 obj-y	+= reset.o
 
 obj-y	+= cache.o
diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S
index 22df3e5..21e05e6 100644
--- a/arch/arm/lib/crt0.S
+++ b/arch/arm/lib/crt0.S
@@ -9,6 +9,9 @@
 #include <config.h>
 #include <asm-offsets.h>
 #include <linux/linkage.h>
+#if defined(CONFIG_ARMV7M)
+#include <asm/armv7m.h>
+#endif
 
 /*
  * This file handles the target-independent stages of the U-Boot
@@ -66,15 +69,32 @@ ENTRY(_main)
 #else
 	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
 #endif
+#if defined(CONFIG_ARMV7M)
+	/* 8-byte alignment for ABI compliance armv7-m version */
+	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_ARMV7M)
+	/* 8-byte alignment for ABI compliance armv7-m version */
+	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_ARMV7M)
+	itt lo
+#endif
 	strlo	r0, [r1]		/* clear 32-bit GD word */
 	addlo	r1, r1, #4		/* move to next */
 	blo	clr_gd
@@ -94,13 +114,23 @@ clr_gd:
  */
 
 	ldr	sp, [r9, #GD_START_ADDR_SP]	/* sp = gd->start_addr_sp */
+#if defined(CONFIG_ARMV7M)
+	/* 8-byte alignment for ABI compliance armv7-m version */
+	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_ARMV7M)
+	orr lr, #1				/* Set bit 0 as required by Thumb-2 */
+#endif
 	ldr	r0, [r9, #GD_RELOCADDR]		/* r0 = gd->relocaddr */
 	b	relocate_code
 here:
@@ -120,6 +150,9 @@ here:
 	mov	r2, #0x00000000		/* prepare zero to clear BSS */
 
 clbss_l:cmp	r0, r1			/* while not at end of BSS */
+#if defined(CONFIG_ARMV7M)
+	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
index 0000000..0d7e891
--- /dev/null
+++ b/arch/arm/lib/interrupts_m.c
@@ -0,0 +1,95 @@
+/*
+ * (C) Copyright 2014
+ * Kamil Lulko, <rev13 at 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();
+}
diff --git a/arch/arm/lib/relocate.S b/arch/arm/lib/relocate.S
index 92f5314..ef2a274 100644
--- a/arch/arm/lib/relocate.S
+++ b/arch/arm/lib/relocate.S
@@ -9,6 +9,10 @@
 #include <asm-offsets.h>
 #include <config.h>
 #include <linux/linkage.h>
+#include <config.h>
+#if defined(CONFIG_ARMV7M)
+#include <asm/armv7m.h>
+#endif
 
 /*
  * Default/weak exception vectors relocation routine
diff --git a/arch/arm/lib/vectors_m.S b/arch/arm/lib/vectors_m.S
new file mode 100644
index 0000000..20a4527
--- /dev/null
+++ b/arch/arm/lib/vectors_m.S
@@ -0,0 +1,58 @@
+/*
+ * (C) Copyright 2014
+ * Kamil Lulko, <rev13 at 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	107 - 16
+	.long	__invalid_entry			@ 16..107 - External Interrupts
+	.endr
-- 
2.2.1.212.gc5b9256



More information about the U-Boot mailing list