diff --git a/arch/xtensa/include/esp32s3/irq.h b/arch/xtensa/include/esp32s3/irq.h index b379a228964..1d6016b6792 100644 --- a/arch/xtensa/include/esp32s3/irq.h +++ b/arch/xtensa/include/esp32s3/irq.h @@ -307,7 +307,7 @@ #define ESP32S3_NIRQS_SREG2 32 #define ESP32S3_IRQ_USB_DEVICE (XTENSA_IRQ_FIRSTPERIPH + ESP32S3_PERIPH_USB_DEVICE) -#define ESP32S3_IRQ_PERIPH_BACKUP (XTENSA_IRQ_FIRSTPERIPH + ESP32S3_PERIPH_PERIPH_BACKUP) +#define ESP32S3_IRQ_PERIPH_BACKUP (XTENSA_IRQ_FIRSTPERIPH + ESP32S3_PERIPH_PERIPH_BACKUP) #define ESP32S3_IRQ_DMA_EXTMEM_REJECT (XTENSA_IRQ_FIRSTPERIPH + ESP32S3_PERIPH_DMA_EXTMEM_REJECT) #define ESP32S3_IRQ_SREG3 ESP32S3_IRQ_USB_DEVICE @@ -331,9 +331,54 @@ # define ESP32S3_NIRQ_GPIO 0 #endif +#ifdef CONFIG_ESP32S3_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 ESP32S3_NIRQ_RTCIO_PERIPH 21 +# define ESP32S3_NIRQ_RTCIO_TOUCHPAD 15 +# define ESP32S3_NIRQ_RTCIO (ESP32S3_NIRQ_RTCIO_PERIPH+ESP32S3_NIRQ_RTCIO_TOUCHPAD) + +# define ESP32S3_FIRST_RTCIOIRQ_PERIPH (XTENSA_NIRQ_INTERNAL+ESP32S3_NIRQ_PERIPH+ESP32S3_NIRQ_GPIO) +# define ESP32S3_LAST_RTCIOIRQ_PERIPH (ESP32S3_FIRST_RTCIOIRQ_PERIPH+ESP32S3_NIRQ_RTCIO_PERIPH-1) +# define ESP32S3_IRQ_RTC_SLP_WAKEUP (ESP32S3_FIRST_RTCIOIRQ_PERIPH+0) +# define ESP32S3_IRQ_RTC_SLP_REJECT (ESP32S3_FIRST_RTCIOIRQ_PERIPH+1) +# define ESP32S3_IRQ_RTC_SDIO_IDLE (ESP32S3_FIRST_RTCIOIRQ_PERIPH+2) +# define ESP32S3_IRQ_RTC_WDT (ESP32S3_FIRST_RTCIOIRQ_PERIPH+3) +# define ESP32S3_IRQ_RTC_TOUCH_SCAN_DONE (ESP32S3_FIRST_RTCIOIRQ_PERIPH+4) +# define ESP32S3_IRQ_RTC_ULP_CP (ESP32S3_FIRST_RTCIOIRQ_PERIPH+5) +# define ESP32S3_IRQ_RTC_TOUCH_DONE (ESP32S3_FIRST_RTCIOIRQ_PERIPH+6) +# define ESP32S3_IRQ_RTC_TOUCH_ACTIVE (ESP32S3_FIRST_RTCIOIRQ_PERIPH+7) +# define ESP32S3_IRQ_RTC_TOUCH_INACTIVE (ESP32S3_FIRST_RTCIOIRQ_PERIPH+8) +# define ESP32S3_IRQ_RTC_BROWN_OUT (ESP32S3_FIRST_RTCIOIRQ_PERIPH+9) +# define ESP32S3_IRQ_RTC_MAIN_TIMER (ESP32S3_FIRST_RTCIOIRQ_PERIPH+10) +# define ESP32S3_IRQ_RTC_SARADC1 (ESP32S3_FIRST_RTCIOIRQ_PERIPH+11) +# define ESP32S3_IRQ_RTC_TSENS (ESP32S3_FIRST_RTCIOIRQ_PERIPH+12) +# define ESP32S3_IRQ_RTC_COCPU (ESP32S3_FIRST_RTCIOIRQ_PERIPH+13) +# define ESP32S3_IRQ_RTC_SARADC2 (ESP32S3_FIRST_RTCIOIRQ_PERIPH+14) +# define ESP32S3_IRQ_RTC_SWD (ESP32S3_FIRST_RTCIOIRQ_PERIPH+15) +# define ESP32S3_IRQ_RTC_XTAL32K_DEAD (ESP32S3_FIRST_RTCIOIRQ_PERIPH+16) +# define ESP32S3_IRQ_RTC_COCPU_TRAP (ESP32S3_FIRST_RTCIOIRQ_PERIPH+17) +# define ESP32S3_IRQ_RTC_TOUCH_TIMEOUT (ESP32S3_FIRST_RTCIOIRQ_PERIPH+18) +# define ESP32S3_IRQ_RTC_GLITCH_DET (ESP32S3_FIRST_RTCIOIRQ_PERIPH+19) +# define ESP32S3_IRQ_RTC_TOUCH_APPROACH_LOOP_DONE (ESP32S3_FIRST_RTCIOIRQ_PERIPH+20) + +# define ESP32S3_FIRST_RTCIOIRQ_TOUCHPAD (ESP32S3_LAST_RTCIOIRQ_PERIPH+1) +# define ESP32S3_LAST_RTCIOIRQ_TOUCHPAD (ESP32S3_FIRST_RTCIOIRQ_TOUCHPAD+ESP32S3_NIRQ_RTCIO_TOUCHPAD-1) +# define ESP32S3_TOUCHPAD2IRQ(t) ((t) + ESP32S3_FIRST_RTCIOIRQ_TOUCHPAD) +# define ESP32S3_IRQ2TOUCHPAD(i) ((i) - ESP32S3_FIRST_RTCIOIRQ_TOUCHPAD) +#else +# define ESP32S3_NIRQ_RTCIO 0 +#endif + /* Total number of interrupts */ -#define NR_IRQS (XTENSA_NIRQ_INTERNAL + ESP32S3_NIRQ_PERIPH + ESP32S3_NIRQ_GPIO) +#define NR_IRQS (XTENSA_NIRQ_INTERNAL + ESP32S3_NIRQ_PERIPH + ESP32S3_NIRQ_GPIO + ESP32S3_NIRQ_RTCIO) /* Xtensa CPU Interrupts. * diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig index 35e0575307c..051ca64a714 100644 --- a/arch/xtensa/src/esp32s3/Kconfig +++ b/arch/xtensa/src/esp32s3/Kconfig @@ -400,6 +400,7 @@ config ESP32S3_RWDT bool "RTC Watchdog Timer" default n select ESP32S3_WDT + select ESP32S3_RTCIO_IRQ ---help--- Includes RWDT. This watchdog timer is from the RTC module. When it is selected, if the developer sets it to reset on expiration @@ -540,6 +541,13 @@ config ESP32S3_GPIO_IRQ ---help--- Enable support for interrupting GPIO pins. +config ESP32S3_RTCIO_IRQ + bool "RTC IO interrupts" + default n + ---help--- + Enable support for RTC peripherals interrupts. + + menu "SPI configuration" depends on ESP32S3_SPI diff --git a/arch/xtensa/src/esp32s3/esp32s3_irq.c b/arch/xtensa/src/esp32s3/esp32s3_irq.c index 3a7bfa9445e..65d29cc6e4f 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_irq.c +++ b/arch/xtensa/src/esp32s3/esp32s3_irq.c @@ -39,6 +39,7 @@ #include "xtensa.h" #include "esp32s3_gpio.h" +#include "esp32s3_rtc_gpio.h" #include "esp32s3_irq.h" #ifdef CONFIG_SMP #include "esp32s3_smp.h" @@ -438,6 +439,10 @@ void up_irqinitialize(void) esp32s3_gpioirqinitialize(); + /* Initialize RTCIO interrupt support */ + + esp32s3_rtcioirqinitialize(); + /* Initialize interrupt handler for the PMS violation ISR */ esp32s3_pmsirqinitialize(); diff --git a/arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.c b/arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.c index a403e0a8f48..cc415b0fab2 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.c +++ b/arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.c @@ -31,8 +31,10 @@ #include #include +#include #include "xtensa.h" +#include "esp32s3_irq.h" #include "esp32s3_rtc_gpio.h" #include "hardware/esp32s3_pinmap.h" #include "hardware/esp32s3_rtc_io.h" @@ -60,6 +62,11 @@ enum rtcio_lh_out_mode_e * Private Data ****************************************************************************/ +#ifdef CONFIG_ESP32S3_RTCIO_IRQ +static int g_rtcio_cpuint; +static uint32_t last_status; +#endif + static const uint32_t rtc_gpio_to_addr[] = { RTCIO_RTC_GPIO_PIN0_REG, @@ -96,6 +103,12 @@ static const uint32_t rtc_gpio_to_addr[] = * Description: * 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) @@ -107,6 +120,85 @@ static inline bool is_valid_rtc_gpio(uint32_t rtcio_num) * Public Functions ****************************************************************************/ +/**************************************************************************** + * 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_ESP32S3_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 < ESP32S3_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 interruption context; + * args - The arguments passed to the handler. + * + * Returned Value: + * Zero (OK). + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_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(ESP32S3_FIRST_RTCIOIRQ_PERIPH, &last_status); + + return OK; +} +#endif + /**************************************************************************** * Name: esp32s3_configrtcio * @@ -293,3 +385,113 @@ int esp32s3_configrtcio(int rtcio_num, rtcio_pinattr_t attr) return OK; } + +/**************************************************************************** + * Name: esp32s3_rtcioirqinitialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for + * RTC IRQs. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_RTCIO_IRQ +void esp32s3_rtcioirqinitialize(void) +{ + /* Setup the RTCIO interrupt. */ + + int cpu = up_cpu_index(); + g_rtcio_cpuint = esp32s3_setup_irq(cpu, ESP32S3_PERIPH_RTC_CORE, + 1, ESP32S3_CPUINT_LEVEL); + DEBUGASSERT(g_rtcio_cpuint >= 0); + + /* Attach and enable the interrupt handler */ + + DEBUGVERIFY(irq_attach(ESP32S3_IRQ_RTC_CORE, rtcio_interrupt, NULL)); + up_enable_irq(ESP32S3_IRQ_RTC_CORE); +} +#endif + +/**************************************************************************** + * Name: esp32s3_rtcioirqenable + * + * Description: + * Enable the interrupt for the specified RTC peripheral IRQ. + * + * Input Parameters: + * irq - The IRQ number. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_RTCIO_IRQ +void esp32s3_rtcioirqenable(int irq) +{ + uintptr_t regaddr = RTC_CNTL_INT_ENA_RTC_REG; + uint32_t regval; + int bit; + + DEBUGASSERT(irq >= ESP32S3_FIRST_RTCIOIRQ_PERIPH && + irq <= ESP32S3_LAST_RTCIOIRQ_PERIPH); + + /* Convert the IRQ number to the corresponding bit */ + + bit = irq - ESP32S3_FIRST_RTCIOIRQ_PERIPH; + + /* Get the address of the GPIO PIN register for this pin */ + + up_disable_irq(ESP32S3_IRQ_RTC_CORE); + + regval = getreg32(regaddr) | (UINT32_C(1) << bit); + putreg32(regval, regaddr); + + up_enable_irq(ESP32S3_IRQ_RTC_CORE); +} +#endif + +/**************************************************************************** + * Name: esp32s3_rtcioirqdisable + * + * Description: + * Disable the interrupt for the specified RTC peripheral IRQ. + * + * Input Parameters: + * irq - The IRQ number. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_RTCIO_IRQ +void esp32s3_rtcioirqdisable(int irq) +{ + uintptr_t regaddr = RTC_CNTL_INT_ENA_RTC_REG; + uint32_t regval; + int bit; + + DEBUGASSERT(irq >= ESP32S3_FIRST_RTCIOIRQ_PERIPH && + irq <= ESP32S3_LAST_RTCIOIRQ_PERIPH); + + /* Convert the IRQ number to the corresponding bit */ + + bit = irq - ESP32S3_FIRST_RTCIOIRQ_PERIPH; + + /* Disable IRQ */ + + up_disable_irq(ESP32S3_IRQ_RTC_CORE); + + regval = getreg32(regaddr) & (~(UINT32_C(1) << bit)); + putreg32(regval, regaddr); + + up_enable_irq(ESP32S3_IRQ_RTC_CORE); +} +#endif diff --git a/arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.h b/arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.h index 0bfecf3de9a..26197c56c90 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.h +++ b/arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.h @@ -575,5 +575,66 @@ static const rtc_io_desc_t g_rtc_io_desc[RTC_GPIO_NUMBER] = int esp32s3_configrtcio(int rtcio_num, rtcio_pinattr_t attr); +/**************************************************************************** + * Name: esp32s3_rtcioirqinitialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for + * RTC IRQs. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_RTCIO_IRQ +void esp32s3_rtcioirqinitialize(void); +#else +# define esp32s3_rtcioirqinitialize() +#endif + +/**************************************************************************** + * Name: esp32s3_rtcioirqenable + * + * Description: + * Enable the interrupt for the specified RTC peripheral IRQ + * + * Input Parameters: + * irq - The IRQ number. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_RTCIO_IRQ +void esp32s3_rtcioirqenable(int irq); +#else +# define esp32s3_rtcioirqenable(irq) +#endif + +/**************************************************************************** + * Name: esp32s3_rtcioirqdisable + * + * Description: + * Disable the interrupt for the specified RTC peripheral IRQ. + * + * Input Parameters: + * irq - The IRQ number. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_RTCIO_IRQ +void esp32s3_rtcioirqdisable(int irq); +#else +# define esp32s3_rtcioirqdisable(irq) +#endif + #endif /* __ASSEMBLY__ */ #endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_RTC_GPIO_H */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_wdt.c b/arch/xtensa/src/esp32s3/esp32s3_wdt.c index c957f06d78c..855a5dcae09 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_wdt.c +++ b/arch/xtensa/src/esp32s3/esp32s3_wdt.c @@ -35,6 +35,7 @@ #include "hardware/esp32s3_efuse.h" #include "esp32s3_irq.h" +#include "esp32s3_rtc_gpio.h" #include "esp32s3_wdt.h" #ifdef CONFIG_ESP32S3_RWDT @@ -168,7 +169,7 @@ struct esp32s3_wdt_priv_s g_esp32s3_rwdt_priv = .ops = &esp32s3_rwdt_ops, .base = RTC_CNTL_RTC_OPTIONS0_REG, .periph = ESP32S3_PERIPH_RTC_CORE, - .irq = ESP32S3_IRQ_RTC_CORE, + .irq = ESP32S3_IRQ_RTC_WDT, .cpuint = -ENOMEM, .inuse = false, }; @@ -636,13 +637,23 @@ static int32_t wdt_setisr(struct esp32s3_wdt_dev_s *dev, xcpt_t handler, if (wdt->cpuint >= 0) { - /* Disable CPU Interrupt, free a previously allocated - * CPU Interrupt - */ +#ifdef CONFIG_ESP32S3_RWDT + if (wdt->irq == ESP32S3_IRQ_RTC_WDT) + { + esp32s3_rtcioirqdisable(wdt->irq); + irq_detach(wdt->irq); + } + else +#endif + { + /* Disable CPU Interrupt, free a previously allocated + * CPU Interrupt + */ - up_disable_irq(wdt->irq); - esp32s3_teardown_irq(wdt->cpu, wdt->periph, wdt->cpuint); - irq_detach(wdt->irq); + up_disable_irq(wdt->irq); + esp32s3_teardown_irq(wdt->cpu, wdt->periph, wdt->cpuint); + irq_detach(wdt->irq); + } } goto errout; @@ -654,29 +665,47 @@ static int32_t wdt_setisr(struct esp32s3_wdt_dev_s *dev, xcpt_t handler, { /* Set up to receive peripheral interrupts on the current CPU */ - wdt->cpu = up_cpu_index(); - wdt->cpuint = esp32s3_setup_irq(wdt->cpu, wdt->periph, - 1, ESP32S3_CPUINT_LEVEL); - if (wdt->cpuint < 0) +#ifdef CONFIG_ESP32S3_RWDT + if (wdt->irq == ESP32S3_IRQ_RTC_WDT) { - wderr("ERROR: No CPU Interrupt available"); - ret = wdt->cpuint; - goto errout; + ret = irq_attach(wdt->irq, handler, arg); + + if (ret != OK) + { + esp32s3_rtcioirqdisable(wdt->irq); + tmrerr("ERROR: Failed to associate an IRQ Number"); + goto errout; + } + + esp32s3_rtcioirqenable(wdt->irq); } - - /* Associate an IRQ Number (from the WDT) to an ISR */ - - ret = irq_attach(wdt->irq, handler, arg); - if (ret != OK) + else +#endif { - esp32s3_teardown_irq(wdt->cpu, wdt->periph, wdt->cpuint); - wderr("ERROR: Failed to associate an IRQ Number"); - goto errout; + wdt->cpu = up_cpu_index(); + wdt->cpuint = esp32s3_setup_irq(wdt->cpu, wdt->periph, + 1, ESP32S3_CPUINT_LEVEL); + if (wdt->cpuint < 0) + { + wderr("ERROR: No CPU Interrupt available"); + ret = wdt->cpuint; + goto errout; + } + + /* Associate an IRQ Number (from the WDT) to an ISR */ + + ret = irq_attach(wdt->irq, handler, arg); + if (ret != OK) + { + esp32s3_teardown_irq(wdt->cpu, wdt->periph, wdt->cpuint); + wderr("ERROR: Failed to associate an IRQ Number"); + goto errout; + } + + /* Enable the CPU Interrupt that is linked to the WDT */ + + up_enable_irq(wdt->irq); } - - /* Enable the CPU Interrupt that is linked to the WDT */ - - up_enable_irq(wdt->irq); } errout: