Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ARM interrupt system (Cortex-A & Cortex-R) #22718

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions arch/arm/core/aarch32/cortex_r/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ zephyr_library_sources(
vector_table.S
reset.S
fault.c
irq_init.c
reboot.c
stacks.c
)
33 changes: 33 additions & 0 deletions arch/arm/core/aarch32/cortex_r/irq_init.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io>
*
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @file
* @brief ARM Cortex-R interrupt initialization
*/

#include <arch/cpu.h>
#include <drivers/interrupt_controller/gic.h>

/**
*
* @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
}
41 changes: 21 additions & 20 deletions arch/arm/core/aarch32/irq_manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@
#include <arch/cpu.h>
#if defined(CONFIG_CPU_CORTEX_M)
#include <arch/arm/aarch32/cortex_m/cmsis.h>
#elif defined(CONFIG_CPU_CORTEX_R)
#include <device.h>
#include <irq_nextlevel.h>
#elif defined(CONFIG_CPU_CORTEX_A) || defined(CONFIG_CPU_CORTEX_R)
ioannisg marked this conversation as resolved.
Show resolved Hide resolved
#include <drivers/interrupt_controller/gic.h>
#endif
#include <sys/__assert.h>
#include <toolchain.h>
Expand Down Expand Up @@ -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);
}

/**
Expand All @@ -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);

Expand Down
29 changes: 21 additions & 8 deletions arch/arm/core/aarch32/isr_wrapper.S
Original file line number Diff line number Diff line change
Expand Up @@ -126,23 +126,26 @@ _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 */
lsls r0, #3 /* table is 8-byte wide */
#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 */
Expand All @@ -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 */

stephanosio marked this conversation as resolved.
Show resolved Hide resolved
#ifdef CONFIG_TRACING_ISR
bl sys_trace_isr_exit
#endif
Expand Down
1 change: 1 addition & 0 deletions arch/arm/core/aarch64/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ endif ()
zephyr_library_sources(
cpu_idle.S
fatal.c
irq_init.c
irq_manage.c
prep_c.c
reset.S
Expand Down
34 changes: 34 additions & 0 deletions arch/arm/core/aarch64/irq_init.c
Original file line number Diff line number Diff line change
@@ -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
}
35 changes: 18 additions & 17 deletions arch/arm/core/aarch64/irq_manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
20 changes: 19 additions & 1 deletion arch/arm/core/aarch64/isr_wrapper.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions arch/arm/core/aarch64/prep_c.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading