From patchwork Tue Jan 6 23:57:27 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: rev13@wp.pl X-Patchwork-Id: 425933 X-Patchwork-Delegate: albert.aribaud@free.fr Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id D835C14007F for ; Wed, 7 Jan 2015 16:14:24 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E99234B604; Wed, 7 Jan 2015 06:14:20 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id S9nmOWYYWiET; Wed, 7 Jan 2015 06:14:20 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id C0F534B5FA; Wed, 7 Jan 2015 06:14:19 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 9FAE94B5EC for ; Wed, 7 Jan 2015 01:06:40 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id s9b0BOFA6drN for ; Wed, 7 Jan 2015 01:06:40 +0100 (CET) X-Greylist: delayed 549 seconds by postgrey-1.32 at theia; Wed, 07 Jan 2015 01:06:37 CET X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from limak-ubuntu (85-222-7-16.dynamic.chello.pl [85.222.7.16]) by theia.denx.de (Postfix) with ESMTP id 735BC4B5E9 for ; Wed, 7 Jan 2015 01:06:37 +0100 (CET) Received: by limak-ubuntu (Postfix, from userid 1000) id AF0AF32252D; Wed, 7 Jan 2015 00:57:29 +0100 (CET) From: rev13@wp.pl To: u-boot@lists.denx.de Date: Wed, 7 Jan 2015 00:57:27 +0100 Message-Id: <1420588647-6034-1-git-send-email-rev13@wp.pl> X-Mailer: git-send-email 2.2.1.212.gc5b9256 X-Mailman-Approved-At: Wed, 07 Jan 2015 06:14:17 +0100 Cc: Kamil Lulko Subject: [U-Boot] [RFC 1/1] ARM: Add ARMv7-M support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.13 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de From: Kamil Lulko 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 --- 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@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, +# +# 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@emcraft.com + * + * (C) Copyright 2014 + * Kamil Lulko, + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +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, + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +.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@emcraft.com + * + * (C) Copyright 2014 + * Kamil Lulko, + * + * 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 #include #include +#if defined(CONFIG_ARMV7M) +#include +#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, + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +/* + * 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 #include #include +#include +#if defined(CONFIG_ARMV7M) +#include +#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, + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +.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