arch/xtensa/esp32s2: Add support for RTC IRQs

This commit is contained in:
Lucas Saavedra Vaz 2023-02-03 16:10:19 -03:00 committed by Alan Carvalho de Assis
parent 7df663bff8
commit 1e3af48fff
6 changed files with 337 additions and 25 deletions

View File

@ -295,9 +295,53 @@
# define ESP32S2_NIRQ_GPIO 0 # define ESP32S2_NIRQ_GPIO 0
#endif #endif
#ifdef CONFIG_ESP32S2_RTCIO_IRQ
/* Second level RTC interrupts. RTC interrupts are decoded and dispatched
* as a second level of decoding: The first level dispatches to the RTC
* interrupt handler. The second to the decoded RTC interrupt handler.
* A third level might be required to be implemented on the driver (e.g.
* Touch pads)
*/
# define ESP32S2_NIRQ_RTCIO_PERIPH 20
# define ESP32S2_NIRQ_RTCIO_TOUCHPAD 15
# define ESP32S2_NIRQ_RTCIO (ESP32S2_NIRQ_RTCIO_PERIPH+ESP32S2_NIRQ_RTCIO_TOUCHPAD)
# define ESP32S2_FIRST_RTCIOIRQ_PERIPH (XTENSA_NIRQ_INTERNAL+ESP32S2_NIRQ_PERIPH+ESP32S2_NIRQ_GPIO)
# define ESP32S2_LAST_RTCIOIRQ_PERIPH (ESP32S2_FIRST_RTCIOIRQ_PERIPH+ESP32S2_NIRQ_RTCIO_PERIPH-1)
# define ESP32S2_IRQ_RTC_SLP_WAKEUP (ESP32S2_FIRST_RTCIOIRQ_PERIPH+0)
# define ESP32S2_IRQ_RTC_SLP_REJECT (ESP32S2_FIRST_RTCIOIRQ_PERIPH+1)
# define ESP32S2_IRQ_RTC_SDIO_IDLE (ESP32S2_FIRST_RTCIOIRQ_PERIPH+2)
# define ESP32S2_IRQ_RTC_WDT (ESP32S2_FIRST_RTCIOIRQ_PERIPH+3)
# define ESP32S2_IRQ_RTC_TOUCH_SCAN_DONE (ESP32S2_FIRST_RTCIOIRQ_PERIPH+4)
# define ESP32S2_IRQ_RTC_ULP_CP (ESP32S2_FIRST_RTCIOIRQ_PERIPH+5)
# define ESP32S2_IRQ_RTC_TOUCH_DONE (ESP32S2_FIRST_RTCIOIRQ_PERIPH+6)
# define ESP32S2_IRQ_RTC_TOUCH_ACTIVE (ESP32S2_FIRST_RTCIOIRQ_PERIPH+7)
# define ESP32S2_IRQ_RTC_TOUCH_INACTIVE (ESP32S2_FIRST_RTCIOIRQ_PERIPH+8)
# define ESP32S2_IRQ_RTC_BROWN_OUT (ESP32S2_FIRST_RTCIOIRQ_PERIPH+9)
# define ESP32S2_IRQ_RTC_MAIN_TIMER (ESP32S2_FIRST_RTCIOIRQ_PERIPH+10)
# define ESP32S2_IRQ_RTC_SARADC1 (ESP32S2_FIRST_RTCIOIRQ_PERIPH+11)
# define ESP32S2_IRQ_RTC_TSENS (ESP32S2_FIRST_RTCIOIRQ_PERIPH+12)
# define ESP32S2_IRQ_RTC_COCPU (ESP32S2_FIRST_RTCIOIRQ_PERIPH+13)
# define ESP32S2_IRQ_RTC_SARADC2 (ESP32S2_FIRST_RTCIOIRQ_PERIPH+14)
# define ESP32S2_IRQ_RTC_SWD (ESP32S2_FIRST_RTCIOIRQ_PERIPH+15)
# define ESP32S2_IRQ_RTC_XTAL32K_DEAD (ESP32S2_FIRST_RTCIOIRQ_PERIPH+16)
# define ESP32S2_IRQ_RTC_COCPU_TRAP (ESP32S2_FIRST_RTCIOIRQ_PERIPH+17)
# define ESP32S2_IRQ_RTC_TOUCH_TIMEOUT (ESP32S2_FIRST_RTCIOIRQ_PERIPH+18)
# define ESP32S2_IRQ_RTC_GLITCH_DET (ESP32S2_FIRST_RTCIOIRQ_PERIPH+19)
# define ESP32S2_FIRST_RTCIOIRQ_TOUCHPAD (ESP32S2_LAST_RTCIOIRQ_PERIPH+1)
# define ESP32S2_LAST_RTCIOIRQ_TOUCHPAD (ESP32S2_FIRST_RTCIOIRQ_TOUCHPAD+ESP32S2_NIRQ_RTCIO_TOUCHPAD-1)
# define ESP32S2_TOUCHPAD2IRQ(t) ((t) + ESP32S2_FIRST_RTCIOIRQ_TOUCHPAD)
# define ESP32S2_IRQ2TOUCHPAD(i) ((i) - ESP32S2_FIRST_RTCIOIRQ_TOUCHPAD)
#else
# define ESP32S2_NIRQ_RTCIO 0
#endif
/* Total number of interrupts */ /* Total number of interrupts */
#define NR_IRQS (XTENSA_NIRQ_INTERNAL + ESP32S2_NIRQ_PERIPH + ESP32S2_NIRQ_GPIO) #define NR_IRQS (XTENSA_NIRQ_INTERNAL + ESP32S2_NIRQ_PERIPH + ESP32S2_NIRQ_GPIO + ESP32S2_NIRQ_RTCIO)
/* Xtensa CPU Interrupts. /* Xtensa CPU Interrupts.
* *

View File

@ -408,6 +408,7 @@ config ESP32S2_RWDT
bool "RTC Watchdog Timer" bool "RTC Watchdog Timer"
default n default n
select ESP32S2_WDT select ESP32S2_WDT
select ESP32S2_RTCIO_IRQ
---help--- ---help---
Includes RWDT. This watchdog timer is from the RTC module. Includes RWDT. This watchdog timer is from the RTC module.
When it is selected, if the developer sets it to reset on expiration When it is selected, if the developer sets it to reset on expiration
@ -465,6 +466,12 @@ config ESP32S2_GPIO_IRQ
---help--- ---help---
Enable support for interrupting GPIO pins. Enable support for interrupting GPIO pins.
config ESP32S2_RTCIO_IRQ
bool "RTC IO interrupts"
default n
---help---
Enable support for RTC peripherals interruptions.
menu "SPI configuration" menu "SPI configuration"
depends on ESP32S2_SPI depends on ESP32S2_SPI

View File

@ -40,6 +40,7 @@
#ifdef CONFIG_ESP32S2_GPIO_IRQ #ifdef CONFIG_ESP32S2_GPIO_IRQ
#include "esp32s2_gpio.h" #include "esp32s2_gpio.h"
#endif #endif
#include "esp32s2_rtc_gpio.h"
#include "esp32s2_irq.h" #include "esp32s2_irq.h"
#include "hardware/esp32s2_soc.h" #include "hardware/esp32s2_soc.h"
#include "hardware/esp32s2_system.h" #include "hardware/esp32s2_system.h"
@ -299,6 +300,10 @@ void up_irqinitialize(void)
esp32s2_gpioirqinitialize(); esp32s2_gpioirqinitialize();
#endif #endif
/* Initialize RTCIO interrupt support */
esp32s2_rtcioirqinitialize();
#ifndef CONFIG_SUPPRESS_INTERRUPTS #ifndef CONFIG_SUPPRESS_INTERRUPTS
/* And finally, enable interrupts. Also clears PS.EXCM */ /* And finally, enable interrupts. Also clears PS.EXCM */

View File

@ -31,8 +31,10 @@
#include <sys/types.h> #include <sys/types.h>
#include <nuttx/arch.h> #include <nuttx/arch.h>
#include <nuttx/irq.h>
#include "xtensa.h" #include "xtensa.h"
#include "esp32s2_irq.h"
#include "esp32s2_rtc_gpio.h" #include "esp32s2_rtc_gpio.h"
#include "hardware/esp32s2_rtc_io.h" #include "hardware/esp32s2_rtc_io.h"
#include "hardware/esp32s2_sens.h" #include "hardware/esp32s2_sens.h"
@ -58,6 +60,11 @@ enum rtcio_lh_out_mode_e
* Private Data * Private Data
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_ESP32S2_RTCIO_IRQ
static int g_rtcio_cpuint;
static uint32_t last_status;
#endif
static const uint32_t rtc_gpio_to_addr[] = static const uint32_t rtc_gpio_to_addr[] =
{ {
RTCIO_RTC_GPIO_PIN0_REG, RTCIO_RTC_GPIO_PIN0_REG,
@ -94,6 +101,12 @@ static const uint32_t rtc_gpio_to_addr[] =
* Description: * Description:
* Determine if the specified rtcio_num is a valid RTC GPIO. * Determine if the specified rtcio_num is a valid RTC GPIO.
* *
* Input Parameters:
* rtcio_num - RTC GPIO to be checked.
*
* Returned Value:
* True if valid. False otherwise.
*
****************************************************************************/ ****************************************************************************/
static inline bool is_valid_rtc_gpio(uint32_t rtcio_num) static inline bool is_valid_rtc_gpio(uint32_t rtcio_num)
@ -101,6 +114,85 @@ static inline bool is_valid_rtc_gpio(uint32_t rtcio_num)
return (rtcio_num < RTC_GPIO_NUMBER); return (rtcio_num < RTC_GPIO_NUMBER);
} }
/****************************************************************************
* Name: rtcio_dispatch
*
* Description:
* Second level dispatch for the RTC interrupt.
*
* Input Parameters:
* irq - The IRQ number;
* reg_status - Pointer to a copy of the interrupt status register.
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef CONFIG_ESP32S2_RTCIO_IRQ
static void rtcio_dispatch(int irq, uint32_t *reg_status)
{
uint32_t status = *reg_status;
uint32_t mask;
int i;
/* Check each bit in the status register */
for (i = 0; i < ESP32S2_NIRQ_RTCIO_PERIPH && status != 0; i++)
{
/* Check if there is an interrupt pending for this type */
mask = (UINT32_C(1) << i);
if ((status & mask) != 0)
{
/* Yes... perform the second level dispatch. The IRQ context will
* contain the contents of the status register.
*/
irq_dispatch(irq + i, (void *)reg_status);
/* Clear the bit in the status so that we might execute this loop
* sooner.
*/
status &= ~mask;
}
}
}
#endif
/****************************************************************************
* Name: rtcio_interrupt
*
* Description:
* RTC interrupt handler.
*
* Input Parameters:
* irq - The IRQ number;
* context - The interrupt context;
* args - The arguments passed to the handler.
*
* Returned Value:
* Zero (OK).
*
****************************************************************************/
#ifdef CONFIG_ESP32S2_RTCIO_IRQ
static int rtcio_interrupt(int irq, void *context, void *arg)
{
/* Read and clear the lower RTC interrupt status */
last_status = getreg32(RTC_CNTL_INT_ST_RTC_REG);
putreg32(last_status, RTC_CNTL_INT_CLR_RTC_REG);
/* Dispatch pending interrupts in the RTC status register */
rtcio_dispatch(ESP32S2_FIRST_RTCIOIRQ_PERIPH, &last_status);
return OK;
}
#endif
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
@ -249,3 +341,94 @@ int esp32s2_configrtcio(int rtcio_num, rtcio_pinattr_t attr)
return OK; return OK;
} }
/****************************************************************************
* Name: esp32s2_rtcioirqinitialize
*
* Description:
* Initialize logic to support a second level of interrupt decoding for
* RTC interrupts.
*
****************************************************************************/
#ifdef CONFIG_ESP32S2_RTCIO_IRQ
void esp32s2_rtcioirqinitialize(void)
{
/* Setup the RTCIO interrupt. */
g_rtcio_cpuint = esp32s2_setup_irq(ESP32S2_PERIPH_RTC_CORE,
1, ESP32S2_CPUINT_LEVEL);
DEBUGASSERT(g_rtcio_cpuint >= 0);
/* Attach and enable the interrupt handler */
DEBUGVERIFY(irq_attach(ESP32S2_IRQ_RTC_CORE, rtcio_interrupt, NULL));
up_enable_irq(ESP32S2_IRQ_RTC_CORE);
}
#endif
/****************************************************************************
* Name: esp32s2_rtcioirqenable
*
* Description:
* Enable the interrupt for a specified RTC IRQ
*
****************************************************************************/
#ifdef CONFIG_ESP32S2_RTCIO_IRQ
void esp32s2_rtcioirqenable(int irq)
{
uintptr_t regaddr = RTC_CNTL_INT_ENA_RTC_REG;
uint32_t regval;
int bit;
DEBUGASSERT(irq >= ESP32S2_FIRST_RTCIOIRQ_PERIPH &&
irq <= ESP32S2_LAST_RTCIOIRQ_PERIPH);
/* Convert the IRQ number to the corresponding bit */
bit = irq - ESP32S2_FIRST_RTCIOIRQ_PERIPH;
/* Get the address of the GPIO PIN register for this pin */
up_disable_irq(ESP32S2_IRQ_RTC_CORE);
regval = getreg32(regaddr) | (UINT32_C(1) << bit);
putreg32(regval, regaddr);
up_enable_irq(ESP32S2_IRQ_RTC_CORE);
}
#endif
/****************************************************************************
* Name: esp32s2_rtcioirqdisable
*
* Description:
* Disable the interrupt for a specified RTC IRQ
*
****************************************************************************/
#ifdef CONFIG_ESP32S2_RTCIO_IRQ
void esp32s2_rtcioirqdisable(int irq)
{
uintptr_t regaddr = RTC_CNTL_INT_ENA_RTC_REG;
uint32_t regval;
int bit;
DEBUGASSERT(irq >= ESP32S2_FIRST_RTCIOIRQ_PERIPH &&
irq <= ESP32S2_LAST_RTCIOIRQ_PERIPH);
/* Convert the IRQ number to the corresponding bit */
bit = irq - ESP32S2_FIRST_RTCIOIRQ_PERIPH;
/* Disable IRQ */
up_disable_irq(ESP32S2_IRQ_RTC_CORE);
regval = getreg32(regaddr) & (~(UINT32_C(1) << bit));
putreg32(regval, regaddr);
up_enable_irq(ESP32S2_IRQ_RTC_CORE);
}
#endif

View File

@ -574,5 +574,48 @@ static const rtc_io_desc_t g_rtc_io_desc[RTC_GPIO_NUMBER] =
int esp32s2_configrtcio(int rtcio_num, rtcio_pinattr_t attr); int esp32s2_configrtcio(int rtcio_num, rtcio_pinattr_t attr);
/****************************************************************************
* Name: esp32s2_rtcioirqinitialize
*
* Description:
* Initialize logic to support a second level of interrupt decoding for
* RTC IRQs.
*
****************************************************************************/
#ifdef CONFIG_ESP32S2_RTCIO_IRQ
void esp32s2_rtcioirqinitialize(void);
#else
# define esp32s2_rtcioirqinitialize()
#endif
/****************************************************************************
* Name: esp32s2_rtcioirqenable
*
* Description:
* Enable the interrupt for the specified RTC peripheral IRQ
*
****************************************************************************/
#ifdef CONFIG_ESP32S2_RTCIO_IRQ
void esp32s2_rtcioirqenable(int irq);
#else
# define esp32s2_rtcioirqenable(irq)
#endif
/****************************************************************************
* Name: esp32s2_rtcioirqdisable
*
* Description:
* Disable the interrupt for the specified RTC peripheral IRQ
*
****************************************************************************/
#ifdef CONFIG_ESP32S2_RTCIO_IRQ
void esp32s2_rtcioirqdisable(int irq);
#else
# define esp32s2_rtcioirqdisable(irq)
#endif
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_RTC_GPIO_H */ #endif /* __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_RTC_GPIO_H */

View File

@ -31,6 +31,7 @@
#include "xtensa.h" #include "xtensa.h"
#include "esp32s2_irq.h" #include "esp32s2_irq.h"
#include "esp32s2_rtc_gpio.h"
#include "esp32s2_wdt.h" #include "esp32s2_wdt.h"
#include "hardware/esp32s2_efuse.h" #include "hardware/esp32s2_efuse.h"
#include "hardware/esp32s2_rtccntl.h" #include "hardware/esp32s2_rtccntl.h"
@ -166,7 +167,7 @@ struct esp32s2_wdt_priv_s g_esp32s2_rwdt_priv =
.ops = &esp32s2_rwdt_ops, .ops = &esp32s2_rwdt_ops,
.base = RTC_CNTL_OPTIONS0_REG, .base = RTC_CNTL_OPTIONS0_REG,
.periph = ESP32S2_PERIPH_RTC_CORE, .periph = ESP32S2_PERIPH_RTC_CORE,
.irq = ESP32S2_IRQ_RTC_CORE, .irq = ESP32S2_IRQ_RTC_WDT,
.cpuint = -ENOMEM, .cpuint = -ENOMEM,
.inuse = false, .inuse = false,
}; };
@ -634,6 +635,15 @@ static int32_t wdt_setisr(struct esp32s2_wdt_dev_s *dev, xcpt_t handler,
if (wdt->cpuint >= 0) if (wdt->cpuint >= 0)
{ {
#ifdef CONFIG_ESP32S2_RWDT
if (wdt->irq == ESP32S2_IRQ_RTC_WDT)
{
esp32s2_rtcioirqdisable(wdt->irq);
irq_detach(wdt->irq);
}
else
#endif
{
/* Disable CPU Interrupt, free a previously allocated /* Disable CPU Interrupt, free a previously allocated
* CPU Interrupt * CPU Interrupt
*/ */
@ -642,6 +652,7 @@ static int32_t wdt_setisr(struct esp32s2_wdt_dev_s *dev, xcpt_t handler,
esp32s2_teardown_irq(wdt->periph, wdt->cpuint); esp32s2_teardown_irq(wdt->periph, wdt->cpuint);
irq_detach(wdt->irq); irq_detach(wdt->irq);
} }
}
goto errout; goto errout;
} }
@ -652,7 +663,25 @@ static int32_t wdt_setisr(struct esp32s2_wdt_dev_s *dev, xcpt_t handler,
{ {
/* Set up to receive peripheral interrupts on the current CPU */ /* Set up to receive peripheral interrupts on the current CPU */
wdt->cpuint = esp32s2_setup_irq(wdt->periph, 1, ESP32S2_CPUINT_LEVEL); #ifdef CONFIG_ESP32S2_RWDT
if (wdt->irq == ESP32S2_IRQ_RTC_WDT)
{
ret = irq_attach(wdt->irq, handler, arg);
if (ret != OK)
{
esp32s2_rtcioirqdisable(wdt->irq);
tmrerr("ERROR: Failed to associate an IRQ Number");
goto errout;
}
esp32s2_rtcioirqenable(wdt->irq);
}
else
#endif
{
wdt->cpuint = esp32s2_setup_irq(wdt->periph, 1,
ESP32S2_CPUINT_LEVEL);
if (wdt->cpuint < 0) if (wdt->cpuint < 0)
{ {
wderr("ERROR: No CPU Interrupt available"); wderr("ERROR: No CPU Interrupt available");
@ -674,6 +703,7 @@ static int32_t wdt_setisr(struct esp32s2_wdt_dev_s *dev, xcpt_t handler,
up_enable_irq(wdt->irq); up_enable_irq(wdt->irq);
} }
}
errout: errout:
return ret; return ret;