arch: arm: aarch64: Refactor interrupt interface
The current AArch64 interrupt system relies on the multi-level interrupt mechanism and the `irq_nextlevel` public interface to invoke the Generic Interrupt Controller (GIC) driver functions. Since the GIC driver has been refactored to provide a direct interface, in order to resolve various implementation issues described in the GIC driver refactoring commit, the architecture interrupt control functions are updated to directly invoke the GIC driver functions. This commit also adds support for the ARMv8 cores (e.g. Cortex-A53) that allow interfacing to a custom external interrupt controller (i.e. non-GIC) by mapping the architecture interrupt control functions to the SoC layer interrupt control functions when `ARM_CUSTOM_INTERRUPT_CONTROLLER` configuration is enabled. Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
This commit is contained in:
parent
5ac617c817
commit
91ceee782f
7 changed files with 110 additions and 19 deletions
|
@ -9,6 +9,7 @@ endif ()
|
|||
zephyr_library_sources(
|
||||
cpu_idle.S
|
||||
fatal.c
|
||||
irq_init.c
|
||||
irq_manage.c
|
||||
prep_c.c
|
||||
reset.S
|
||||
|
|
34
arch/arm/core/aarch64/irq_init.c
Normal file
34
arch/arm/core/aarch64/irq_init.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief ARM64 Cortex-A interrupt initialisation
|
||||
*/
|
||||
|
||||
#include <arch/cpu.h>
|
||||
#include <drivers/interrupt_controller/gic.h>
|
||||
|
||||
/**
|
||||
* @brief Initialise interrupts
|
||||
*
|
||||
* This function invokes the ARM Generic Interrupt Controller (GIC) driver to
|
||||
* initialise the interrupt system on the SoCs that use the GIC as the primary
|
||||
* interrupt controller.
|
||||
*
|
||||
* When a custom interrupt controller is used, however, the SoC layer function
|
||||
* is invoked for SoC-specific interrupt system initialisation.
|
||||
*/
|
||||
void z_arm64_interrupt_init(void)
|
||||
{
|
||||
#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
|
||||
}
|
|
@ -11,46 +11,47 @@
|
|||
|
||||
#include <kernel.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <device.h>
|
||||
#include <tracing/tracing.h>
|
||||
#include <irq.h>
|
||||
#include <irq_nextlevel.h>
|
||||
#include <toolchain.h>
|
||||
#include <linker/sections.h>
|
||||
#include <sw_isr_table.h>
|
||||
#include <drivers/interrupt_controller/gic.h>
|
||||
|
||||
void z_arm64_fatal_error(unsigned int reason, const z_arch_esf_t *esf);
|
||||
|
||||
#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER)
|
||||
/*
|
||||
* The default interrupt controller for AArch64 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/aarch64/irq.h`.
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void z_arm64_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 */
|
||||
|
||||
void z_irq_spurious(void *unused)
|
||||
{
|
||||
|
|
|
@ -64,11 +64,29 @@ SECTION_FUNC(TEXT, _isr_wrapper)
|
|||
bl sys_trace_isr_enter
|
||||
#endif
|
||||
|
||||
/* Cortex-A has one IRQ line so the main handler will be at offset 0 */
|
||||
/* 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 */
|
||||
stp x0, x1, [sp, #-16]!
|
||||
lsl x0, x0, #4 /* table is 16-byte wide */
|
||||
|
||||
/* Call interrupt service routine */
|
||||
ldr x1, =_sw_isr_table
|
||||
add x1, x1, x0
|
||||
ldp x0, x3, [x1] /* arg in x0, ISR in x3 */
|
||||
blr x3
|
||||
|
||||
/* Signal end-of-interrupt */
|
||||
ldp x0, x1, [sp], #16
|
||||
#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER)
|
||||
bl arm_gic_eoi
|
||||
#else
|
||||
bl z_soc_irq_eoi
|
||||
#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */
|
||||
|
||||
#ifdef CONFIG_TRACING
|
||||
bl sys_trace_isr_exit
|
||||
#endif
|
||||
|
|
|
@ -28,6 +28,7 @@ extern FUNC_NORETURN void z_cstart(void);
|
|||
void z_arm64_prep_c(void)
|
||||
{
|
||||
z_bss_zero();
|
||||
z_arm64_interrupt_init();
|
||||
z_cstart();
|
||||
|
||||
CODE_UNREACHABLE;
|
||||
|
|
|
@ -27,7 +27,14 @@ extern "C" {
|
|||
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);
|
||||
|
@ -36,6 +43,35 @@ extern int arch_irq_is_enabled(unsigned int irq);
|
|||
extern void z_arm64_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_arm64_irq_priority_set(irq, prio, flags) \
|
||||
z_soc_irq_priority_set(irq, prio, flags)
|
||||
|
||||
#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */
|
||||
|
||||
extern void z_arm64_interrupt_init(void);
|
||||
|
||||
/* All arguments must be computable by the compiler at build time.
|
||||
*
|
||||
* Z_ISR_DECLARE will populate the .intList section with the interrupt's
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ARM_ARCH_TIMER_IRQ ((ARM_TIMER_VIRTUAL_IRQ + 1) << 8)
|
||||
#define ARM_ARCH_TIMER_IRQ ARM_TIMER_VIRTUAL_IRQ
|
||||
#define CNTV_CTL_ENABLE ((1) << 0)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue