205 lines
4.4 KiB
C
205 lines
4.4 KiB
C
/*
|
|
* 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 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 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;
|
|
|
|
INTC_LOG("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) {
|
|
INTC_LOG("Clamping the source: %d no more IRQs available", source);
|
|
irq = ESP32C3_INTC_AVAILABLE_IRQS;
|
|
} else if (irq == 0) {
|
|
irq = 1;
|
|
}
|
|
|
|
INTC_LOG("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));
|
|
}
|
|
|
|
INTC_LOG("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));
|
|
}
|
|
|
|
INTC_LOG("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));
|
|
}
|
|
|
|
INTC_LOG("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)
|
|
{
|
|
INTC_LOG("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];
|
|
}
|
|
}
|