diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 41f3578131c..c6966334ca7 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -23,5 +23,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) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index 82915b8fd26..97196869703 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -69,6 +69,8 @@ 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" endmenu diff --git a/drivers/interrupt_controller/Kconfig.esp32c3 b/drivers/interrupt_controller/Kconfig.esp32c3 new file mode 100644 index 00000000000..1022decc8e9 --- /dev/null +++ b/drivers/interrupt_controller/Kconfig.esp32c3 @@ -0,0 +1,10 @@ +# Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config INTC_ESP32C3 + bool "Enables ESP32C3 interrupt controller driver" + depends on SOC_ESP32C3 + default y + help + Enables the esp32c3 interrupt controller driver to handle ISR + management at SoC level. diff --git a/drivers/interrupt_controller/intc_esp32c3.c b/drivers/interrupt_controller/intc_esp32c3.c new file mode 100644 index 00000000000..48838410c6e --- /dev/null +++ b/drivers/interrupt_controller/intc_esp32c3.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2021 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 +LOG_MODULE_REGISTER(intc_esp32c3, CONFIG_LOG_DEFAULT_LEVEL); + +#define ESP32C3_INTC_DEFAULT_PRIORITY 15 +#define ESP32C3_INTC_DEFAULT_THRESHOLD 1 +#define ESP32C3_INTC_DISABLED_SLOT 31 +#define ESP32C3_INTC_SRCS_PER_IRQ 2 +#define ESP32C3_INTC_AVAILABLE_IRQS 30 + +static uint32_t esp_intr_enabled_mask[2] = {0, 0}; + +static void esp_intr_default_isr(const void *arg) +{ + ARG_UNUSED(arg); + ulong_t mcause; + + __asm__ volatile("csrr %0, mcause" : "=r" (mcause)); + mcause &= SOC_MCAUSE_EXP_MASK; + + LOG_DBG("Spurious interrupt, mcause: %ld, source %d", mcause, soc_intr_get_next_source()); +} + +static uint32_t esp_intr_find_irq_for_source(uint32_t source) +{ + /* in general case, each 2 sources goes routed to + * 1 IRQ line. + */ + uint32_t irq = (source / ESP32C3_INTC_SRCS_PER_IRQ); + + if (irq > ESP32C3_INTC_AVAILABLE_IRQS) { + LOG_DBG("Clamping the source: %d no more IRQs available", source); + irq = ESP32C3_INTC_AVAILABLE_IRQS; + } else if (irq == 0) { + irq = 1; + } + + LOG_DBG("Found IRQ: %d for source: %d", irq, source); + + return irq; +} + +void esp_intr_initialize(void) +{ + /* IRQ 31 is reserved for disabled interrupts, + * so route all sources to it + */ + for (int i = 0 ; i < ESP32C3_INTC_AVAILABLE_IRQS + 2; i++) { + irq_disable(i); + } + + for (int i = 0; i < ETS_MAX_INTR_SOURCE; i++) { + esp_rom_intr_matrix_set(0, + i, + ESP32C3_INTC_DISABLED_SLOT); + + irq_connect_dynamic(i, + ESP32C3_INTC_DEFAULT_PRIORITY, + esp_intr_default_isr, + NULL, + 0); + } + + /* set global esp32c3's INTC masking level */ + esprv_intc_int_set_threshold(ESP32C3_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); + + esp_rom_intr_matrix_set(0, source, irq); + + irq_connect_dynamic(source, + ESP32C3_INTC_DEFAULT_PRIORITY, + handler, + arg, + 0); + + if (source < 32) { + esp_intr_enabled_mask[0] |= (1 << source); + } else { + esp_intr_enabled_mask[1] |= (1 << (source - 32)); + } + + LOG_DBG("Enabled isrs -- 0: 0x%X -- 1: 0x%X", + esp_intr_enabled_mask[0], esp_intr_enabled_mask[1]); + + irq_unlock(key); + irq_enable(irq); + + return 0; +} + +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(source, + source, + ESP32C3_INTC_DISABLED_SLOT); + + if (source < 32) { + esp_intr_enabled_mask[0] &= ~(1 << source); + } else { + esp_intr_enabled_mask[1] &= ~(1 << (source - 32)); + } + + LOG_DBG("Enabled isrs -- 0: 0x%X -- 1: 0x%X", + esp_intr_enabled_mask[0], esp_intr_enabled_mask[1]); + + 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); + + irq_disable(irq); + esp_rom_intr_matrix_set(0, source, irq); + + if (source < 32) { + esp_intr_enabled_mask[0] |= (1 << source); + } else { + esp_intr_enabled_mask[1] |= (1 << (source - 32)); + } + + LOG_DBG("Enabled isrs -- 0: 0x%X -- 1: 0x%X", + esp_intr_enabled_mask[0], esp_intr_enabled_mask[1]); + + irq_enable(irq); + irq_unlock(key); + + return 0; +} + +uint32_t esp_intr_get_enabled_intmask(int status_mask_number) +{ + LOG_DBG("Enabled isrs -- 0: 0x%X -- 1: 0x%X", + esp_intr_enabled_mask[0], esp_intr_enabled_mask[1]); + + if (status_mask_number == 0) { + return esp_intr_enabled_mask[0]; + } else { + return esp_intr_enabled_mask[1]; + } +} diff --git a/drivers/timer/esp32c3_sys_timer.c b/drivers/timer/esp32c3_sys_timer.c index 65755af0dbb..1d087af7fa3 100644 --- a/drivers/timer/esp32c3_sys_timer.c +++ b/drivers/timer/esp32c3_sys_timer.c @@ -13,12 +13,11 @@ #include #include +#include #include #include #include -#define SYS_TIMER_CPU_IRQ 16 - #define CYC_PER_TICK ((uint32_t)((uint64_t)sys_clock_hw_cycles_per_sec() \ / (uint64_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC)) #define MAX_CYC 0xffffffffu @@ -45,7 +44,6 @@ static uint64_t systimer_alarm(void) static void sys_timer_isr(const void *arg) { ARG_UNUSED(arg); - systimer_ll_clear_alarm_int(SYSTIMER_ALARM_0); k_spinlock_key_t key = k_spin_lock(&lock); @@ -72,17 +70,18 @@ int sys_clock_driver_init(const struct device *dev) { ARG_UNUSED(dev); - esp_rom_intr_matrix_set(0, - ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, - SYS_TIMER_CPU_IRQ); - IRQ_CONNECT(SYS_TIMER_CPU_IRQ, 0, sys_timer_isr, NULL, 0); + esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, + 0, + sys_timer_isr, + NULL, + NULL); + systimer_hal_init(); systimer_hal_connect_alarm_counter(SYSTIMER_ALARM_0, SYSTIMER_COUNTER_1); systimer_hal_enable_counter(SYSTIMER_COUNTER_1); systimer_hal_counter_can_stall_by_cpu(SYSTIMER_COUNTER_1, 0, true); last_count = systimer_alarm(); set_systimer_alarm(last_count + CYC_PER_TICK); - irq_enable(SYS_TIMER_CPU_IRQ); return 0; } diff --git a/include/drivers/interrupt_controller/intc_esp32c3.h b/include/drivers/interrupt_controller/intc_esp32c3.h new file mode 100644 index 00000000000..761f1df4286 --- /dev/null +++ b/include/drivers/interrupt_controller/intc_esp32c3.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_ESP_INTR_ALLOC_H__ +#define ZEPHYR_INCLUDE_DRIVERS_ESP_INTR_ALLOC_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< #include "hal/soc_ll.h" #include "esp_spi_flash.h" -#include #include +#include #include #include #include #include -#define ESP32C3_INTC_DEFAULT_PRIO 15 - extern void _PrepC(void); -extern void esprv_intc_int_set_threshold(int priority_threshold); /* * This is written in C rather than assembly since, during the port bring up, @@ -94,15 +91,15 @@ void __attribute__((section(".iram1"))) __start(void) esp_rom_cache_set_idrom_mmu_size(cache_mmu_irom_size, CACHE_DROM_MMU_MAX_END - cache_mmu_irom_size); - /* set global esp32c3's INTC masking level */ - esprv_intc_int_set_threshold(1); - /* Enable wireless phy subsystem clock, * This needs to be done before the kernel starts */ REG_CLR_BIT(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_SDIOSLAVE_EN); SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_EN); + /*Initialize the esp32c3 interrupt controller */ + esp_intr_initialize(); + /* Start Zephyr */ _PrepC(); @@ -167,24 +164,3 @@ void sys_arch_reboot(int type) { esp_restart_noos(); } - -void arch_irq_enable(unsigned int irq) -{ - uint32_t key = irq_lock(); - - esprv_intc_int_set_priority(irq, ESP32C3_INTC_DEFAULT_PRIO); - esprv_intc_int_set_type(irq, 0); - esprv_intc_int_enable(1 << irq); - - irq_unlock(key); -} - -void arch_irq_disable(unsigned int irq) -{ - esprv_intc_int_disable(1 << irq); -} - -int arch_irq_is_enabled(unsigned int irq) -{ - return (REG_READ(INTERRUPT_CORE0_CPU_INT_ENABLE_REG) & (1 << irq)); -} diff --git a/soc/riscv/esp32c3/soc.h b/soc/riscv/esp32c3/soc.h index 6e2cf0ab923..76a3cb878a1 100644 --- a/soc/riscv/esp32c3/soc.h +++ b/soc/riscv/esp32c3/soc.h @@ -41,6 +41,8 @@ extern void esp_rom_uart_tx_wait_idle(uint8_t uart_no); extern STATUS esp_rom_uart_tx_one_char(uint8_t chr); extern STATUS esp_rom_uart_rx_one_char(uint8_t *chr); extern void esp_rom_ets_set_user_start(uint32_t start); +extern void esprv_intc_int_set_threshold(int priority_threshold); +uint32_t soc_intr_get_next_source(void); #endif /* _ASMLANGUAGE */ diff --git a/soc/riscv/esp32c3/soc_irq.S b/soc/riscv/esp32c3/soc_irq.S index 7edbe136ee6..9054b173452 100644 --- a/soc/riscv/esp32c3/soc_irq.S +++ b/soc/riscv/esp32c3/soc_irq.S @@ -9,6 +9,7 @@ /* Exports */ GTEXT(__soc_is_irq) GTEXT(__soc_handle_irq) +GTEXT(soc_intr_get_next_source) SECTION_FUNC(exception.other, __soc_is_irq) csrr a0, mcause @@ -16,4 +17,10 @@ SECTION_FUNC(exception.other, __soc_is_irq) ret SECTION_FUNC(exception.other, __soc_handle_irq) + addi sp, sp,-4 + sw ra, 0x00(sp) + la t1, soc_intr_get_next_source + jalr ra, t1 + lw ra, 0x00(sp) + addi sp, sp, 4 ret diff --git a/soc/riscv/esp32c3/soc_irq.c b/soc/riscv/esp32c3/soc_irq.c new file mode 100644 index 00000000000..461c8c5b1f4 --- /dev/null +++ b/soc/riscv/esp32c3/soc_irq.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include "hal/soc_ll.h" +#include +#include +#include +#include + +#include +#include +#include +#include + +#define ESP32C3_INTC_DEFAULT_PRIO 15 +#define ESP32C3_INTSTATUS_SLOT1_THRESHOLD 32 + +void arch_irq_enable(unsigned int irq) +{ + uint32_t key = irq_lock(); + + esprv_intc_int_set_priority(irq, ESP32C3_INTC_DEFAULT_PRIO); + esprv_intc_int_set_type(irq, INTR_TYPE_LEVEL); + esprv_intc_int_enable(1 << irq); + irq_unlock(key); +} + +void arch_irq_disable(unsigned int irq) +{ + esprv_intc_int_disable(1 << irq); +} + +int arch_irq_is_enabled(unsigned int irq) +{ + return (REG_READ(INTERRUPT_CORE0_CPU_INT_ENABLE_REG) & (1 << irq)); +} + +uint32_t soc_intr_get_next_source(void) +{ + uint32_t status; + uint32_t source; + + status = REG_READ(INTERRUPT_CORE0_INTR_STATUS_0_REG) & + esp_intr_get_enabled_intmask(0); + + if (status) { + source = __builtin_ffs(status) - 1; + } else { + status = REG_READ(INTERRUPT_CORE0_INTR_STATUS_1_REG) & + esp_intr_get_enabled_intmask(1); + source = (__builtin_ffs(status) - 1 + ESP32C3_INTSTATUS_SLOT1_THRESHOLD); + } + + return source; +}