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
#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 */

View File

@ -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

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_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

View File

@ -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 */

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_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;