arch/risc-v/esp32c3: Add RTC interrupt support

This commit is contained in:
Lucas Saavedra Vaz 2023-02-07 21:40:41 -03:00 committed by Xiang Xiao
parent 5d2e1d40dc
commit 14d95eb131
7 changed files with 523 additions and 42 deletions

View File

@ -209,8 +209,33 @@
# define ESP32C3_NIRQ_GPIO 0 # define ESP32C3_NIRQ_GPIO 0
#endif #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 */ #endif /* __ARCH_RISCV_INCLUDE_ESP32C3_IRQ_H */

View File

@ -193,6 +193,12 @@ config ESP32C3_GPIO_IRQ
---help--- ---help---
Enable support for interrupting GPIO pins 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 config ESP32C3_UART0
bool "UART0" bool "UART0"
default y default y
@ -279,6 +285,7 @@ config ESP32C3_RWDT
bool "RTC Watchdog Timer" bool "RTC Watchdog Timer"
default n default n
select ESP32C3_WDT select ESP32C3_WDT
select ESP32C3_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

View File

@ -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_allocateheap.c esp32c3_start.c esp32c3_wdt.c esp32c3_idle.c
CHIP_CSRCS += esp32c3_irq.c esp32c3_libc_stubs.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_lowputc.c esp32c3_serial.c
CHIP_CSRCS += esp32c3_systemreset.c esp32c3_resetcause.c CHIP_CSRCS += esp32c3_systemreset.c esp32c3_resetcause.c
CHIP_CSRCS += esp32c3_uid.c esp32c3_perf.c CHIP_CSRCS += esp32c3_uid.c esp32c3_perf.c

View File

@ -40,6 +40,7 @@
#include "esp32c3.h" #include "esp32c3.h"
#include "esp32c3_attr.h" #include "esp32c3_attr.h"
#include "esp32c3_gpio.h" #include "esp32c3_gpio.h"
#include "esp32c3_rtc_gpio.h"
#include "esp32c3_irq.h" #include "esp32c3_irq.h"
@ -234,6 +235,10 @@ void up_irqinitialize(void)
esp32c3_gpioirqinitialize(); esp32c3_gpioirqinitialize();
#endif #endif
/* Initialize RTCIO interrupt support */
esp32c3_rtcioirqinitialize();
#ifndef CONFIG_SUPPRESS_INTERRUPTS #ifndef CONFIG_SUPPRESS_INTERRUPTS
/* And finally, enable interrupts */ /* And finally, enable interrupts */

View File

@ -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 <nuttx/config.h>
#include <assert.h>
#include <debug.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#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

View File

@ -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 <nuttx/config.h>
#include <stdbool.h>
#include <stdint.h>
#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 */

View File

@ -36,6 +36,7 @@
#include "esp32c3_irq.h" #include "esp32c3_irq.h"
#include "esp32c3_rtc.h" #include "esp32c3_rtc.h"
#include "esp32c3_rtc_gpio.h"
#include "esp32c3_wdt.h" #include "esp32c3_wdt.h"
/**************************************************************************** /****************************************************************************
@ -177,7 +178,7 @@ struct esp32c3_wdt_priv_s g_esp32c3_rwdt_priv =
.ops = &esp32c3_rwdt_ops, .ops = &esp32c3_rwdt_ops,
.base = RTC_CNTL_OPTIONS0_REG, .base = RTC_CNTL_OPTIONS0_REG,
.periph = ESP32C3_PERIPH_RTC_CORE, .periph = ESP32C3_PERIPH_RTC_CORE,
.irq = ESP32C3_IRQ_RTC_CORE, .irq = ESP32C3_IRQ_RTC_WDT,
.cpuint = -ENOMEM, .cpuint = -ENOMEM,
.inuse = false, .inuse = false,
}; };
@ -738,7 +739,16 @@ static int32_t esp32c3_wdt_setisr(struct esp32c3_wdt_dev_s *dev,
if (handler == NULL) 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 (wdt->cpuint != -ENOMEM)
{
{ {
/* If a CPU Interrupt was previously allocated, /* If a CPU Interrupt was previously allocated,
* then deallocate it. * then deallocate it.
@ -750,11 +760,28 @@ static int32_t esp32c3_wdt_setisr(struct esp32c3_wdt_dev_s *dev,
wdt->cpuint = -ENOMEM; wdt->cpuint = -ENOMEM;
} }
} }
}
/* Otherwise set callback and enable interrupt. */ /* Otherwise set callback and enable interrupt. */
else else
{ {
#ifdef CONFIG_ESP32C3_RWDT
if (wdt->irq == ESP32C3_IRQ_RTC_WDT)
{
ret = irq_attach(wdt->irq, handler, arg);
if (ret != OK)
{
esp32c3_rtcioirqdisable(wdt->irq);
tmrerr("ERROR: Failed to associate an IRQ Number");
}
esp32c3_rtcioirqenable(wdt->irq);
}
else
#endif
{
if (wdt->cpuint != -ENOMEM) if (wdt->cpuint != -ENOMEM)
{ {
/* Disable the provided CPU interrupt to configure it. */ /* Disable the provided CPU interrupt to configure it. */
@ -793,6 +820,7 @@ static int32_t esp32c3_wdt_setisr(struct esp32c3_wdt_dev_s *dev,
up_enable_irq(wdt->cpuint); up_enable_irq(wdt->cpuint);
} }
}
return ret; return ret;
} }