mirror of
https://github.com/apache/nuttx.git
synced 2026-05-22 22:20:01 +08:00
arch/xtensa: add non-iram interrupt support for ESP32-S2
Adds support for enabling and disabling non-iram interrupts on ESP32-S2. Signed-off-by: Filipe Cavalcanti <filipe.cavalcanti@espressif.com>
This commit is contained in:
committed by
Matteo Golin
parent
02bfd290ac
commit
7297ecc02e
@@ -39,6 +39,16 @@
|
||||
|
||||
#define ESP32S2_INT_PRIO_DEF 1
|
||||
|
||||
/* CPU interrupt flags:
|
||||
* These flags can be used to specify which interrupt qualities the
|
||||
* code calling esp32s3_setup_irq needs.
|
||||
*/
|
||||
|
||||
#define ESP32S2_CPUINT_FLAG_LEVEL (1 << 0) /* Level-triggered interrupt */
|
||||
#define ESP32S2_CPUINT_FLAG_EDGE (1 << 1) /* Edge-triggered interrupt */
|
||||
#define ESP32S2_CPUINT_FLAG_SHARED (1 << 2) /* Interrupt can be shared between ISRs */
|
||||
#define ESP32S2_CPUINT_FLAG_IRAM (1 << 3) /* ISR can be called if cache is disabled */
|
||||
|
||||
/* Interrupt Matrix
|
||||
*
|
||||
* The Interrupt Matrix embedded in the ESP32-S2 independently allocates
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <nuttx/board.h>
|
||||
#include <arch/irq.h>
|
||||
#include <arch/board/board.h>
|
||||
#include <irq/irq.h>
|
||||
|
||||
#include "xtensa.h"
|
||||
#ifdef CONFIG_ESP32S2_GPIO_IRQ
|
||||
@@ -101,6 +102,24 @@ static volatile uint8_t g_irqmap[NR_IRQS];
|
||||
|
||||
static uint32_t g_intenable;
|
||||
|
||||
/* g_non_iram_int_mask is a bitmask of the interrupts that should be
|
||||
* disabled during a SPI flash operation. Non-IRAM interrupts should always
|
||||
* be disabled, but interrupts place on IRAM are able to run during a SPI
|
||||
* flash operation.
|
||||
*/
|
||||
|
||||
static uint32_t g_non_iram_int_mask;
|
||||
|
||||
/* g_non_iram_int_disabled[] keeps track of the interrupts disabled during
|
||||
* a SPI flash operation.
|
||||
*/
|
||||
|
||||
static uint32_t g_non_iram_int_disabled;
|
||||
|
||||
/* Flag to indicate that non-IRAM interrupts were disabled */
|
||||
|
||||
static bool g_non_iram_int_disabled_flag;
|
||||
|
||||
/* Bitsets for free, unallocated CPU interrupts available to peripheral
|
||||
* devices.
|
||||
*/
|
||||
@@ -286,6 +305,9 @@ static void esp32s2_free_cpuint(int cpuint)
|
||||
void up_irqinitialize(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
g_non_iram_int_mask = UINT32_MAX;
|
||||
|
||||
for (i = 0; i < NR_IRQS; i++)
|
||||
{
|
||||
g_irqmap[i] = IRQ_UNMAPPED;
|
||||
@@ -399,6 +421,21 @@ void up_enable_irq(int irq)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if the registered ISR for this IRQ is intended to be run from
|
||||
* IRAM. If so, check if its interrupt handler is located in IRAM.
|
||||
*/
|
||||
|
||||
bool isr_in_iram = !((g_non_iram_int_mask & (1 << cpuint)) > 0);
|
||||
|
||||
xcpt_t handler = g_irqvector[irq].handler;
|
||||
|
||||
if (isr_in_iram && handler && !esp32s2_ptr_iram(handler))
|
||||
{
|
||||
irqerr("Interrupt handler isn't in IRAM (%08" PRIxPTR ")",
|
||||
(intptr_t)handler);
|
||||
PANIC();
|
||||
}
|
||||
|
||||
/* For peripheral interrupts, attach the interrupt to the peripheral;
|
||||
* the CPU interrupt was already enabled when allocated.
|
||||
*/
|
||||
@@ -481,7 +518,9 @@ int esp32s2_cpuint_initialize(void)
|
||||
* periphid - The peripheral number from irq.h to be assigned to
|
||||
* a CPU interrupt.
|
||||
* priority - Interrupt's priority (1 - 5).
|
||||
* type - Interrupt's type (level or edge).
|
||||
* flags - An ORred mask of the ESP32S3_CPUINT_FLAG_* defines. These
|
||||
* restrict the choice of interrupts that this routine can
|
||||
* choose from.
|
||||
*
|
||||
* Returned Value:
|
||||
* The allocated CPU interrupt on success, a negated errno value on
|
||||
@@ -489,12 +528,22 @@ int esp32s2_cpuint_initialize(void)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32s2_setup_irq(int periphid, int priority, int type)
|
||||
int esp32s2_setup_irq(int periphid, int priority, int flags)
|
||||
{
|
||||
irqstate_t irqstate;
|
||||
uintptr_t regaddr;
|
||||
int irq;
|
||||
int cpuint;
|
||||
int type;
|
||||
|
||||
if ((flags & ESP32S2_CPUINT_EDGE) != 0)
|
||||
{
|
||||
type = ESP32S2_CPUINT_EDGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = ESP32S2_CPUINT_LEVEL;
|
||||
}
|
||||
|
||||
irqstate = enter_critical_section();
|
||||
|
||||
@@ -524,6 +573,15 @@ int esp32s2_setup_irq(int periphid, int priority, int type)
|
||||
g_irqmap[irq] = cpuint;
|
||||
regaddr = CORE_MAP_REGADDR(periphid);
|
||||
|
||||
if ((flags & ESP32S2_CPUINT_FLAG_IRAM) != 0)
|
||||
{
|
||||
esp32s2_irq_set_iram_isr(irq);
|
||||
}
|
||||
else
|
||||
{
|
||||
esp32s2_irq_unset_iram_isr(irq);
|
||||
}
|
||||
|
||||
putreg32(cpuint, regaddr);
|
||||
|
||||
leave_critical_section(irqstate);
|
||||
@@ -649,3 +707,162 @@ uint32_t *xtensa_int_decode(uint32_t *cpuints, uint32_t *regs)
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_irq_noniram_disable
|
||||
*
|
||||
* Description:
|
||||
* Disable interrupts that aren't specifically marked as running from IRAM
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void esp32s2_irq_noniram_disable(void)
|
||||
{
|
||||
irqstate_t irqstate;
|
||||
uint32_t mask;
|
||||
int bit;
|
||||
uint32_t oldint;
|
||||
uint32_t non_iram_ints;
|
||||
|
||||
irqstate = enter_critical_section();
|
||||
non_iram_ints = g_non_iram_int_mask;
|
||||
|
||||
ASSERT(!g_non_iram_int_disabled_flag);
|
||||
|
||||
g_non_iram_int_disabled_flag = true;
|
||||
oldint = g_intenable;
|
||||
|
||||
for (bit = 0; bit < ESP32S2_NCPUINTS; bit++)
|
||||
{
|
||||
mask = 1 << bit;
|
||||
if ((non_iram_ints & mask) != 0)
|
||||
{
|
||||
xtensa_disable_cpuint(&g_intenable, bit);
|
||||
}
|
||||
}
|
||||
|
||||
g_non_iram_int_disabled = oldint & non_iram_ints;
|
||||
|
||||
leave_critical_section(irqstate);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_irq_noniram_enable
|
||||
*
|
||||
* Description:
|
||||
* Re-enable interrupts disabled by esp32s2_irq_noniram_disable
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void esp32s2_irq_noniram_enable(void)
|
||||
{
|
||||
irqstate_t irqstate;
|
||||
uint32_t mask;
|
||||
int bit;
|
||||
uint32_t non_iram_ints;
|
||||
|
||||
irqstate = enter_critical_section();
|
||||
non_iram_ints = g_non_iram_int_disabled;
|
||||
|
||||
ASSERT(g_non_iram_int_disabled_flag);
|
||||
|
||||
g_non_iram_int_disabled_flag = false;
|
||||
|
||||
for (bit = 0; bit < ESP32S2_NCPUINTS; bit++)
|
||||
{
|
||||
mask = 1 << bit;
|
||||
if ((non_iram_ints & mask) != 0)
|
||||
{
|
||||
xtensa_enable_cpuint(&g_intenable, bit);
|
||||
}
|
||||
}
|
||||
|
||||
leave_critical_section(irqstate);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_irq_noniram_status
|
||||
*
|
||||
* Description:
|
||||
* Get the current status of non-IRAM interrupts on a specific CPU core
|
||||
*
|
||||
* Input Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returned Value:
|
||||
* True if non-IRAM interrupts are enabled. False otherwise.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool esp32s2_irq_noniram_status()
|
||||
{
|
||||
return !g_non_iram_int_disabled_flag;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_irq_set_iram_isr
|
||||
*
|
||||
* Description:
|
||||
* Set the ISR associated to an IRQ as a IRAM-enabled ISR.
|
||||
*
|
||||
* Input Parameters:
|
||||
* irq - The associated IRQ to set
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; A negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32s2_irq_set_iram_isr(int irq)
|
||||
{
|
||||
int cpuint = CPUINT_GETIRQ(g_cpu_intmap[irq]);
|
||||
|
||||
if (cpuint == IRQ_UNMAPPED)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
g_non_iram_int_mask &= ~(1 << cpuint);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_irq_unset_iram_isr
|
||||
*
|
||||
* Description:
|
||||
* Set the ISR associated to an IRQ as a non-IRAM ISR.
|
||||
*
|
||||
* Input Parameters:
|
||||
* irq - The associated IRQ to set
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; A negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32s2_irq_unset_iram_isr(int irq)
|
||||
{
|
||||
int cpuint = CPUINT_GETIRQ(g_cpu_intmap[irq]);
|
||||
|
||||
if (cpuint == IRQ_UNMAPPED)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
g_non_iram_int_mask |= (1 << cpuint);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ extern "C"
|
||||
|
||||
/* CPU interrupt types. */
|
||||
|
||||
#define ESP32S2_CPUINT_LEVEL 0
|
||||
#define ESP32S2_CPUINT_EDGE 1
|
||||
#define ESP32S2_CPUINT_LEVEL ESP32S2_CPUINT_FLAG_LEVEL
|
||||
#define ESP32S2_CPUINT_EDGE ESP32S2_CPUINT_FLAG_EDGE
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions Prototypes
|
||||
@@ -81,7 +81,9 @@ int esp32s2_cpuint_initialize(void);
|
||||
* periphid - The peripheral number from irq.h to be assigned to
|
||||
* a CPU interrupt.
|
||||
* priority - Interrupt's priority (1 - 5).
|
||||
* type - Interrupt's type (level or edge).
|
||||
* flags - An ORred mask of the ESP32S3_CPUINT_FLAG_* defines. These
|
||||
* restrict the choice of interrupts that this routine can
|
||||
* choose from.
|
||||
*
|
||||
* Returned Value:
|
||||
* The allocated CPU interrupt on success, a negated errno value on
|
||||
@@ -89,7 +91,7 @@ int esp32s2_cpuint_initialize(void);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32s2_setup_irq(int periphid, int priority, int type);
|
||||
int esp32s2_setup_irq(int periphid, int priority, int flags);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_teardown_irq
|
||||
@@ -112,6 +114,86 @@ int esp32s2_setup_irq(int periphid, int priority, int type);
|
||||
|
||||
void esp32s2_teardown_irq(int periphid, int cpuint);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_irq_noniram_disable
|
||||
*
|
||||
* Description:
|
||||
* Disable interrupts that aren't specifically marked as running from IRAM
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void esp32s2_irq_noniram_disable(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_irq_noniram_enable
|
||||
*
|
||||
* Description:
|
||||
* Re-enable interrupts disabled by esp32s2_irq_noniram_disable
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void esp32s2_irq_noniram_enable(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_irq_noniram_status
|
||||
*
|
||||
* Description:
|
||||
* Get the current status of non-IRAM interrupts.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returned Value:
|
||||
* True if non-IRAM interrupts are enabled, false otherwise.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool esp32s2_irq_noniram_status(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_irq_set_iram_isr
|
||||
*
|
||||
* Description:
|
||||
* Set the ISR associated to an IRQ as a IRAM-enabled ISR.
|
||||
*
|
||||
* Input Parameters:
|
||||
* irq - The associated IRQ to set
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; A negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32s2_irq_set_iram_isr(int irq);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_irq_unset_iram_isr
|
||||
*
|
||||
* Description:
|
||||
* Set the ISR associated to an IRQ as a non-IRAM ISR.
|
||||
*
|
||||
* Input Parameters:
|
||||
* irq - The associated IRQ to set
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; A negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32s2_irq_unset_iram_isr(int irq);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
||||
@@ -433,6 +433,19 @@ static inline bool IRAM_ATTR esp32s2_ptr_extram(const void *p)
|
||||
(intptr_t)p < SOC_EXTRAM_DATA_HIGH);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_ptr_iram
|
||||
*
|
||||
* Description:
|
||||
* Check if the pointer is in IRAM
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline bool IRAM_ATTR esp32s2_ptr_iram(const void *p)
|
||||
{
|
||||
return ((intptr_t)p >= SOC_IRAM_LOW && (intptr_t)p < SOC_IRAM_HIGH);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s2_ptr_exec
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user