Skip to content

drivers: Add interrupt controller API #66505

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

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft
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
47 changes: 47 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ set(ZEPHYR_FINAL_EXECUTABLE zephyr_final)

# Set some phony targets to collect dependencies
set(OFFSETS_H_TARGET offsets_h)
set(SYS_IRQ_TARGET sys_irq_target)
set(SYSCALL_LIST_H_TARGET syscall_list_h_target)
set(DRIVER_VALIDATION_H_TARGET driver_validation_h_target)
set(KOBJ_TYPES_H_TARGET kobj_types_h_target)
Expand Down Expand Up @@ -910,6 +911,10 @@ add_dependencies(zephyr_interface
${KOBJ_TYPES_H_TARGET}
)

if (CONFIG_SYS_IRQ)
add_dependencies(zephyr_interface ${SYS_IRQ_TARGET})
endif()

add_custom_command(
OUTPUT ${OFFSETS_H_PATH}
COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/gen_offset_header.py
Expand All @@ -921,6 +926,48 @@ add_custom_command(
)
add_custom_target(${OFFSETS_H_TARGET} DEPENDS ${OFFSETS_H_PATH})

set(SYS_IRQ_H_PATH ${PROJECT_BINARY_DIR}/include/generated/zephyr/sys_irq_generated.h)
set(SYS_IRQ_INTERNAL_H_PATH ${PROJECT_BINARY_DIR}/include/generated/zephyr/sys_irq_internal_generated.h)
set(SYS_IRQ_HANDLER_H_PATH ${PROJECT_BINARY_DIR}/include/generated/zephyr/sys_irq_handler_generated.h)
set(SYS_IRQ_HANDLER_C_PATH ${PROJECT_BINARY_DIR}/misc/generated/sys_irq_handler_generated.c)

if(CONFIG_SYS_IRQ_LOG_SPURIOUS)
set(SYS_IRQ_LOG_SPURIOUS_ARG --log-spurious-irq)
endif()

if(CONFIG_SYS_IRQ_DYNAMIC)
set(SYS_IRQ_DYNAMIC_ARG --dynamic-irq)
endif()

add_custom_command(
OUTPUT
${SYS_IRQ_H_PATH}
${SYS_IRQ_INTERNAL_H_PATH}
${SYS_IRQ_HANDLER_H_PATH}
${SYS_IRQ_HANDLER_C_PATH}
COMMAND
${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/build/gen_sys_irq.py
--edt-pickle ${EDT_PICKLE}
--irq-h ${SYS_IRQ_H_PATH}
--irq-internal-h ${SYS_IRQ_INTERNAL_H_PATH}
--irq-handler-h ${SYS_IRQ_HANDLER_H_PATH}
--irq-handler-c ${SYS_IRQ_HANDLER_C_PATH}
${SYS_IRQ_LOG_SPURIOUS_ARG}
${SYS_IRQ_DYNAMIC_ARG}
DEPENDS
${EDT_PICKLE}
)

add_custom_target(
${SYS_IRQ_TARGET}
DEPENDS
${SYS_IRQ_H_PATH}
${SYS_IRQ_INTERNAL_H_PATH}
${SYS_IRQ_HANDLER_H_PATH}
${SYS_IRQ_HANDLER_C_PATH}
)

zephyr_get_include_directories_for_lang(C ZEPHYR_INCLUDES)

add_subdirectory(kernel)
Expand Down
1 change: 1 addition & 0 deletions doc/kernel/services/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ synchronization.
synchronization/condvar.rst
synchronization/events.rst
smp/smp.rst
system_interrupts.rst

.. _kernel_data_passing_api:

Expand Down
58 changes: 58 additions & 0 deletions doc/kernel/services/sys_irq.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.. _sys_irq:

SYS IRQ (SYStem Interrupt ReQuest) WIP
######################################

The SYS IRQ kernel service utilizes the devicetree and device driver model to
provide interrupt handling scalably, portably and efficiently.

Design
******

The design provides clear separation between interrupt controllers, interrupt
generating devices, and interrupt request management.

IRQ (Interrupt ReQuests)
========================

An IRQ is a hardware event which, when triggered, invokes a handler in
software.

INTC (INTerrupt Controller)
===========================

INTCs invoke SYS IRQ INTL (INTerrupt Line) handlers when an interrupt is detected
on the corresponding INTL.

It is the responsibility of the INTC device driver, SoC and Arch, to do any and
all preparation required to invoke the SYS IRQ INTL handlers from a execution
context.

Any and all configuration of INTLs is performed by SYS IRQ through the INTC device
driver API.

INTD (INTerrupt generating Device)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the abbreviation and the full name should be separated. Simply put, the whole process should be capitalized according to the first letter of the sentence, without deliberately showing the abbreviation.

For example

INTD (Interrupt generating device)

(Applicable to all changes.)

==================================

INTDs route IRQs through INTLs. Its' IRQs are defined in the devicetree, and managed
by SYS IRQ.

INTD device drivers define their IRQ handlers which SYS IRQ will invoke when the
IRQ is triggered.

INTD device drivers configure and enable/disable their IRQs using SYS IRQ.

Porting guide
*************

The following section describes how to port a series SoCs, Archs and device drivers
from legacy IRQ to SYS IRQ.

INTC
====

Device drivers implementing the INTC API for all INTCs must be written for each
INTC.

INTD
====
2 changes: 2 additions & 0 deletions drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ add_subdirectory_ifdef(CONFIG_I2S i2s)
add_subdirectory_ifdef(CONFIG_I3C i3c)
add_subdirectory_ifdef(CONFIG_IEEE802154 ieee802154)
add_subdirectory_ifdef(CONFIG_INPUT input)
add_subdirectory_ifdef(CONFIG_INTC intc)
add_subdirectory_ifdef(CONFIG_IPM ipm)
add_subdirectory_ifdef(CONFIG_KSCAN kscan)
add_subdirectory_ifdef(CONFIG_LED led)
Expand All @@ -69,6 +70,7 @@ add_subdirectory_ifdef(CONFIG_NET_DRIVERS net)
add_subdirectory_ifdef(CONFIG_PECI peci)
add_subdirectory_ifdef(CONFIG_PINCTRL pinctrl)
add_subdirectory_ifdef(CONFIG_PM_CPU_OPS pm_cpu_ops)
add_subdirectory_ifdef(CONFIG_POWER power)
add_subdirectory_ifdef(CONFIG_POWER_DOMAIN power_domain)
add_subdirectory_ifdef(CONFIG_PS2 ps2)
add_subdirectory_ifdef(CONFIG_PTP_CLOCK ptp_clock)
Expand Down
2 changes: 2 additions & 0 deletions drivers/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ source "drivers/i2s/Kconfig"
source "drivers/i3c/Kconfig"
source "drivers/ieee802154/Kconfig"
source "drivers/input/Kconfig"
source "drivers/intc/Kconfig"
source "drivers/interrupt_controller/Kconfig"
source "drivers/interrupt_controller/Kconfig.shared_irq"
source "drivers/ipm/Kconfig"
Expand All @@ -66,6 +67,7 @@ source "drivers/pcie/Kconfig"
source "drivers/peci/Kconfig"
source "drivers/pinctrl/Kconfig"
source "drivers/pm_cpu_ops/Kconfig"
source "drivers/power/Kconfig"
source "drivers/power_domain/Kconfig"
source "drivers/ps2/Kconfig"
source "drivers/ptp_clock/Kconfig"
Expand Down
21 changes: 15 additions & 6 deletions drivers/clock_control/clock_control_nrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include <nrfx_clock.h>
#include <zephyr/logging/log.h>
#include <zephyr/shell/shell.h>
#include <zephyr/irq.h>
#include <zephyr/sys/irq.h>

LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL);

Expand Down Expand Up @@ -531,7 +531,7 @@ static void lfclk_spinwait(enum nrf_lfclk_start_mode mode)
/* Clear pending interrupt, otherwise new clock event
* would not wake up from idle.
*/
NVIC_ClearPendingIRQ(DT_INST_IRQN(0));
sys_irq_clear(SYS_DT_IRQN(DT_NODELABEL(clock)));
nrf_clock_task_trigger(NRF_CLOCK,
NRF_CLOCK_TASK_LFCLKSTART);
}
Expand Down Expand Up @@ -648,6 +648,16 @@ static void hfclkaudio_init(void)
#endif
}

static int clk_irq_handler_wrapper(const void *data)
{
ARG_UNUSED(data);

nrfx_clock_irq_handler();
return SYS_IRQ_HANDLED;
}

SYS_DT_DEFINE_IRQ_HANDLER(DT_NODELABEL(clock), clk_irq_handler_wrapper, NULL);

static int clk_init(const struct device *dev)
{
nrfx_err_t nrfx_err;
Expand All @@ -657,9 +667,6 @@ static int clk_init(const struct device *dev)
.stop = onoff_stop
};

IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
nrfx_isr, nrfx_power_clock_irq_handler, 0);

nrfx_err = nrfx_clock_init(clock_event_handler);
if (nrfx_err != NRFX_SUCCESS) {
return -EIO;
Expand All @@ -673,7 +680,9 @@ static int clk_init(const struct device *dev)
z_nrf_clock_calibration_init(data->mgr);
}

nrfx_clock_enable();
sys_irq_configure(SYS_DT_IRQN(DT_NODELABEL(clock)),
SYS_DT_IRQ_FLAGS(DT_NODELABEL(clock)));
sys_irq_enable(SYS_DT_IRQN(DT_NODELABEL(clock)));

for (enum clock_control_nrf_type i = 0;
i < CLOCK_CONTROL_NRF_TYPE_COUNT; i++) {
Expand Down
38 changes: 32 additions & 6 deletions drivers/gpio/gpio_nrfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <string.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/dt-bindings/gpio/nordic-nrf-gpio.h>
#include <zephyr/irq.h>
#include <zephyr/sys/irq.h>

#include <zephyr/drivers/gpio/gpio_utils.h>

Expand Down Expand Up @@ -385,10 +385,6 @@ static void nrfx_gpio_handler(nrfx_gpiote_pin_t abs_pin,
}
#endif /* CONFIG_GPIO_NRFX_INTERRUPT */

#define GPIOTE_IRQ_HANDLER_CONNECT(node_id) \
IRQ_CONNECT(DT_IRQN(node_id), DT_IRQ(node_id, priority), nrfx_isr, \
NRFX_CONCAT(nrfx_gpiote_, DT_PROP(node_id, instance), _irq_handler), 0);

static int gpio_nrfx_init(const struct device *port)
{
const struct gpio_nrfx_cfg *cfg = get_port_cfg(port);
Expand All @@ -409,7 +405,6 @@ static int gpio_nrfx_init(const struct device *port)

#ifdef CONFIG_GPIO_NRFX_INTERRUPT
nrfx_gpiote_global_callback_set(&cfg->gpiote, nrfx_gpio_handler, NULL);
DT_FOREACH_STATUS_OKAY(nordic_nrf_gpiote, GPIOTE_IRQ_HANDLER_CONNECT);
#endif /* CONFIG_GPIO_NRFX_INTERRUPT */

return 0;
Expand Down Expand Up @@ -474,3 +469,34 @@ static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = {
&gpio_nrfx_drv_api_funcs);

DT_INST_FOREACH_STATUS_OKAY(GPIO_NRF_DEVICE)

#define GPIOTE_NRF_ISR_SYM(node_id) \
NRFX_CONCAT( \
nrfx_gpiote_, \
DT_PROP(node_id, instance), \
_irq_handler \
)

#define GPIOTE_NRF_ISR_WRAP_SYM(node_id) \
_CONCAT_3( \
gpiote_nrf_, \
DT_PROP(node_id, instance), \
_isr_wrapper \
)

#define GPIOTE_NRF_DEFINE_IRQ_HANDLER(node_id) \
static int GPIOTE_NRF_ISR_WRAP_SYM(node_id)(const void *data) \
{ \
GPIOTE_NRF_ISR_SYM(node_id)(); \
return SYS_IRQ_HANDLED; \
} \
\
SYS_DT_DEFINE_IRQ_HANDLER( \
node_id, \
GPIOTE_NRF_ISR_WRAP_SYM(node_id), \
NULL \
)

#ifdef CONFIG_GPIO_NRFX_INTERRUPT
DT_FOREACH_STATUS_OKAY(nordic_nrf_gpiote, GPIOTE_NRF_DEFINE_IRQ_HANDLER);
#endif /* CONFIG_GPIO_NRFX_INTERRUPT */
5 changes: 5 additions & 0 deletions drivers/intc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright (c) 2024 Bjarki Arge Andreasen
# SPDX-License-Identifier: Apache-2.0

add_subdirectory_ifdef(CONFIG_INTC_ARM_V7M_NVIC intc_arm_v7m_nvic)
add_subdirectory_ifdef(CONFIG_INTC_ARM_V8M_NVIC intc_arm_v8m_nvic)
12 changes: 12 additions & 0 deletions drivers/intc/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright (c) 2023 Bjarki Arge Andreasen
# SPDX-License-Identifier: Apache-2.0

menuconfig INTC
bool "INTC (INTerrupt Controller) drivers"

if INTC

rsource "intc_arm_v7m_nvic/Kconfig"
rsource "intc_arm_v8m_nvic/Kconfig"

endif # INTC
7 changes: 7 additions & 0 deletions drivers/intc/intc_arm_v7m_nvic/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (c) 2024 Nordic Semiconductor
# SPDX-License-Identifier: Apache-2.0

zephyr_library()

zephyr_library_sources(arm_v7m_nvic.c)
zephyr_linker_sources(ROM_START SORT_KEY 0x0vectors irq-vector-table.ld)
7 changes: 7 additions & 0 deletions drivers/intc/intc_arm_v7m_nvic/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (c) 2024 Nordic Semiconductor
# SPDX-License-Identifier: Apache-2.0

config INTC_ARM_V7M_NVIC
bool "Arm V7M Nested Vector Interrupt Controller"
default y
depends on DT_HAS_ARM_V7M_NVIC_ENABLED
Loading
Loading