Skip to content

Commit

Permalink
ARM: Add base support for ARMv7-M
Browse files Browse the repository at this point in the history
This patch adds the base support for the ARMv7-M
architecture. It consists of the corresponding arch/arm/mm/ files and
various #ifdef's around the kernel. Exception handling is implemented by
a subsequent patch.

[ukleinek: squash in some changes originating from commit

b5717ba (Cortex-M3: Add support for the Microcontroller Prototyping System)

from the v2.6.33-arm1 patch stack, port to post 3.6, drop zImage
support, drop reorganisation of pt_regs, assert CONFIG_CPU_V7M doesn't
leak into installed headers and a few cosmetic changes]

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Jonathan Austin <jonathan.austin@arm.com>
Tested-by: Jonathan Austin <jonathan.austin@arm.com>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
  • Loading branch information
Catalin Marinas authored and Uwe Kleine-König committed Apr 17, 2013
1 parent 73a09d2 commit 55bdd69
Show file tree
Hide file tree
Showing 16 changed files with 407 additions and 21 deletions.
17 changes: 16 additions & 1 deletion arch/arm/include/asm/assembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,11 @@
* assumes FIQs are enabled, and that the processor is in SVC mode.
*/
.macro save_and_disable_irqs, oldcpsr
#ifdef CONFIG_CPU_V7M
mrs \oldcpsr, primask
#else
mrs \oldcpsr, cpsr
#endif
disable_irq
.endm

Expand All @@ -150,7 +154,11 @@
* guarantee that this will preserve the flags.
*/
.macro restore_irqs_notrace, oldcpsr
#ifdef CONFIG_CPU_V7M
msr primask, \oldcpsr
#else
msr cpsr_c, \oldcpsr
#endif
.endm

.macro restore_irqs, oldcpsr
Expand Down Expand Up @@ -229,7 +237,14 @@
#endif
.endm

#ifdef CONFIG_THUMB2_KERNEL
#if defined(CONFIG_CPU_V7M)
/*
* setmode is used to assert to be in svc mode during boot. For v7-M
* this is done in __v7m_setup, so setmode can be empty here.
*/
.macro setmode, mode, reg
.endm
#elif defined(CONFIG_THUMB2_KERNEL)
.macro setmode, mode, reg
mov \reg, #\mode
msr cpsr_c, \reg
Expand Down
12 changes: 11 additions & 1 deletion arch/arm/include/asm/cputype.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,17 @@ static inline unsigned int __attribute_const__ read_cpuid_id(void)
return read_cpuid(CPUID_ID);
}

#else /* ifdef CONFIG_CPU_CP15 */
#elif defined(CONFIG_CPU_V7M)

#include <asm/io.h>
#include <asm/v7m.h>

static inline unsigned int __attribute_const__ read_cpuid_id(void)
{
return readl(BASEADDR_V7M_SCB + V7M_SCB_CPUID);
}

#else /* ifdef CONFIG_CPU_CP15 / elif defined(CONFIG_CPU_V7M) */

static inline unsigned int __attribute_const__ read_cpuid_id(void)
{
Expand Down
27 changes: 27 additions & 0 deletions arch/arm/include/asm/glue-cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,37 @@
# endif
#endif

#if defined(CONFIG_CPU_V7M)
# ifdef _CACHE
# define MULTI_CACHE 1
# else
# define _CACHE nop
# endif
#endif

#if !defined(_CACHE) && !defined(MULTI_CACHE)
#error Unknown cache maintenance model
#endif

#ifndef __ASSEMBLER__
extern inline void nop_flush_icache_all(void) { }
extern inline void nop_flush_kern_cache_all(void) { }
extern inline void nop_flush_kern_cache_louis(void) { }
extern inline void nop_flush_user_cache_all(void) { }
extern inline void nop_flush_user_cache_range(unsigned long a,
unsigned long b, unsigned int c) { }

extern inline void nop_coherent_kern_range(unsigned long a, unsigned long b) { }
extern inline int nop_coherent_user_range(unsigned long a,
unsigned long b) { return 0; }
extern inline void nop_flush_kern_dcache_area(void *a, size_t s) { }

extern inline void nop_dma_flush_range(const void *a, const void *b) { }

extern inline void nop_dma_map_area(const void *s, size_t l, int f) { }
extern inline void nop_dma_unmap_area(const void *s, size_t l, int f) { }
#endif

#ifndef MULTI_CACHE
#define __cpuc_flush_icache_all __glue(_CACHE,_flush_icache_all)
#define __cpuc_flush_kern_all __glue(_CACHE,_flush_kern_cache_all)
Expand Down
8 changes: 8 additions & 0 deletions arch/arm/include/asm/glue-df.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@
# endif
#endif

#ifdef CONFIG_CPU_ABRT_NOMMU
# ifdef CPU_DABORT_HANDLER
# define MULTI_DABORT 1
# else
# define CPU_DABORT_HANDLER nommu_early_abort
# endif
#endif

#ifndef CPU_DABORT_HANDLER
#error Unknown data abort handler type
#endif
Expand Down
9 changes: 9 additions & 0 deletions arch/arm/include/asm/glue-proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,15 @@
# endif
#endif

#ifdef CONFIG_CPU_V7M
# ifdef CPU_NAME
# undef MULTI_CPU
# define MULTI_CPU
# else
# define CPU_NAME cpu_v7m
# endif
#endif

#ifndef MULTI_CPU
#define cpu_proc_init __glue(CPU_NAME,_proc_init)
#define cpu_proc_fin __glue(CPU_NAME,_proc_fin)
Expand Down
22 changes: 16 additions & 6 deletions arch/arm/include/asm/irqflags.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,24 @@
/*
* CPU interrupt mask handling.
*/
#ifdef CONFIG_CPU_V7M
#define IRQMASK_REG_NAME_R "primask"
#define IRQMASK_REG_NAME_W "primask"
#define IRQMASK_I_BIT 1
#else
#define IRQMASK_REG_NAME_R "cpsr"
#define IRQMASK_REG_NAME_W "cpsr_c"
#define IRQMASK_I_BIT PSR_I_BIT
#endif

#if __LINUX_ARM_ARCH__ >= 6

static inline unsigned long arch_local_irq_save(void)
{
unsigned long flags;

asm volatile(
" mrs %0, cpsr @ arch_local_irq_save\n"
" mrs %0, " IRQMASK_REG_NAME_R " @ arch_local_irq_save\n"
" cpsid i"
: "=r" (flags) : : "memory", "cc");
return flags;
Expand Down Expand Up @@ -129,7 +139,7 @@ static inline unsigned long arch_local_save_flags(void)
{
unsigned long flags;
asm volatile(
" mrs %0, cpsr @ local_save_flags"
" mrs %0, " IRQMASK_REG_NAME_R " @ local_save_flags"
: "=r" (flags) : : "memory", "cc");
return flags;
}
Expand All @@ -140,16 +150,16 @@ static inline unsigned long arch_local_save_flags(void)
static inline void arch_local_irq_restore(unsigned long flags)
{
asm volatile(
" msr cpsr_c, %0 @ local_irq_restore"
" msr " IRQMASK_REG_NAME_W ", %0 @ local_irq_restore"
:
: "r" (flags)
: "memory", "cc");
}

static inline int arch_irqs_disabled_flags(unsigned long flags)
{
return flags & PSR_I_BIT;
return flags & IRQMASK_I_BIT;
}

#endif
#endif
#endif /* ifdef __KERNEL__ */
#endif /* ifndef __ASM_ARM_IRQFLAGS_H */
4 changes: 4 additions & 0 deletions arch/arm/include/asm/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ struct pt_regs {
*/
static inline int valid_user_regs(struct pt_regs *regs)
{
#ifndef CONFIG_CPU_V7M
unsigned long mode = regs->ARM_cpsr & MODE_MASK;

/*
Expand All @@ -67,6 +68,9 @@ static inline int valid_user_regs(struct pt_regs *regs)
regs->ARM_cpsr |= USR_MODE;

return 0;
#else /* ifndef CONFIG_CPU_V7M */
return 1;
#endif
}

static inline long regs_return_value(struct pt_regs *regs)
Expand Down
1 change: 1 addition & 0 deletions arch/arm/include/asm/system_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define CPU_ARCH_ARMv5TEJ 7
#define CPU_ARCH_ARMv6 8
#define CPU_ARCH_ARMv7 9
#define CPU_ARCH_ARMv7M 10

#ifndef __ASSEMBLY__

Expand Down
44 changes: 44 additions & 0 deletions arch/arm/include/asm/v7m.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Common defines for v7m cpus
*/
#define V7M_SCS_ICTR IOMEM(0xe000e004)
#define V7M_SCS_ICTR_INTLINESNUM_MASK 0x0000000f

#define BASEADDR_V7M_SCB IOMEM(0xe000ed00)

#define V7M_SCB_CPUID 0x00

#define V7M_SCB_ICSR 0x04
#define V7M_SCB_ICSR_PENDSVSET (1 << 28)
#define V7M_SCB_ICSR_PENDSVCLR (1 << 27)
#define V7M_SCB_ICSR_RETTOBASE (1 << 11)

#define V7M_SCB_VTOR 0x08

#define V7M_SCB_SCR 0x10
#define V7M_SCB_SCR_SLEEPDEEP (1 << 2)

#define V7M_SCB_CCR 0x14
#define V7M_SCB_CCR_STKALIGN (1 << 9)

#define V7M_SCB_SHPR2 0x1c
#define V7M_SCB_SHPR3 0x20

#define V7M_SCB_SHCSR 0x24
#define V7M_SCB_SHCSR_USGFAULTENA (1 << 18)
#define V7M_SCB_SHCSR_BUSFAULTENA (1 << 17)
#define V7M_SCB_SHCSR_MEMFAULTENA (1 << 16)

#define V7M_xPSR_FRAMEPTRALIGN 0x00000200
#define V7M_xPSR_EXCEPTIONNO 0x000001ff

/*
* When branching to an address that has bits [31:28] == 0xf an exception return
* occurs. Bits [27:5] are reserved (SBOP). If the processor implements the FP
* extension Bit [4] defines if the exception frame has space allocated for FP
* state information, SBOP otherwise. Bit [3] defines the mode that is returned
* to (0 -> handler mode; 1 -> thread mode). Bit [2] defines which sp is used
* (0 -> msp; 1 -> psp). Bits [1:0] are fixed to 0b01.
*/
#define EXC_RET_STACK_MASK 0x00000004
#define EXC_RET_THREADMODE_PROCESSSTACK 0xfffffffd
35 changes: 27 additions & 8 deletions arch/arm/include/uapi/asm/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,47 @@

/*
* PSR bits
* Note on V7M there is no mode contained in the PSR
*/
#define USR26_MODE 0x00000000
#define FIQ26_MODE 0x00000001
#define IRQ26_MODE 0x00000002
#define SVC26_MODE 0x00000003
#if defined(__KERNEL__) && defined(CONFIG_CPU_V7M)
/*
* Use 0 here to get code right that creates a userspace
* or kernel space thread.
*/
#define USR_MODE 0x00000000
#define SVC_MODE 0x00000000
#else
#define USR_MODE 0x00000010
#define SVC_MODE 0x00000013
#endif
#define FIQ_MODE 0x00000011
#define IRQ_MODE 0x00000012
#define SVC_MODE 0x00000013
#define ABT_MODE 0x00000017
#define HYP_MODE 0x0000001a
#define UND_MODE 0x0000001b
#define SYSTEM_MODE 0x0000001f
#define MODE32_BIT 0x00000010
#define MODE_MASK 0x0000001f
#define PSR_T_BIT 0x00000020
#define PSR_F_BIT 0x00000040
#define PSR_I_BIT 0x00000080
#define PSR_A_BIT 0x00000100
#define PSR_E_BIT 0x00000200
#define PSR_J_BIT 0x01000000
#define PSR_Q_BIT 0x08000000

#define V4_PSR_T_BIT 0x00000020 /* >= V4T, but not V7M */
#define V7M_PSR_T_BIT 0x01000000
#if defined(__KERNEL__) && defined(CONFIG_CPU_V7M)
#define PSR_T_BIT V7M_PSR_T_BIT
#else
/* for compatibility */
#define PSR_T_BIT V4_PSR_T_BIT
#endif

#define PSR_F_BIT 0x00000040 /* >= V4, but not V7M */
#define PSR_I_BIT 0x00000080 /* >= V4, but not V7M */
#define PSR_A_BIT 0x00000100 /* >= V6, but not V7M */
#define PSR_E_BIT 0x00000200 /* >= V6, but not V7M */
#define PSR_J_BIT 0x01000000 /* >= V5J, but not V7M */
#define PSR_Q_BIT 0x08000000 /* >= V5E, including V7M */
#define PSR_V_BIT 0x10000000
#define PSR_C_BIT 0x20000000
#define PSR_Z_BIT 0x40000000
Expand Down
10 changes: 7 additions & 3 deletions arch/arm/kernel/head-nommu.S
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <asm/asm-offsets.h>
#include <asm/cp15.h>
#include <asm/thread_info.h>
#include <asm/v7m.h>

/*
* Kernel startup entry point.
Expand Down Expand Up @@ -50,10 +51,13 @@ ENTRY(stext)

setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
@ and irqs disabled
#ifndef CONFIG_CPU_CP15
ldr r9, =CONFIG_PROCESSOR_ID
#else
#if defined(CONFIG_CPU_CP15)
mrc p15, 0, r9, c0, c0 @ get processor id
#elif defined(CONFIG_CPU_V7M)
ldr r9, =BASEADDR_V7M_SCB
ldr r9, [r9, V7M_SCB_CPUID]
#else
ldr r9, =CONFIG_PROCESSOR_ID
#endif
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=0)?
Expand Down
Loading

0 comments on commit 55bdd69

Please sign in to comment.