diff --git a/arch/risc-v/include/esp32c3/irq.h b/arch/risc-v/include/esp32c3/irq.h index 20dc46e377..b778f7859d 100644 --- a/arch/risc-v/include/esp32c3/irq.h +++ b/arch/risc-v/include/esp32c3/irq.h @@ -209,8 +209,33 @@ # define ESP32C3_NIRQ_GPIO 0 #endif -/* Total number of IRQs: ecall + Number of peripheral IRQs + GPIOs IRQs. */ +#ifdef CONFIG_ESP32C3_RTCIO_IRQ -#define NR_IRQS (RISCV_NIRQ_INTERRUPTS + ESP32C3_NIRQ_PERIPH + ESP32C3_NIRQ_GPIO) +/* 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. + */ + +# define ESP32C3_NIRQ_RTCIO 9 + +# define ESP32C3_FIRST_RTCIOIRQ (RISCV_NIRQ_INTERRUPTS+ESP32C3_NIRQ_PERIPH+ESP32C3_NIRQ_GPIO) +# define ESP32C3_LAST_RTCIOIRQ (ESP32C3_FIRST_RTCIOIRQ+ESP32C3_NIRQ_RTCIO-1) +# define ESP32C3_IRQ_RTC_SLP_WAKEUP (ESP32C3_FIRST_RTCIOIRQ+0) +# define ESP32C3_IRQ_RTC_SLP_REJECT (ESP32C3_FIRST_RTCIOIRQ+1) +# define ESP32C3_IRQ_RTC_WDT (ESP32C3_FIRST_RTCIOIRQ+2) +# define ESP32C3_IRQ_RTC_BROWN_OUT (ESP32C3_FIRST_RTCIOIRQ+3) +# define ESP32C3_IRQ_RTC_MAIN_TIMER (ESP32C3_FIRST_RTCIOIRQ+4) +# define ESP32C3_IRQ_RTC_SWD (ESP32C3_FIRST_RTCIOIRQ+5) +# define ESP32C3_IRQ_RTC_XTAL32K_DEAD (ESP32C3_FIRST_RTCIOIRQ+6) +# define ESP32C3_IRQ_RTC_GLITCH_DET (ESP32C3_FIRST_RTCIOIRQ+7) +# define ESP32C3_IRQ_RTC_BBPLL_CAL (ESP32C3_FIRST_RTCIOIRQ+8) +#else +# define ESP32C3_NIRQ_RTCIO 0 +#endif + +/* Total number of IRQs: ecall + Peripheral IRQs + GPIOs IRQs + RTCIO IRQs. */ + +#define NR_IRQS (RISCV_NIRQ_INTERRUPTS + ESP32C3_NIRQ_PERIPH + ESP32C3_NIRQ_GPIO + ESP32C3_NIRQ_RTCIO) #endif /* __ARCH_RISCV_INCLUDE_ESP32C3_IRQ_H */ diff --git a/arch/risc-v/src/esp32c3/Kconfig b/arch/risc-v/src/esp32c3/Kconfig index 1d0bee2140..a2866074d5 100644 --- a/arch/risc-v/src/esp32c3/Kconfig +++ b/arch/risc-v/src/esp32c3/Kconfig @@ -193,6 +193,12 @@ config ESP32C3_GPIO_IRQ ---help--- Enable support for interrupting GPIO pins +config ESP32C3_RTCIO_IRQ + bool "RTC IO interrupts" + default n + ---help--- + Enable support for RTC peripherals interrupts. + config ESP32C3_UART0 bool "UART0" default y @@ -279,6 +285,7 @@ config ESP32C3_RWDT bool "RTC Watchdog Timer" default n select ESP32C3_WDT + select ESP32C3_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 diff --git a/arch/risc-v/src/esp32c3/Make.defs b/arch/risc-v/src/esp32c3/Make.defs index e9a775d3df..003eeaa42e 100644 --- a/arch/risc-v/src/esp32c3/Make.defs +++ b/arch/risc-v/src/esp32c3/Make.defs @@ -36,7 +36,7 @@ CMN_ASRCS := $(filter-out riscv_vectors.S,$(CMN_ASRCS)) CHIP_CSRCS = esp32c3_allocateheap.c esp32c3_start.c esp32c3_wdt.c esp32c3_idle.c CHIP_CSRCS += esp32c3_irq.c esp32c3_libc_stubs.c -CHIP_CSRCS += esp32c3_clockconfig.c esp32c3_gpio.c +CHIP_CSRCS += esp32c3_clockconfig.c esp32c3_gpio.c esp32c3_rtc_gpio.c CHIP_CSRCS += esp32c3_lowputc.c esp32c3_serial.c CHIP_CSRCS += esp32c3_systemreset.c esp32c3_resetcause.c CHIP_CSRCS += esp32c3_uid.c esp32c3_perf.c diff --git a/arch/risc-v/src/esp32c3/esp32c3_irq.c b/arch/risc-v/src/esp32c3/esp32c3_irq.c index c27e40e2c0..888f6b35fb 100644 --- a/arch/risc-v/src/esp32c3/esp32c3_irq.c +++ b/arch/risc-v/src/esp32c3/esp32c3_irq.c @@ -40,6 +40,7 @@ #include "esp32c3.h" #include "esp32c3_attr.h" #include "esp32c3_gpio.h" +#include "esp32c3_rtc_gpio.h" #include "esp32c3_irq.h" @@ -234,6 +235,10 @@ void up_irqinitialize(void) esp32c3_gpioirqinitialize(); #endif + /* Initialize RTCIO interrupt support */ + + esp32c3_rtcioirqinitialize(); + #ifndef CONFIG_SUPPRESS_INTERRUPTS /* And finally, enable interrupts */ diff --git a/arch/risc-v/src/esp32c3/esp32c3_rtc_gpio.c b/arch/risc-v/src/esp32c3/esp32c3_rtc_gpio.c new file mode 100644 index 0000000000..a73209999e --- /dev/null +++ b/arch/risc-v/src/esp32c3/esp32c3_rtc_gpio.c @@ -0,0 +1,267 @@ +/**************************************************************************** + * arch/risc-v/src/esp32c3/esp32c3_rtc_gpio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "riscv_internal.h" +#include "esp32c3_irq.h" +#include "esp32c3_rtc_gpio.h" +#include "hardware/esp32c3_rtccntl.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_ESP32C3_RTCIO_IRQ +static int g_rtcio_cpuint; +static uint32_t last_status; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: is_valid_rtc_gpio + * + * 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) +{ + 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_ESP32C3_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 < ESP32C3_NIRQ_RTCIO && status != 0; i++) + { + /* Check if there is an interrupt pending for this type */ + + mask = (UINT32_C(1) << rtc_irq_reg_shift[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_ESP32C3_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_REG); + putreg32(last_status, RTC_CNTL_INT_CLR_REG); + + /* Dispatch pending interrupts in the RTC status register */ + + rtcio_dispatch(ESP32C3_FIRST_RTCIOIRQ, &last_status); + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32c3_rtcioirqinitialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for + * RTC IRQs. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32C3_RTCIO_IRQ +void esp32c3_rtcioirqinitialize(void) +{ + /* Setup the RTCIO interrupt. */ + + g_rtcio_cpuint = esp32c3_setup_irq(ESP32C3_PERIPH_RTC_CORE, + 1, ESP32C3_INT_LEVEL); + DEBUGASSERT(g_rtcio_cpuint >= 0); + + /* Attach and enable the interrupt handler */ + + DEBUGVERIFY(irq_attach(ESP32C3_IRQ_RTC_CORE, rtcio_interrupt, NULL)); + up_enable_irq(ESP32C3_IRQ_RTC_CORE); +} +#endif + +/**************************************************************************** + * Name: esp32c3_rtcioirqenable + * + * Description: + * Enable the interrupt for the specified RTC peripheral IRQ. + * + * Input Parameters: + * irq - The IRQ number. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32C3_RTCIO_IRQ +void esp32c3_rtcioirqenable(int irq) +{ + uintptr_t regaddr = RTC_CNTL_INT_ENA_REG; + uint32_t regval; + int bit; + + DEBUGASSERT(irq >= ESP32C3_FIRST_RTCIOIRQ && + irq <= ESP32C3_LAST_RTCIOIRQ); + + /* Convert the IRQ number to the corresponding bit */ + + bit = rtc_irq_reg_shift[irq - ESP32C3_FIRST_RTCIOIRQ]; + + /* Get the address of the GPIO PIN register for this pin */ + + up_disable_irq(ESP32C3_IRQ_RTC_CORE); + + regval = getreg32(regaddr) | (UINT32_C(1) << bit); + putreg32(regval, regaddr); + + up_enable_irq(ESP32C3_IRQ_RTC_CORE); +} +#endif + +/**************************************************************************** + * Name: esp32c3_rtcioirqdisable + * + * Description: + * Disable the interrupt for the specified RTC peripheral IRQ. + * + * Input Parameters: + * irq - The IRQ number. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32C3_RTCIO_IRQ +void esp32c3_rtcioirqdisable(int irq) +{ + uintptr_t regaddr = RTC_CNTL_INT_ENA_REG; + uint32_t regval; + int bit; + + DEBUGASSERT(irq >= ESP32C3_FIRST_RTCIOIRQ && + irq <= ESP32C3_LAST_RTCIOIRQ); + + /* Convert the IRQ number to the corresponding bit */ + + bit = rtc_irq_reg_shift[irq - ESP32C3_FIRST_RTCIOIRQ]; + + /* Disable IRQ */ + + up_disable_irq(ESP32C3_IRQ_RTC_CORE); + + regval = getreg32(regaddr) & (~(UINT32_C(1) << bit)); + putreg32(regval, regaddr); + + up_enable_irq(ESP32C3_IRQ_RTC_CORE); +} +#endif \ No newline at end of file diff --git a/arch/risc-v/src/esp32c3/esp32c3_rtc_gpio.h b/arch/risc-v/src/esp32c3/esp32c3_rtc_gpio.h new file mode 100644 index 0000000000..cccdfc216c --- /dev/null +++ b/arch/risc-v/src/esp32c3/esp32c3_rtc_gpio.h @@ -0,0 +1,149 @@ +/**************************************************************************** + * arch/risc-v/src/esp32c3/esp32c3_rtc_gpio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_ESP32C3_ESP32C3_RTC_GPIO_H +#define __ARCH_RISCV_SRC_ESP32C3_ESP32C3_RTC_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "hardware/esp32c3_rtccntl.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* RTC GPIO channels */ + +#define RTC_GPIO_NUMBER 5 + +#define RTCIO_GPIO0_CHANNEL 0 /* RTCIO_CHANNEL_0 */ +#define RTCIO_CHANNEL_0_GPIO_NUM 4 + +#define RTCIO_GPIO1_CHANNEL 1 /* RTCIO_CHANNEL_1 */ +#define RTCIO_CHANNEL_1_GPIO_NUM 5 + +#define RTCIO_GPIO2_CHANNEL 2 /* RTCIO_CHANNEL_2 */ +#define RTCIO_CHANNEL_2_GPIO_NUM 6 + +#define RTCIO_GPIO3_CHANNEL 3 /* RTCIO_CHANNEL_3 */ +#define RTCIO_CHANNEL_3_GPIO_NUM 8 + +#define RTCIO_GPIO4_CHANNEL 4 /* RTCIO_CHANNEL_4 */ +#define RTCIO_CHANNEL_4_GPIO_NUM 9 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef CONFIG_ESP32C3_RTCIO_IRQ +static const int rtc_irq_reg_shift[ESP32C3_NIRQ_RTCIO] = +{ + RTC_CNTL_SLP_WAKEUP_INT_ENA_S, + RTC_CNTL_SLP_REJECT_INT_ENA_S, + RTC_CNTL_WDT_INT_ENA_S, + RTC_CNTL_BROWN_OUT_INT_ENA_S, + RTC_CNTL_MAIN_TIMER_INT_ENA_S, + RTC_CNTL_SWD_INT_ENA_S, + RTC_CNTL_XTAL32K_DEAD_INT_ENA_S, + RTC_CNTL_GLITCH_DET_INT_ENA_S, + RTC_CNTL_BBPLL_CAL_INT_ENA_S +}; +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32c3_rtcioirqinitialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for + * RTC IRQs. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32C3_RTCIO_IRQ +void esp32c3_rtcioirqinitialize(void); +#else +# define esp32c3_rtcioirqinitialize() +#endif + +/**************************************************************************** + * Name: esp32c3_rtcioirqenable + * + * Description: + * Enable the interrupt for the specified RTC peripheral IRQ. + * + * Input Parameters: + * irq - The IRQ number. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32C3_RTCIO_IRQ +void esp32c3_rtcioirqenable(int irq); +#else +# define esp32c3_rtcioirqenable(irq) +#endif + +/**************************************************************************** + * Name: esp32c3_rtcioirqdisable + * + * Description: + * Disable the interrupt for the specified RTC peripheral IRQ. + * + * Input Parameters: + * irq - The IRQ number. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32C3_RTCIO_IRQ +void esp32c3_rtcioirqdisable(int irq); +#else +# define esp32c3_rtcioirqdisable(irq) +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_RISCV_SRC_ESP32C3_ESP32C3_RTC_GPIO_H */ diff --git a/arch/risc-v/src/esp32c3/esp32c3_wdt.c b/arch/risc-v/src/esp32c3/esp32c3_wdt.c index abf70e1738..fe14f4897c 100644 --- a/arch/risc-v/src/esp32c3/esp32c3_wdt.c +++ b/arch/risc-v/src/esp32c3/esp32c3_wdt.c @@ -36,6 +36,7 @@ #include "esp32c3_irq.h" #include "esp32c3_rtc.h" +#include "esp32c3_rtc_gpio.h" #include "esp32c3_wdt.h" /**************************************************************************** @@ -177,7 +178,7 @@ struct esp32c3_wdt_priv_s g_esp32c3_rwdt_priv = .ops = &esp32c3_rwdt_ops, .base = RTC_CNTL_OPTIONS0_REG, .periph = ESP32C3_PERIPH_RTC_CORE, - .irq = ESP32C3_IRQ_RTC_CORE, + .irq = ESP32C3_IRQ_RTC_WDT, .cpuint = -ENOMEM, .inuse = false, }; @@ -738,16 +739,26 @@ static int32_t esp32c3_wdt_setisr(struct esp32c3_wdt_dev_s *dev, if (handler == NULL) { +#ifdef CONFIG_ESP32C3_RWDT + if (wdt->irq == ESP32C3_IRQ_RTC_WDT) + { + esp32c3_rtcioirqdisable(wdt->irq); + irq_detach(wdt->irq); + } + else +#endif if (wdt->cpuint != -ENOMEM) { - /* If a CPU Interrupt was previously allocated, - * then deallocate it. - */ + { + /* If a CPU Interrupt was previously allocated, + * then deallocate it. + */ - up_disable_irq(wdt->cpuint); - irq_detach(wdt->irq); - esp32c3_teardown_irq(wdt->periph, wdt->cpuint); - wdt->cpuint = -ENOMEM; + up_disable_irq(wdt->cpuint); + irq_detach(wdt->irq); + esp32c3_teardown_irq(wdt->periph, wdt->cpuint); + wdt->cpuint = -ENOMEM; + } } } @@ -755,43 +766,60 @@ static int32_t esp32c3_wdt_setisr(struct esp32c3_wdt_dev_s *dev, else { - if (wdt->cpuint != -ENOMEM) +#ifdef CONFIG_ESP32C3_RWDT + if (wdt->irq == ESP32C3_IRQ_RTC_WDT) { - /* Disable the provided CPU interrupt to configure it. */ + ret = irq_attach(wdt->irq, handler, arg); - up_disable_irq(wdt->cpuint); + if (ret != OK) + { + esp32c3_rtcioirqdisable(wdt->irq); + tmrerr("ERROR: Failed to associate an IRQ Number"); + } - /* Free CPU interrupt that is attached to this peripheral - * because we will get another from esp32c3_setup_irq() - */ - - esp32c3_teardown_irq(wdt->periph, wdt->cpuint); + esp32c3_rtcioirqenable(wdt->irq); } - - wdt->cpuint = esp32c3_setup_irq(wdt->periph, - ESP32C3_INT_PRIO_DEF, - ESP32C3_INT_LEVEL); - - if (wdt->cpuint < 0) + else +#endif { - return wdt->cpuint; + if (wdt->cpuint != -ENOMEM) + { + /* Disable the provided CPU interrupt to configure it. */ + + up_disable_irq(wdt->cpuint); + + /* Free CPU interrupt that is attached to this peripheral + * because we will get another from esp32c3_setup_irq() + */ + + esp32c3_teardown_irq(wdt->periph, wdt->cpuint); + } + + wdt->cpuint = esp32c3_setup_irq(wdt->periph, + ESP32C3_INT_PRIO_DEF, + ESP32C3_INT_LEVEL); + + if (wdt->cpuint < 0) + { + return wdt->cpuint; + } + + /* Attach and enable the IRQ. */ + + ret = irq_attach(wdt->irq, handler, arg); + if (ret != OK) + { + /* Failed to attach IRQ, so CPU interrupt must be freed. */ + + esp32c3_teardown_irq(wdt->periph, wdt->cpuint); + wdt->cpuint = -ENOMEM; + return ret; + } + + /* Enable the CPU interrupt that is linked to the WDT. */ + + up_enable_irq(wdt->cpuint); } - - /* Attach and enable the IRQ. */ - - ret = irq_attach(wdt->irq, handler, arg); - if (ret != OK) - { - /* Failed to attach IRQ, so CPU interrupt must be freed. */ - - esp32c3_teardown_irq(wdt->periph, wdt->cpuint); - wdt->cpuint = -ENOMEM; - return ret; - } - - /* Enable the CPU interrupt that is linked to the WDT. */ - - up_enable_irq(wdt->cpuint); } return ret;