From 034c0cb977e2409423eacd1b810ce58a87007fd2 Mon Sep 17 00:00:00 2001 From: Raffael Rostagno Date: Fri, 21 Feb 2025 15:35:44 -0300 Subject: [PATCH] drivers: intc: esp32: Shared allocator for Xtensa and RISCV Update interrupt allocator to use the same driver for both Xtensa and RISCV devices. Signed-off-by: Raffael Rostagno Signed-off-by: Sylvio Alves --- drivers/interrupt_controller/CMakeLists.txt | 1 - drivers/interrupt_controller/Kconfig | 2 - drivers/interrupt_controller/Kconfig.esp32 | 3 +- drivers/interrupt_controller/Kconfig.esp32c3 | 21 -- drivers/interrupt_controller/intc_esp32.c | 162 +++++----- drivers/interrupt_controller/intc_esp32c3.c | 277 ------------------ .../drivers/interrupt_controller/intc_esp32.h | 36 ++- .../interrupt_controller/intc_esp32c3.h | 124 -------- .../interrupt-controller/esp-esp32c2-intmux.h | 7 +- .../interrupt-controller/esp-esp32c3-intmux.h | 7 +- .../interrupt-controller/esp-esp32c6-intmux.h | 7 +- .../interrupt-controller/esp-xtensa-intmux.h | 4 +- .../esp32s2-xtensa-intmux.h | 4 +- .../esp32s3-xtensa-intmux.h | 4 +- 14 files changed, 107 insertions(+), 552 deletions(-) delete mode 100644 drivers/interrupt_controller/Kconfig.esp32c3 delete mode 100644 drivers/interrupt_controller/intc_esp32c3.c delete mode 100644 include/zephyr/drivers/interrupt_controller/intc_esp32c3.h diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index a825f7af787..fa1797d2dcf 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -28,7 +28,6 @@ zephyr_library_sources_ifdef(CONFIG_RV32M1_INTMUX intc_rv32m1_intmux.c zephyr_library_sources_ifdef(CONFIG_SAM0_EIC intc_sam0_eic.c) zephyr_library_sources_ifdef(CONFIG_SHARED_IRQ intc_shared_irq.c) zephyr_library_sources_ifdef(CONFIG_INTC_ESP32 intc_esp32.c) -zephyr_library_sources_ifdef(CONFIG_INTC_ESP32C3 intc_esp32c3.c) zephyr_library_sources_ifdef(CONFIG_SWERV_PIC intc_swerv_pic.c) zephyr_library_sources_ifdef(CONFIG_VEXRISCV_LITEX_IRQ intc_vexriscv_litex.c) zephyr_library_sources_ifdef(CONFIG_VIM intc_vim.c) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index 84bc1f54181..e5c2b028e11 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -84,8 +84,6 @@ source "drivers/interrupt_controller/Kconfig.intel_vtd" source "drivers/interrupt_controller/Kconfig.esp32" -source "drivers/interrupt_controller/Kconfig.esp32c3" - source "drivers/interrupt_controller/Kconfig.xec" source "drivers/interrupt_controller/Kconfig.clic" diff --git a/drivers/interrupt_controller/Kconfig.esp32 b/drivers/interrupt_controller/Kconfig.esp32 index 507161fb613..35699cce56f 100644 --- a/drivers/interrupt_controller/Kconfig.esp32 +++ b/drivers/interrupt_controller/Kconfig.esp32 @@ -4,10 +4,9 @@ # SPDX-License-Identifier: Apache-2.0 config INTC_ESP32 - bool "Interrupt allocator for Xtensa-based Espressif SoCs" + bool "Interrupt allocator for Espressif SoCs" default y depends on SOC_FAMILY_ESPRESSIF_ESP32 - depends on !SOC_SERIES_ESP32C2 && !SOC_SERIES_ESP32C3 && !SOC_SERIES_ESP32C6 help Enable custom interrupt allocator for Espressif SoCs based on Xtensa architecture. diff --git a/drivers/interrupt_controller/Kconfig.esp32c3 b/drivers/interrupt_controller/Kconfig.esp32c3 deleted file mode 100644 index c1a72395648..00000000000 --- a/drivers/interrupt_controller/Kconfig.esp32c3 +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -config INTC_ESP32C3 - bool "ESP32C3 interrupt controller driver" - depends on SOC_FAMILY_ESPRESSIF_ESP32 - depends on SOC_SERIES_ESP32C2 || SOC_SERIES_ESP32C3 || SOC_SERIES_ESP32C6 - default y - help - Enables the esp32c3 interrupt controller driver to handle ISR - management at SoC level. - -config INTC_ESP32C3_DECISIONS_LOG - bool "Espressif's interrupt allocator logging" - depends on INTC_ESP32C3 - select LOG - help - Enable this option to visualize information on decisions made by the - interrupt allocator. This has no impact on the interrupt allocator usage - but may be valuable for debugging purposes. When enabled, messages are - print to the serial console. diff --git a/drivers/interrupt_controller/intc_esp32.c b/drivers/interrupt_controller/intc_esp32.c index 23073d80edc..d6980b3e615 100644 --- a/drivers/interrupt_controller/intc_esp32.c +++ b/drivers/interrupt_controller/intc_esp32.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2021-2025 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include #include #include @@ -15,13 +16,14 @@ #include #include #include +#include #include #include #include #include #include -LOG_MODULE_REGISTER(esp32_intc, CONFIG_LOG_DEFAULT_LEVEL); +LOG_MODULE_REGISTER(intc_esp32, CONFIG_LOG_DEFAULT_LEVEL); #define ETS_INTERNAL_TIMER0_INTR_NO 6 #define ETS_INTERNAL_TIMER1_INTR_NO 15 @@ -47,7 +49,6 @@ LOG_MODULE_REGISTER(esp32_intc, CONFIG_LOG_DEFAULT_LEVEL); #endif /* Typedef for C-callable interrupt handler function */ -typedef void (*intc_handler_t)(void *); typedef void (*intc_dyn_handler_t)(const void *); /* shared critical section context */ @@ -63,32 +64,6 @@ static inline void esp_intr_unlock(void) irq_unlock(esp_intc_csec); } -/* - * Interrupt handler table and unhandled interrupt routine. Duplicated - * from xtensa_intr.c... it's supposed to be private, but we need to look - * into it in order to see if someone allocated an int using - * set_interrupt_handler. - */ -struct intr_alloc_table_entry { - void (*handler)(void *arg); - void *arg; -}; - -/* Default handler for unhandled interrupts. */ -void IRAM_ATTR default_intr_handler(void *arg) -{ - esp_rom_printf("Unhandled interrupt %d on cpu %d!\n", (int)arg, esp_cpu_get_core_id()); -} - -static struct intr_alloc_table_entry intr_alloc_table[ESP_INTC_INTS_NUM * CONFIG_MP_MAX_NUM_CPUS]; - -static void set_interrupt_handler(int n, intc_handler_t f, void *arg) -{ - irq_disable(n); - intr_alloc_table[n * CONFIG_MP_MAX_NUM_CPUS].handler = f; - irq_connect_dynamic(n, 0, (intc_dyn_handler_t)f, arg, 0); -} - /* Linked list of vector descriptions, sorted by cpu.intno value */ static struct vector_desc_t *vector_desc_head; /* implicitly initialized to NULL */ @@ -201,19 +176,9 @@ static struct vector_desc_t *find_desc_for_source(int source, int cpu) return vd; } -void esp_intr_initialize(void) -{ - unsigned int num_cpus = arch_num_cpus(); - - for (size_t i = 0; i < (ESP_INTC_INTS_NUM * num_cpus); ++i) { - intr_alloc_table[i].handler = default_intr_handler; - intr_alloc_table[i].arg = (void *)i; - } -} - int esp_intr_mark_shared(int intno, int cpu, bool is_int_ram) { - if (intno >= ESP_INTC_INTS_NUM) { + if (intno >= SOC_CPU_INTR_NUM) { return -EINVAL; } if (cpu >= arch_num_cpus()) { @@ -238,7 +203,7 @@ int esp_intr_mark_shared(int intno, int cpu, bool is_int_ram) int esp_intr_reserve(int intno, int cpu) { - if (intno >= ESP_INTC_INTS_NUM) { + if (intno >= SOC_CPU_INTR_NUM) { return -EINVAL; } if (cpu >= arch_num_cpus()) { @@ -263,7 +228,7 @@ static bool intr_has_handler(int intr, int cpu) { bool r; - r = intr_alloc_table[intr * CONFIG_MP_MAX_NUM_CPUS + cpu].handler != default_intr_handler; + r = _sw_isr_table[intr * CONFIG_MP_MAX_NUM_CPUS + cpu].isr != z_irq_spurious; return r; } @@ -273,7 +238,6 @@ static bool is_vect_desc_usable(struct vector_desc_t *vd, int flags, int cpu, in /* Check if interrupt is not reserved by design */ int x = vd->intno; esp_cpu_intr_desc_t intr_desc; - esp_cpu_intr_get_desc(cpu, x, &intr_desc); if (intr_desc.flags & ESP_CPU_INTR_DESC_FLAG_RESVD) { @@ -286,14 +250,14 @@ static bool is_vect_desc_usable(struct vector_desc_t *vd, int flags, int cpu, in } #ifndef SOC_CPU_HAS_FLEXIBLE_INTC - /* Check if the interrupt priority is acceptable */ + /* Check if the interrupt level is acceptable */ if (!(flags & (1 << intr_desc.priority))) { - INTC_LOG("....Unusable: incompatible priority"); + INTC_LOG("....Unusable: incompatible level"); return false; } /* check if edge/level type matches what we want */ if (((flags & ESP_INTR_FLAG_EDGE) && (intr_desc.type == ESP_CPU_INTR_TYPE_LEVEL)) || - (((!(flags & ESP_INTR_FLAG_EDGE)) && (intr_desc.type == ESP_CPU_INTR_TYPE_EDGE)))) { + (((!(flags & ESP_INTR_FLAG_EDGE)) && (intr_desc.type == ESP_CPU_INTR_TYPE_EDGE)))) { INTC_LOG("....Unusable: incompatible trigger type"); return false; } @@ -335,7 +299,6 @@ static bool is_vect_desc_usable(struct vector_desc_t *vd, int flags, int cpu, in return false; } } else if (intr_has_handler(x, cpu)) { - /* Check if interrupt already is allocated by set_interrupt_handler */ INTC_LOG("....Unusable: already allocated"); return false; } @@ -400,7 +363,7 @@ static int get_available_int(int flags, int cpu, int force, int source) INTC_LOG("%s: start looking. Current cpu: %d", __func__, cpu); /* No allocated handlers as well as forced intr, iterate over the 32 possible interrupts */ - for (x = 0; x < ESP_INTC_INTS_NUM; x++) { + for (x = 0; x < SOC_CPU_INTR_NUM; x++) { /* Grab the vector_desc for this vector. */ vd = find_desc_for_int(x, cpu); if (vd == NULL) { @@ -409,12 +372,10 @@ static int get_available_int(int flags, int cpu, int force, int source) } esp_cpu_intr_desc_t intr_desc; - esp_cpu_intr_get_desc(cpu, x, &intr_desc); INTC_LOG("Int %d reserved %d level %d %s hasIsr %d", - x, intr_desc.flags & ESP_CPU_INTR_DESC_FLAG_RESVD, - intr_desc.priority, + x, intr_desc.flags & ESP_CPU_INTR_DESC_FLAG_RESVD, intr_desc.priority, intr_desc.type == ESP_CPU_INTR_TYPE_LEVEL ? "LEVEL" : "EDGE", intr_has_handler(x, cpu)); @@ -438,7 +399,8 @@ static int get_available_int(int flags, int cpu, int force, int source) no++; svdesc = svdesc->next; } - if (no < best_shared_ct || best_level > intr_desc.priority) { + if (no < best_shared_ct || + best_level > intr_desc.priority) { /* * Seems like this shared vector is both okay and has * the least amount of ISRs already attached to it. @@ -500,8 +462,7 @@ static void IRAM_ATTR shared_intr_isr(void *arg) esp_intr_lock(); while (sh_vec) { if (!sh_vec->disabled) { - if ((sh_vec->statusreg == NULL) || - (*sh_vec->statusreg & sh_vec->statusmask)) { + if (!(sh_vec->statusreg) || (*sh_vec->statusreg & sh_vec->statusmask)) { sh_vec->isr(sh_vec->arg); } } @@ -516,9 +477,9 @@ int esp_intr_alloc_intrstatus(int source, uint32_t intrstatusmask, intr_handler_t handler, void *arg, - struct intr_handle_data_t **ret_handle) + intr_handle_t *ret_handle) { - struct intr_handle_data_t *ret = NULL; + intr_handle_data_t *ret = NULL; int force = -1; INTC_LOG("%s (cpu %d): checking args", __func__, esp_cpu_get_core_id()); @@ -544,8 +505,8 @@ int esp_intr_alloc_intrstatus(int source, * we need to make sure the interrupt is connected to the CPU0. * CPU1 does not have access to the RTC fast memory through this region. */ - if ((flags & ESP_INTR_FLAG_IRAM) && handler && !esp_ptr_in_iram(handler) && - !esp_ptr_in_rtc_iram_fast(handler)) { + if ((flags & ESP_INTR_FLAG_IRAM) && handler && + !esp_ptr_in_iram(handler) && !esp_ptr_in_rtc_iram_fast(handler)) { return -EINVAL; } @@ -636,16 +597,20 @@ int esp_intr_alloc_intrstatus(int source, sv->disabled = 0; vd->shared_vec_info = sv; vd->flags |= VECDESC_FL_SHARED; + + /* Disable interrupt to avoid assert at IRQ install */ + irq_disable(intr); + /* (Re-)set shared isr handler to new value. */ - set_interrupt_handler(intr, shared_intr_isr, vd); + irq_connect_dynamic(intr, 0, (intc_dyn_handler_t)shared_intr_isr, vd, 0); } else { /* Mark as unusable for other interrupt sources. This is ours now! */ vd->flags = VECDESC_FL_NONSHARED; if (handler) { - set_interrupt_handler(intr, handler, arg); + irq_connect_dynamic(intr, 0, (intc_dyn_handler_t)handler, arg, 0); } if (flags & ESP_INTR_FLAG_EDGE) { - xthal_set_intclear(1 << intr); + esp_cpu_intr_edge_ack(intr); } vd->source = source; } @@ -675,10 +640,9 @@ int esp_intr_alloc_intrstatus(int source, esp_intr_disable(ret); } -#ifdef SOC_CPU_HAS_FLEXIBLE_INTC +#if SOC_CPU_HAS_FLEXIBLE_INTC /* Extract the level from the interrupt passed flags */ int level = esp_intr_flags_to_level(flags); - esp_cpu_intr_set_priority(intr, level); if (flags & ESP_INTR_FLAG_EDGE) { @@ -688,6 +652,11 @@ int esp_intr_alloc_intrstatus(int source, } #endif +#if SOC_INT_PLIC_SUPPORTED + /* Make sure the interrupt is not delegated to user mode (IDF uses machine mode only) */ + RV_CLEAR_CSR(mideleg, BIT(intr)); +#endif + esp_intr_unlock(); /* Fill return handle if needed, otherwise free handle. */ @@ -698,6 +667,7 @@ int esp_intr_alloc_intrstatus(int source, } LOG_DBG("Connected src %d to int %d (cpu %d)", source, intr, cpu); + return 0; } @@ -705,7 +675,7 @@ int esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, - struct intr_handle_data_t **ret_handle) + intr_handle_t *ret_handle) { /* * As an optimization, we can create a table with the possible interrupt status @@ -715,7 +685,7 @@ int esp_intr_alloc(int source, return esp_intr_alloc_intrstatus(source, flags, 0, 0, handler, arg, ret_handle); } -int IRAM_ATTR esp_intr_set_in_iram(struct intr_handle_data_t *handle, bool is_in_iram) +int IRAM_ATTR esp_intr_set_in_iram(intr_handle_t handle, bool is_in_iram) { if (!handle) { return -EINVAL; @@ -739,7 +709,7 @@ int IRAM_ATTR esp_intr_set_in_iram(struct intr_handle_data_t *handle, bool is_in return 0; } -int esp_intr_free(struct intr_handle_data_t *handle) +int esp_intr_free(intr_handle_t handle) { bool free_shared_vector = false; @@ -780,18 +750,20 @@ int esp_intr_free(struct intr_handle_data_t *handle) if ((handle->vector_desc->flags & VECDESC_FL_NONSHARED) || free_shared_vector) { INTC_LOG("%s: Disabling int, killing handler", __func__); - /* Reset to normal handler */ - set_interrupt_handler(handle->vector_desc->intno, - default_intr_handler, - (void *)((int)handle->vector_desc->intno)); + + /* Disable interrupt to avoid assert at IRQ install */ + irq_disable(handle->vector_desc->intno); + + /* Reset IRQ handler */ + irq_connect_dynamic(handle->vector_desc->intno, 0, + (intc_dyn_handler_t)z_irq_spurious, + (void *)((int)handle->vector_desc->intno), 0); /* * Theoretically, we could free the vector_desc... not sure if that's worth the * few bytes of memory we save.(We can also not use the same exit path for empty * shared ints anymore if we delete the desc.) For now, just mark it as free. */ - handle->vector_desc->flags &= ~(VECDESC_FL_NONSHARED | - VECDESC_FL_RESERVED | VECDESC_FL_SHARED); - + handle->vector_desc->flags &= !(VECDESC_FL_NONSHARED | VECDESC_FL_RESERVED); /* Also kill non_iram mask bit. */ non_iram_int_mask[handle->vector_desc->cpu] &= ~(1 << (handle->vector_desc->intno)); } @@ -800,12 +772,12 @@ int esp_intr_free(struct intr_handle_data_t *handle) return 0; } -int esp_intr_get_intno(struct intr_handle_data_t *handle) +int esp_intr_get_intno(intr_handle_t handle) { return handle->vector_desc->intno; } -int esp_intr_get_cpu(struct intr_handle_data_t *handle) +int esp_intr_get_cpu(intr_handle_t handle) { return handle->vector_desc->cpu; } @@ -824,7 +796,7 @@ int esp_intr_get_cpu(struct intr_handle_data_t *handle) */ #define INT_MUX_DISABLED_INTNO 6 -int IRAM_ATTR esp_intr_enable(struct intr_handle_data_t *handle) +int IRAM_ATTR esp_intr_enable(intr_handle_t handle) { if (!handle) { return -EINVAL; @@ -840,8 +812,8 @@ int IRAM_ATTR esp_intr_enable(struct intr_handle_data_t *handle) } if (source >= 0) { /* Disabled using int matrix; re-connect to enable */ - esp_rom_route_intr_matrix(handle->vector_desc->cpu, - source, handle->vector_desc->intno); + esp_rom_route_intr_matrix(handle->vector_desc->cpu, source, + handle->vector_desc->intno); } else { /* Re-enable using cpu int ena reg */ if (handle->vector_desc->cpu != esp_cpu_get_core_id()) { @@ -854,7 +826,7 @@ int IRAM_ATTR esp_intr_enable(struct intr_handle_data_t *handle) return 0; } -int IRAM_ATTR esp_intr_disable(struct intr_handle_data_t *handle) +int IRAM_ATTR esp_intr_disable(intr_handle_t handle) { if (!handle) { return -EINVAL; @@ -884,8 +856,8 @@ int IRAM_ATTR esp_intr_disable(struct intr_handle_data_t *handle) if (source >= 0) { if (disabled) { /* Disable using int matrix */ - esp_rom_route_intr_matrix(handle->vector_desc->cpu, - source, INT_MUX_DISABLED_INTNO); + esp_rom_route_intr_matrix(handle->vector_desc->cpu, source, + INT_MUX_DISABLED_INTNO); } } else { /* Disable using per-cpu regs */ @@ -899,7 +871,6 @@ int IRAM_ATTR esp_intr_disable(struct intr_handle_data_t *handle) return 0; } - void IRAM_ATTR esp_intr_noniram_disable(void) { esp_intr_lock(); @@ -914,6 +885,7 @@ void IRAM_ATTR esp_intr_noniram_disable(void) oldint = esp_cpu_intr_get_enabled_mask(); esp_cpu_intr_disable(non_iram_ints); rtc_isr_noniram_disable(cpu); + /* Save which ints we did disable */ non_iram_int_disabled[cpu] = oldint & non_iram_ints; esp_intr_unlock(); } @@ -932,3 +904,29 @@ void IRAM_ATTR esp_intr_noniram_enable(void) rtc_isr_noniram_enable(cpu); esp_intr_unlock(); } + +#if defined(CONFIG_RISCV) +/* + * Functions below are implemented to keep consistency with current + * Xtensa chips API behavior. When accessing Zephyr's API + * directly, the CPU IRQs can be enabled or disabled directly. This + * is mostly used to control lines that are not muxed, thus bypass the + * interrupt matrix. For RISCV, these functions are not expected to + * be used via user API, as peripherals are all routed through INTMUX + * and shared interrupts require managing sources state. + */ +void arch_irq_enable(unsigned int irq) +{ + esp_cpu_intr_enable(1 << irq); +} + +void arch_irq_disable(unsigned int irq) +{ + esp_cpu_intr_disable(1 << irq); +} + +int arch_irq_is_enabled(unsigned int irq) +{ + return !!(esp_cpu_intr_get_enabled_mask() & (1 << irq)); +} +#endif diff --git a/drivers/interrupt_controller/intc_esp32c3.c b/drivers/interrupt_controller/intc_esp32c3.c deleted file mode 100644 index 4ddfbfcb132..00000000000 --- a/drivers/interrupt_controller/intc_esp32c3.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (c) 2021-2025 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "soc/soc.h" -#include -#include -#include -#include -#include - -#include -LOG_MODULE_REGISTER(intc_esp32, CONFIG_LOG_DEFAULT_LEVEL); - -/* - * Define this to debug the choices made when allocating the interrupt. This leads to much debugging - * output within a critical region, which can lead to weird effects like e.g. the interrupt watchdog - * being triggered, that is why it is separate from the normal LOG* scheme. - */ -#ifdef CONFIG_INTC_ESP32C3_DECISIONS_LOG -# define INTC_LOG(...) LOG_INF(__VA_ARGS__) -#else -# define INTC_LOG(...) do {} while (0) -#endif - -#define ESP32_INTC_DEFAULT_PRIORITY 15 -#define ESP32_INTC_DEFAULT_THRESHOLD 1 -#define ESP32_INTC_DISABLED_SLOT 31 -#define ESP32_INTC_SRCS_PER_IRQ 2 - -/* Define maximum interrupt sources per SoC */ -#if defined(CONFIG_SOC_SERIES_ESP32C6) -/* - * Interrupt reserved mask - * 0 is reserved - * 1 is for Wi-Fi - * 3, 4 and 7 are unavailable for PULP CPU as they are bound to Core-Local Interrupts (CLINT) - */ -#define RSVD_MASK (BIT(0) | BIT(1) | BIT(3) | BIT(4) | BIT(7)) -#define ESP_INTC_AVAILABLE_IRQS 31 -#else -/* - * Interrupt reserved mask - * 1 is for Wi-Fi - */ -#define RSVD_MASK (BIT(0) | BIT(1)) -#define ESP_INTC_AVAILABLE_IRQS 30 -#endif - -/* Single array for IRQ allocation */ -static uint8_t esp_intr_irq_alloc[ESP_INTC_AVAILABLE_IRQS * ESP32_INTC_SRCS_PER_IRQ]; - -#define ESP_INTR_IDX(irq, slot) ((irq % ESP_INTC_AVAILABLE_IRQS) * ESP32_INTC_SRCS_PER_IRQ + slot) - -#define STATUS_MASK_NUM 3 - -static uint32_t esp_intr_enabled_mask[STATUS_MASK_NUM] = {0, 0, 0}; - -static uint32_t esp_intr_find_irq_for_source(uint32_t source) -{ - if (source >= ETS_MAX_INTR_SOURCE) { - return IRQ_NA; - } - - uint32_t irq = source / ESP32_INTC_SRCS_PER_IRQ; - - /* Check if the derived IRQ is usable first */ - for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) { - int idx = ESP_INTR_IDX(irq, j); - - /* Ensure idx is within a valid range */ - if (idx >= ARRAY_SIZE(esp_intr_irq_alloc)) { - continue; - } - - /* If source is already assigned, return the IRQ */ - if (esp_intr_irq_alloc[idx] == source) { - return irq; - } - - /* If slot is free, allocate it */ - if (esp_intr_irq_alloc[idx] == IRQ_FREE) { - esp_intr_irq_alloc[idx] = source; - return irq; - } - } - - /* If derived IRQ is full, search for another available IRQ */ - for (irq = 0; irq < ESP_INTC_AVAILABLE_IRQS; irq++) { - if (RSVD_MASK & (1U << irq)) { - continue; - } - for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) { - int idx = ESP_INTR_IDX(irq, j); - - /* Ensure idx is within a valid range */ - if (idx >= ARRAY_SIZE(esp_intr_irq_alloc)) { - continue; - } - - /* If source is already assigned, return this IRQ */ - if (esp_intr_irq_alloc[idx] == source) { - return irq; - } - - /* If slot is free, allocate it */ - if (esp_intr_irq_alloc[idx] == IRQ_FREE) { - esp_intr_irq_alloc[idx] = source; - return irq; - } - } - } - - /* No available slot found */ - return IRQ_NA; -} - -void esp_intr_initialize(void) -{ - for (int i = 0; i < ETS_MAX_INTR_SOURCE; i++) { - esp_rom_intr_matrix_set(0, i, ESP32_INTC_DISABLED_SLOT); - } - - for (int irq = 0; irq < ESP_INTC_AVAILABLE_IRQS; irq++) { - for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) { - int idx = ESP_INTR_IDX(irq, j); - - if (RSVD_MASK & (1U << irq)) { - esp_intr_irq_alloc[idx] = IRQ_NA; - } else { - esp_intr_irq_alloc[idx] = IRQ_FREE; - } - } - } - - /* set global INTC masking level */ - esprv_intc_int_set_threshold(ESP32_INTC_DEFAULT_THRESHOLD); -} - -int esp_intr_alloc(int source, - int flags, - isr_handler_t handler, - void *arg, - void **ret_handle) -{ - ARG_UNUSED(flags); - ARG_UNUSED(ret_handle); - - if (handler == NULL) { - return -EINVAL; - } - - if (source < 0 || source >= ETS_MAX_INTR_SOURCE) { - return -EINVAL; - } - - uint32_t key = irq_lock(); - uint32_t irq = esp_intr_find_irq_for_source(source); - - if (irq == IRQ_NA) { - irq_unlock(key); - return -ENOMEM; - } - - irq_connect_dynamic(source, - ESP32_INTC_DEFAULT_PRIORITY, - handler, - arg, - 0); - - INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X", - esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]); - - irq_unlock(key); - int ret = esp_intr_enable(source); - - return ret; -} - -int esp_intr_disable(int source) -{ - if (source < 0 || source >= ETS_MAX_INTR_SOURCE) { - return -EINVAL; - } - - uint32_t key = irq_lock(); - - esp_rom_intr_matrix_set(0, - source, - ESP32_INTC_DISABLED_SLOT); - - for (int i = 0; i < ESP_INTC_AVAILABLE_IRQS; i++) { - if (RSVD_MASK & (1U << i)) { - continue; - } - for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) { - int idx = ESP_INTR_IDX(i, j); - - if (esp_intr_irq_alloc[idx] == source) { - esp_intr_irq_alloc[idx] = IRQ_FREE; - } - } - } - - if (source < 32) { - esp_intr_enabled_mask[0] &= ~(1 << source); - } else if (source < 64) { - esp_intr_enabled_mask[1] &= ~(1 << (source - 32)); - } else if (source < 96) { - esp_intr_enabled_mask[2] &= ~(1 << (source - 64)); - } - - INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X", - esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]); - - irq_unlock(key); - - return 0; -} - -int esp_intr_enable(int source) -{ - if (source < 0 || source >= ETS_MAX_INTR_SOURCE) { - return -EINVAL; - } - - uint32_t key = irq_lock(); - uint32_t irq = esp_intr_find_irq_for_source(source); - - if (irq == IRQ_NA) { - irq_unlock(key); - return -ENOMEM; - } - - esp_rom_intr_matrix_set(0, source, irq); - - if (source < 32) { - esp_intr_enabled_mask[0] |= (1 << source); - } else if (source < 64) { - esp_intr_enabled_mask[1] |= (1 << (source - 32)); - } else if (source < 96) { - esp_intr_enabled_mask[2] |= (1 << (source - 64)); - } - - INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X", - esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]); - - esprv_intc_int_set_priority(irq, ESP32_INTC_DEFAULT_PRIORITY); - esprv_intc_int_set_type(irq, INTR_TYPE_LEVEL); - esprv_intc_int_enable(1 << irq); - - irq_unlock(key); - - return 0; -} - -uint32_t esp_intr_get_enabled_intmask(int status_mask_number) -{ - INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X", - esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]); - - if (status_mask_number < STATUS_MASK_NUM) { - return esp_intr_enabled_mask[status_mask_number]; - } - - return 0; -} diff --git a/include/zephyr/drivers/interrupt_controller/intc_esp32.h b/include/zephyr/drivers/interrupt_controller/intc_esp32.h index 5b5ce8d94bb..91083528e37 100644 --- a/include/zephyr/drivers/interrupt_controller/intc_esp32.h +++ b/include/zephyr/drivers/interrupt_controller/intc_esp32.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2021-2025 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,9 +10,6 @@ #include #include -/* number of possible interrupts per core */ -#define ESP_INTC_INTS_NUM (32) - /* * Interrupt allocation flags - These flags can be used to specify * which interrupt qualities the code calling esp_intr_alloc* needs. @@ -71,6 +68,12 @@ /* Function prototype for interrupt handler function */ typedef void (*intr_handler_t)(void *arg); +/* Interrupt handler associated data structure */ +typedef struct intr_handle_data_t intr_handle_data_t; + +/* Handle to an interrupt handler */ +typedef intr_handle_data_t *intr_handle_t; + struct shared_vector_desc_t { int disabled : 1; int source : 8; @@ -97,11 +100,6 @@ struct intr_handle_data_t { struct shared_vector_desc_t *shared_vector_desc; }; -/** - * @brief Initializes interrupt table to its defaults - */ -void esp_intr_initialize(void); - /** * @brief Mark an interrupt as a shared interrupt * @@ -158,7 +156,7 @@ int esp_intr_reserve(int intno, int cpu); * @param handler The interrupt handler. Must be NULL when an interrupt of level >3 * is requested, because these types of interrupts aren't C-callable. * @param arg Optional argument for passed to the interrupt handler - * @param ret_handle Pointer to a struct intr_handle_data_t pointer to store a handle that can + * @param ret_handle Pointer to an intr_handle_t pointer to store a handle that can * later be used to request details or free the interrupt. Can be NULL if no handle * is required. * @@ -170,7 +168,7 @@ int esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, - struct intr_handle_data_t **ret_handle); + intr_handle_t *ret_handle); /** @@ -200,7 +198,7 @@ int esp_intr_alloc(int source, * @param handler The interrupt handler. Must be NULL when an interrupt of level >3 * is requested, because these types of interrupts aren't C-callable. * @param arg Optional argument for passed to the interrupt handler - * @param ret_handle Pointer to a struct intr_handle_data_t pointer to store a handle that can + * @param ret_handle Pointer to an intr_handle_t pointer to store a handle that can * later be used to request details or free the interrupt. Can be NULL if no handle * is required. * @@ -214,7 +212,7 @@ int esp_intr_alloc_intrstatus(int source, uint32_t intrstatusmask, intr_handler_t handler, void *arg, - struct intr_handle_data_t **ret_handle); + intr_handle_t *ret_handle); /** @@ -235,7 +233,7 @@ int esp_intr_alloc_intrstatus(int source, * @return -EINVAL the handle is NULL * 0 otherwise */ -int esp_intr_free(struct intr_handle_data_t *handle); +int esp_intr_free(intr_handle_t handle); /** @@ -245,7 +243,7 @@ int esp_intr_free(struct intr_handle_data_t *handle); * * @return The core number where the interrupt is allocated */ -int esp_intr_get_cpu(struct intr_handle_data_t *handle); +int esp_intr_get_cpu(intr_handle_t handle); /** * @brief Get the allocated interrupt for a certain handle @@ -254,7 +252,7 @@ int esp_intr_get_cpu(struct intr_handle_data_t *handle); * * @return The interrupt number */ -int esp_intr_get_intno(struct intr_handle_data_t *handle); +int esp_intr_get_intno(intr_handle_t handle); /** * @brief Disable the interrupt associated with the handle @@ -272,7 +270,7 @@ int esp_intr_get_intno(struct intr_handle_data_t *handle); * @return -EINVAL if the combination of arguments is invalid. * 0 otherwise */ -int esp_intr_disable(struct intr_handle_data_t *handle); +int esp_intr_disable(intr_handle_t handle); /** * @brief Enable the interrupt associated with the handle @@ -285,7 +283,7 @@ int esp_intr_disable(struct intr_handle_data_t *handle); * @return -EINVAL if the combination of arguments is invalid. * 0 otherwise */ -int esp_intr_enable(struct intr_handle_data_t *handle); +int esp_intr_enable(intr_handle_t handle); /** * @brief Set the "in IRAM" status of the handler. @@ -299,7 +297,7 @@ int esp_intr_enable(struct intr_handle_data_t *handle); * @return -EINVAL if the combination of arguments is invalid. * 0 otherwise */ -int esp_intr_set_in_iram(struct intr_handle_data_t *handle, bool is_in_iram); +int esp_intr_set_in_iram(intr_handle_t handle, bool is_in_iram); /** * @brief Disable interrupts that aren't specifically marked as running from IRAM diff --git a/include/zephyr/drivers/interrupt_controller/intc_esp32c3.h b/include/zephyr/drivers/interrupt_controller/intc_esp32c3.h deleted file mode 100644 index 127e7972632..00000000000 --- a/include/zephyr/drivers/interrupt_controller/intc_esp32c3.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_DRIVERS_INTERRUPT_CONTROLLER_INTC_ESP32C3_H_ -#define ZEPHYR_INCLUDE_DRIVERS_INTERRUPT_CONTROLLER_INTC_ESP32C3_H_ - -#include -#include -#include -/* - * Interrupt allocation flags - These flags can be used to specify - * which interrupt qualities the code calling esp_intr_alloc* needs. - */ - -/* Keep the LEVELx values as they are here; they match up with (1< 0 ? ((1 << (priority)) & ESP_INTR_FLAG_LEVELMASK) : 0) - -/* - * Check interrupt flags from input and filter unallowed values. - */ -#define ESP_INT_FLAGS_CHECK(int_flags) ((int_flags) & ESP_INTR_FLAG_SHARED) - - -/* Function prototype for interrupt handler function */ -typedef void (*isr_handler_t)(const void *arg); - -/** - * @brief Initializes interrupt table to its defaults - */ -void esp_intr_initialize(void); - -/** - * @brief Allocate an interrupt with the given parameters. - * - * This finds an interrupt that matches the restrictions as given in the flags - * parameter, maps the given interrupt source to it and hooks up the given - * interrupt handler (with optional argument) as well. If needed, it can return - * a handle for the interrupt as well. - * - * @param source The interrupt source. - * @param flags An ORred mask of the ESP_INTR_FLAG_* defines. These restrict the - * choice of interrupts that this routine can choose from. If this value - * is 0, it will default to allocating a non-shared interrupt of level - * 1, 2 or 3. If this is ESP_INTR_FLAG_SHARED, it will allocate a shared - * interrupt of level 1. Setting ESP_INTR_FLAG_INTRDISABLED will return - * from this function with the interrupt disabled. - * @param handler The interrupt handler. - * @param arg Optional argument for passed to the interrupt handler - * @param ret_handle Pointer to a struct intr_handle_data_t pointer to store a handle that can - * later be used to request details or free the interrupt. Can be NULL if no handle - * is required. - * - * @return -EINVAL if the combination of arguments is invalid. - * -ENODEV No free interrupt found with the specified flags - * 0 otherwise - */ -int esp_intr_alloc(int source, - int flags, - isr_handler_t handler, - void *arg, - void **ret_handle); - -/** - * @brief Disable the interrupt associated with the source - * - * @param source The interrupt source - * - * @return -EINVAL if the combination of arguments is invalid. - * 0 otherwise - */ -int esp_intr_disable(int source); - -/** - * @brief Enable the interrupt associated with the source - * - * @param source The interrupt source - * @return -EINVAL if the combination of arguments is invalid. - * 0 otherwise - */ -int esp_intr_enable(int source); - -/** - * @brief Gets the current enabled interrupts - * - * @param status_mask_number the status mask can be 0 or 1 - * @return bitmask of enabled interrupt sources - */ -uint32_t esp_intr_get_enabled_intmask(int status_mask_number); - -#endif /* ZEPHYR_INCLUDE_DRIVERS_INTERRUPT_CONTROLLER_INTC_ESP32C3_H_ */ diff --git a/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c2-intmux.h b/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c2-intmux.h index 5f4cd793f18..cf0e9c5eee5 100644 --- a/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c2-intmux.h +++ b/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c2-intmux.h @@ -51,11 +51,8 @@ #define CORE0_PIF_PMS_SIZE_INTR_SOURCE 41 #define CACHE_CORE0_ACS_INTR_SOURCE 42 -/* RISC-V supports priority values from 1 (lowest) to 15. - * As interrupt controller for Xtensa and RISC-V is shared, this is - * set to an intermediate and compatible value. - */ -#define IRQ_DEFAULT_PRIORITY 3 +/* Zero will allocate low/medium levels of priority (ESP_INTR_FLAG_LOWMED) */ +#define IRQ_DEFAULT_PRIORITY 0 #define ESP_INTR_FLAG_SHARED (1<<8) /* Interrupt can be shared between ISRs */ diff --git a/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c3-intmux.h b/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c3-intmux.h index f6059000505..4f4df11455d 100644 --- a/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c3-intmux.h +++ b/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c3-intmux.h @@ -70,11 +70,8 @@ #define BAK_PMS_VIOLATE_INTR_SOURCE 60 #define CACHE_CORE0_ACS_INTR_SOURCE 61 -/* RISC-V supports priority values from 1 (lowest) to 15. - * As interrupt controller for Xtensa and RISC-V is shared, this is - * set to an intermediate and compatible value. - */ -#define IRQ_DEFAULT_PRIORITY 3 +/* Zero will allocate low/medium levels of priority (ESP_INTR_FLAG_LOWMED) */ +#define IRQ_DEFAULT_PRIORITY 0 #define ESP_INTR_FLAG_SHARED (1<<8) /* Interrupt can be shared between ISRs */ diff --git a/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c6-intmux.h b/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c6-intmux.h index 24b55504016..fc89526d7bd 100644 --- a/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c6-intmux.h +++ b/include/zephyr/dt-bindings/interrupt-controller/esp-esp32c6-intmux.h @@ -86,11 +86,8 @@ #define ECC_INTR_SOURCE 76 /* interrupt of ECC accelerator, level*/ #define MAX_INTR_SOURCE 77 -/* RISC-V supports priority values from 1 (lowest) to 15. - * As interrupt controller for Xtensa and RISC-V is shared, this is - * set to an intermediate and compatible value. - */ -#define IRQ_DEFAULT_PRIORITY 3 +/* Zero will allocate low/medium levels of priority (ESP_INTR_FLAG_LOWMED) */ +#define IRQ_DEFAULT_PRIORITY 0 #define ESP_INTR_FLAG_SHARED (1<<8) /* Interrupt can be shared between ISRs */ diff --git a/include/zephyr/dt-bindings/interrupt-controller/esp-xtensa-intmux.h b/include/zephyr/dt-bindings/interrupt-controller/esp-xtensa-intmux.h index 32194e69a48..4d644af20bb 100644 --- a/include/zephyr/dt-bindings/interrupt-controller/esp-xtensa-intmux.h +++ b/include/zephyr/dt-bindings/interrupt-controller/esp-xtensa-intmux.h @@ -79,9 +79,7 @@ #define CACHE_IA_INTR_SOURCE 68 /* Cache Invalid Access, LEVEL */ #define MAX_INTR_SOURCE 69 /* total number of interrupt sources */ -/* For Xtensa architecture, zero will allocate low/medium - * levels of priority (ESP_INTR_FLAG_LOWMED) - */ +/* Zero will allocate low/medium levels of priority (ESP_INTR_FLAG_LOWMED) */ #define IRQ_DEFAULT_PRIORITY 0 #define ESP_INTR_FLAG_SHARED (1<<8) /* Interrupt can be shared between ISRs */ diff --git a/include/zephyr/dt-bindings/interrupt-controller/esp32s2-xtensa-intmux.h b/include/zephyr/dt-bindings/interrupt-controller/esp32s2-xtensa-intmux.h index 383f9a62306..34bb3429cbb 100644 --- a/include/zephyr/dt-bindings/interrupt-controller/esp32s2-xtensa-intmux.h +++ b/include/zephyr/dt-bindings/interrupt-controller/esp32s2-xtensa-intmux.h @@ -106,9 +106,7 @@ #define ICACHE_SYNC_INTR_SOURCE 94 /* instruction cache sync done, level */ #define MAX_INTR_SOURCE 95 /* total number of interrupt sources */ -/* For Xtensa architecture, zero will allocate low/medium - * levels of priority (ESP_INTR_FLAG_LOWMED) - */ +/* Zero will allocate low/medium levels of priority (ESP_INTR_FLAG_LOWMED) */ #define IRQ_DEFAULT_PRIORITY 0 #define ESP_INTR_FLAG_SHARED (1<<8) /* Interrupt can be shared between ISRs */ diff --git a/include/zephyr/dt-bindings/interrupt-controller/esp32s3-xtensa-intmux.h b/include/zephyr/dt-bindings/interrupt-controller/esp32s3-xtensa-intmux.h index 87c690606f6..ae6f7760e58 100644 --- a/include/zephyr/dt-bindings/interrupt-controller/esp32s3-xtensa-intmux.h +++ b/include/zephyr/dt-bindings/interrupt-controller/esp32s3-xtensa-intmux.h @@ -104,9 +104,7 @@ #define DMA_EXTMEM_REJECT_SOURCE 98 #define MAX_INTR_SOURCE 99 /* number of interrupt sources */ -/* For Xtensa architecture, zero will allocate low/medium - * levels of priority (ESP_INTR_FLAG_LOWMED) - */ +/* Zero will allocate low/medium levels of priority (ESP_INTR_FLAG_LOWMED) */ #define IRQ_DEFAULT_PRIORITY 0 #define ESP_INTR_FLAG_SHARED (1<<8) /* Interrupt can be shared between ISRs */