This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new d7b66adbeb arch/xtensa/esp32s3: Add support for RTC IRQs
d7b66adbeb is described below
commit d7b66adbeb3928f0c2abc035169921cc68b2993a
Author: Lucas Saavedra Vaz <[email protected]>
AuthorDate: Tue Feb 7 16:34:59 2023 -0300
arch/xtensa/esp32s3: Add support for RTC IRQs
---
arch/xtensa/include/esp32s3/irq.h | 49 ++++++-
arch/xtensa/src/esp32s3/Kconfig | 8 ++
arch/xtensa/src/esp32s3/esp32s3_irq.c | 5 +
arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.c | 202 +++++++++++++++++++++++++++++
arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.h | 61 +++++++++
arch/xtensa/src/esp32s3/esp32s3_wdt.c | 81 ++++++++----
6 files changed, 378 insertions(+), 28 deletions(-)
diff --git a/arch/xtensa/include/esp32s3/irq.h
b/arch/xtensa/include/esp32s3/irq.h
index b379a22896..1d6016b679 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 35e0575307..051ca64a71 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 3a7bfa9445..65d29cc6e4 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 a403e0a8f4..cc415b0fab 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_rtc_gpio.c
@@ -31,8 +31,10 @@
#include <sys/types.h>
#include <nuttx/arch.h>
+#include <nuttx/irq.h>
#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 0bfecf3de9..26197c56c9 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 c957f06d78..855a5dcae0 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
- */
-
- up_disable_irq(wdt->irq);
- esp32s3_teardown_irq(wdt->cpu, wdt->periph, wdt->cpuint);
- irq_detach(wdt->irq);
+#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);
+ }
}
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);
- /* Associate an IRQ Number (from the WDT) to an ISR */
+ if (ret != OK)
+ {
+ esp32s3_rtcioirqdisable(wdt->irq);
+ tmrerr("ERROR: Failed to associate an IRQ Number");
+ goto errout;
+ }
- ret = irq_attach(wdt->irq, handler, arg);
- if (ret != OK)
+ esp32s3_rtcioirqenable(wdt->irq);
+ }
+ 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: