interrupt_controller: intc_esp32c3: added intc driver

For esp32c3 and replaces the hardcoded interrupt
attaching procedures with this new driver.

Signed-off-by: Felipe Neves <felipe.neves@espressif.com>
diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt
index 41f3578..c696633 100644
--- a/drivers/interrupt_controller/CMakeLists.txt
+++ b/drivers/interrupt_controller/CMakeLists.txt
@@ -23,5 +23,6 @@
 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 82915b8..9719686 100644
--- a/drivers/interrupt_controller/Kconfig
+++ b/drivers/interrupt_controller/Kconfig
@@ -69,6 +69,8 @@
 
 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 0000000..1022dec
--- /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 0000000..4883841
--- /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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <soc/periph_defs.h>
+#include <limits.h>
+#include <assert.h>
+#include "soc/soc.h"
+#include <soc.h>
+#include <zephyr.h>
+#include <drivers/interrupt_controller/intc_esp32c3.h>
+#include <sw_isr_table.h>
+
+#include <logging/log.h>
+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 65755af..1d087af 100644
--- a/drivers/timer/esp32c3_sys_timer.c
+++ b/drivers/timer/esp32c3_sys_timer.c
@@ -13,12 +13,11 @@
 #include <rom/ets_sys.h>
 #include <esp_attr.h>
 
+#include <drivers/interrupt_controller/intc_esp32c3.h>
 #include <drivers/timer/system_timer.h>
 #include <sys_clock.h>
 #include <soc.h>
 
-#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 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 @@
 {
 	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 0000000..761f1df
--- /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 <stdint.h>
+#include <stdbool.h>
+#include <soc.h>
+/*
+ * 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<<level) */
+#define ESP_INTR_FLAG_LEVEL1		(1<<1)	/* Accept a Level 1 int vector, lowest priority */
+#define ESP_INTR_FLAG_EDGE		    (1<<9)	/* Edge-triggered interrupt */
+
+/* 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
diff --git a/soc/riscv/esp32c3/CMakeLists.txt b/soc/riscv/esp32c3/CMakeLists.txt
index b2fd9e6..f66f57c 100644
--- a/soc/riscv/esp32c3/CMakeLists.txt
+++ b/soc/riscv/esp32c3/CMakeLists.txt
@@ -4,5 +4,6 @@
   idle.c
   vectors.S
   soc_irq.S
+  soc_irq.c
   soc.c
   )
diff --git a/soc/riscv/esp32c3/Kconfig.defconfig b/soc/riscv/esp32c3/Kconfig.defconfig
index f400b93..ca2c54e 100644
--- a/soc/riscv/esp32c3/Kconfig.defconfig
+++ b/soc/riscv/esp32c3/Kconfig.defconfig
@@ -9,7 +9,7 @@
 	default "esp32c3"
 
 config NUM_IRQS
-	default 32
+	default 62
 
 config GEN_ISR_TABLES
 	default y
diff --git a/soc/riscv/esp32c3/soc.c b/soc/riscv/esp32c3/soc.c
index c0da3a2..197c089 100644
--- a/soc/riscv/esp32c3/soc.c
+++ b/soc/riscv/esp32c3/soc.c
@@ -13,18 +13,15 @@
 #include <soc/cache_memory.h>
 #include "hal/soc_ll.h"
 #include "esp_spi_flash.h"
-#include <riscv/interrupt.h>
 #include <soc/interrupt_reg.h>
+#include <drivers/interrupt_controller/intc_esp32c3.h>
 
 #include <kernel_structs.h>
 #include <string.h>
 #include <toolchain/gcc.h>
 #include <soc.h>
 
-#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 @@
 	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 @@
 {
 	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 6e2cf0a..76a3cb8 100644
--- a/soc/riscv/esp32c3/soc.h
+++ b/soc/riscv/esp32c3/soc.h
@@ -41,6 +41,8 @@
 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 7edbe13..9054b17 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 @@
 	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 0000000..461c8c5
--- /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 <soc/rtc_cntl_reg.h>
+#include <soc/timer_group_reg.h>
+#include <soc/gpio_reg.h>
+#include <soc/syscon_reg.h>
+#include <soc/system_reg.h>
+#include <soc/cache_memory.h>
+#include "hal/soc_ll.h"
+#include <riscv/interrupt.h>
+#include <soc/interrupt_reg.h>
+#include <soc/periph_defs.h>
+#include <drivers/interrupt_controller/intc_esp32c3.h>
+
+#include <kernel_structs.h>
+#include <string.h>
+#include <toolchain/gcc.h>
+#include <soc.h>
+
+#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;
+}