diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4176617eb85..47e8e447b29 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -16,4 +16,24 @@ config ARM64 bool select 64BIT +config ARM_CUSTOM_INTERRUPT_CONTROLLER + bool + depends on !CPU_CORTEX_M + help + This option indicates that the ARM CPU is connected to a custom (i.e. + non-GIC) interrupt controller. + + A number of Cortex-A and Cortex-R cores (Cortex-A5, Cortex-R4/5, ...) + allow interfacing to a custom external interrupt controller and this + option must be selected when such cores are connected to an interrupt + controller that is not the ARM Generic Interrupt Controller (GIC). + + When this option is selected, the architecture interrupt control + functions are mapped to the SoC interrupt control interface, which is + implemented at the SoC level. + + N.B. This option is only applicable to the Cortex-A and Cortex-R + family cores. The Cortex-M family cores are always equipped with + the ARM Nested Vectored Interrupt Controller (NVIC). + endmenu diff --git a/arch/arm/core/aarch32/cortex_r/CMakeLists.txt b/arch/arm/core/aarch32/cortex_r/CMakeLists.txt index a1154a3efb9..52b6d71804e 100644 --- a/arch/arm/core/aarch32/cortex_r/CMakeLists.txt +++ b/arch/arm/core/aarch32/cortex_r/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library_sources( vector_table.S reset.S fault.c + irq_init.c reboot.c stacks.c ) diff --git a/arch/arm/core/aarch32/cortex_r/irq_init.c b/arch/arm/core/aarch32/cortex_r/irq_init.c new file mode 100644 index 00000000000..e6a96bf3957 --- /dev/null +++ b/arch/arm/core/aarch32/cortex_r/irq_init.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Stephanos Ioannidis + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM Cortex-R interrupt initialization + */ + +#include +#include + +/** + * + * @brief Initialize interrupts + * + * @return N/A + */ +void z_arm_interrupt_init(void) +{ + /* + * Initialise interrupt controller. + */ +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + /* Initialise the Generic Interrupt Controller (GIC) driver */ + arm_gic_init(); +#else + /* Invoke SoC-specific interrupt controller initialisation */ + z_soc_irq_init(); +#endif +} diff --git a/arch/arm/core/aarch32/irq_manage.c b/arch/arm/core/aarch32/irq_manage.c index 6d1cf304b4a..0130bdd5a1f 100644 --- a/arch/arm/core/aarch32/irq_manage.c +++ b/arch/arm/core/aarch32/irq_manage.c @@ -18,9 +18,8 @@ #include #if defined(CONFIG_CPU_CORTEX_M) #include -#elif defined(CONFIG_CPU_CORTEX_R) -#include -#include +#elif defined(CONFIG_CPU_CORTEX_A) || defined(CONFIG_CPU_CORTEX_R) +#include #endif #include #include @@ -96,26 +95,32 @@ void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags) NVIC_SetPriority((IRQn_Type)irq, prio); } -#elif defined(CONFIG_CPU_CORTEX_R) +#elif defined(CONFIG_CPU_CORTEX_A) || defined(CONFIG_CPU_CORTEX_R) +/* + * For Cortex-A and Cortex-R cores, the default interrupt controller is the ARM + * Generic Interrupt Controller (GIC) and therefore the architecture interrupt + * control functions are mapped to the GIC driver interface. + * + * When a custom interrupt controller is used (i.e. + * CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER is enabled), the architecture + * interrupt control functions are mapped to the SoC layer in + * `include/arch/arm/aarch32/irq.h`. + */ + +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) void arch_irq_enable(unsigned int irq) { - struct device *dev = _sw_isr_table[0].arg; - - irq_enable_next_level(dev, (irq >> 8) - 1); + arm_gic_irq_enable(irq); } void arch_irq_disable(unsigned int irq) { - struct device *dev = _sw_isr_table[0].arg; - - irq_disable_next_level(dev, (irq >> 8) - 1); + arm_gic_irq_disable(irq); } int arch_irq_is_enabled(unsigned int irq) { - struct device *dev = _sw_isr_table[0].arg; - - return irq_is_enabled_next_level(dev); + return arm_gic_irq_is_enabled(irq); } /** @@ -132,15 +137,11 @@ int arch_irq_is_enabled(unsigned int irq) */ void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags) { - struct device *dev = _sw_isr_table[0].arg; - - if (irq == 0) - return; - - irq_set_priority_next_level(dev, (irq >> 8) - 1, prio, flags); + arm_gic_irq_set_priority(irq, prio, flags); } +#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ -#endif +#endif /* CONFIG_CPU_CORTEX_M */ void z_arm_fatal_error(unsigned int reason, const z_arch_esf_t *esf); diff --git a/arch/arm/core/aarch32/isr_wrapper.S b/arch/arm/core/aarch32/isr_wrapper.S index 4aa3049c725..0d350fc7394 100644 --- a/arch/arm/core/aarch32/isr_wrapper.S +++ b/arch/arm/core/aarch32/isr_wrapper.S @@ -126,7 +126,6 @@ _idle_state_cleared: #if defined(CONFIG_CPU_CORTEX_M) mrs r0, IPSR /* get exception number */ -#endif #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) ldr r1, =16 subs r0, r1 /* get IRQ number */ @@ -134,15 +133,19 @@ _idle_state_cleared: #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) sub r0, r0, #16 /* get IRQ number */ lsl r0, r0, #3 /* table is 8-byte wide */ -#elif defined(CONFIG_ARMV7_R) - /* - * Cortex-R only has one IRQ line so the main handler will be at - * offset 0 of the table. - */ - mov r0, #0 +#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ +#elif defined(CONFIG_CPU_CORTEX_R) + /* Get active IRQ number from the interrupt controller */ +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + bl arm_gic_get_active +#else + bl z_soc_irq_get_active +#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ + push {r0, r1} + lsl r0, r0, #3 /* table is 8-byte wide */ #else #error Unknown ARM architecture -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ +#endif /* CONFIG_CPU_CORTEX_M */ ldr r1, =_sw_isr_table add r1, r1, r0 /* table entry: ISRs must have their MSB set to stay * in thumb mode */ @@ -162,6 +165,16 @@ _idle_state_cleared: #endif /* CONFIG_EXECUTION_BENCHMARKING */ blx r3 /* call ISR */ +#if defined(CONFIG_CPU_CORTEX_R) + /* Signal end-of-interrupt */ + pop {r0, r1} +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + bl arm_gic_eoi +#else + bl z_soc_irq_eoi +#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ +#endif /* CONFIG_CPU_CORTEX_R */ + #ifdef CONFIG_TRACING_ISR bl sys_trace_isr_exit #endif diff --git a/include/arch/arm/aarch32/irq.h b/include/arch/arm/aarch32/irq.h index 647e080a81e..1a9f59842cc 100644 --- a/include/arch/arm/aarch32/irq.h +++ b/include/arch/arm/aarch32/irq.h @@ -29,20 +29,52 @@ GTEXT(z_arm_int_exit); GTEXT(arch_irq_enable) GTEXT(arch_irq_disable) GTEXT(arch_irq_is_enabled) +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) +GTEXT(z_soc_irq_get_active) +GTEXT(z_soc_irq_eoi) +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ #else + +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + extern void arch_irq_enable(unsigned int irq); extern void arch_irq_disable(unsigned int irq); extern int arch_irq_is_enabled(unsigned int irq); +/* internal routine documented in C file, needed by IRQ_CONNECT() macro */ +extern void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, + u32_t flags); + +#else + +/* + * When a custom interrupt controller is specified, map the architecture + * interrupt control functions to the SoC layer interrupt control functions. + */ + +void z_soc_irq_init(void); +void z_soc_irq_enable(unsigned int irq); +void z_soc_irq_disable(unsigned int irq); +int z_soc_irq_is_enabled(unsigned int irq); + +void z_soc_irq_priority_set( + unsigned int irq, unsigned int prio, unsigned int flags); + +unsigned int z_soc_irq_get_active(void); +void z_soc_irq_eoi(unsigned int irq); + +#define arch_irq_enable(irq) z_soc_irq_enable(irq) +#define arch_irq_disable(irq) z_soc_irq_disable(irq) +#define arch_irq_is_enabled(irq) z_soc_irq_is_enabled(irq) + +#define z_arm_irq_priority_set(irq, prio, flags) \ + z_soc_irq_priority_set(irq, prio, flags) + +#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ + extern void z_arm_int_exit(void); -#if defined(CONFIG_ARMV7_R) -static ALWAYS_INLINE void z_arm_interrupt_init(void) -{ -} -#else extern void z_arm_interrupt_init(void); -#endif /* macros convert value of it's argument to a string */ #define DO_TOSTR(s) #s @@ -52,11 +84,6 @@ extern void z_arm_interrupt_init(void); #define DO_CONCAT(x, y) x ## y #define CONCAT(x, y) DO_CONCAT(x, y) -/* internal routine documented in C file, needed by IRQ_CONNECT() macro */ -extern void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, - u32_t flags); - - /* Flags for use with IRQ_CONNECT() */ #ifdef CONFIG_ZERO_LATENCY_IRQS /**