From b9d44017cf90691c9f55dc7268f5501eeef65234 Mon Sep 17 00:00:00 2001 From: Sara Souza Date: Wed, 14 Oct 2020 14:33:11 -0300 Subject: [PATCH] xtensa/esp32: Watchdog support (MWDTs) --- arch/xtensa/src/esp32/Kconfig | 45 +- arch/xtensa/src/esp32/Make.defs | 8 + arch/xtensa/src/esp32/esp32_tim_lowerhalf.c | 2 +- arch/xtensa/src/esp32/esp32_wtd.c | 1006 +++++++++++++++++ arch/xtensa/src/esp32/esp32_wtd.h | 106 ++ arch/xtensa/src/esp32/esp32_wtd_lowerhalf.c | 718 ++++++++++++ arch/xtensa/src/esp32/esp32_wtd_lowerhalf.h | 52 + .../xtensa/src/esp32/hardware/esp32_rtccntl.h | 22 +- arch/xtensa/src/esp32/hardware/esp32_soc.h | 2 +- arch/xtensa/src/esp32/hardware/esp32_tim.h | 19 + .../esp32-core/configs/watchdog/defconfig | 55 + boards/xtensa/esp32/esp32-core/src/Makefile | 6 + .../xtensa/esp32/esp32-core/src/esp32-core.h | 13 +- .../esp32/esp32-core/src/esp32_bringup.c | 64 +- .../xtensa/esp32/esp32-core/src/esp32_timer.c | 74 +- .../xtensa/esp32/esp32-core/src/esp32_wtd.c | 110 ++ 16 files changed, 2213 insertions(+), 89 deletions(-) create mode 100644 arch/xtensa/src/esp32/esp32_wtd.c create mode 100644 arch/xtensa/src/esp32/esp32_wtd.h create mode 100644 arch/xtensa/src/esp32/esp32_wtd_lowerhalf.c create mode 100644 arch/xtensa/src/esp32/esp32_wtd_lowerhalf.h create mode 100644 boards/xtensa/esp32/esp32-core/configs/watchdog/defconfig create mode 100644 boards/xtensa/esp32/esp32-core/src/esp32_wtd.c diff --git a/arch/xtensa/src/esp32/Kconfig b/arch/xtensa/src/esp32/Kconfig index 8825571b0c..0404ce84e5 100644 --- a/arch/xtensa/src/esp32/Kconfig +++ b/arch/xtensa/src/esp32/Kconfig @@ -47,6 +47,10 @@ config ESP32_TIMER bool default n +config ESP32_WTD + bool + default n + config ESP32_BT bool "Bluetooth" default n @@ -205,43 +209,20 @@ config ESP32_TIMER3 Enables Timer config ESP32_MWDT0 - bool "Timer 0 Watchdog" + bool "Main System Watchdog Timer (Group 0)" default n - depends on EXPERIMENTAL - select ESP32_TIMER0 + select ESP32_WTD ---help--- - No yet implemented - + Includes MWDT0. This watchdog timer is part of the Group 0 + timer submodule. + config ESP32_MWDT1 - bool "Timer 1 Watchdog" + bool "Main System Watchdog Timer (Group 1)" default n - depends on EXPERIMENTAL - select ESP32_TIMER1 + select ESP32_WTD ---help--- - No yet implemented - -config ESP32_MWDT2 - bool "Timer 2 Watchdog" - default n - depends on EXPERIMENTAL - select ESP32_TIMER2 - ---help--- - No yet implemented - -config ESP32_MWDT3 - bool "Timer 3 Watchdog" - default n - depends on EXPERIMENTAL - select ESP32_TIMER3 - ---help--- - No yet implemented - -config ESP32_RWDT - bool "RTC Watchdog" - default n - depends on EXPERIMENTAL - ---help--- - No yet implemented + Includes MWDT1. This watchdog timer is part of the Group 0 + timer submodule. config ESP32_UART0 bool "UART 0" diff --git a/arch/xtensa/src/esp32/Make.defs b/arch/xtensa/src/esp32/Make.defs index fd34a7c1d1..5373f732d1 100644 --- a/arch/xtensa/src/esp32/Make.defs +++ b/arch/xtensa/src/esp32/Make.defs @@ -157,6 +157,14 @@ ifeq ($(CONFIG_ESP32_PARTITION),y) CHIP_CSRCS += esp32_partition.c endif +ifeq ($(CONFIG_WATCHDOG),y) +CHIP_CSRCS += esp32_wtd_lowerhalf.c +ifeq ($(CONFIG_ESP32_WTD),y) +CHIP_CSRCS += esp32_wtd.c +endif +endif + + ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y) CHIP_CSRCS += esp32_modtext.c CMN_ASRCS += xtensa_loadstore.S diff --git a/arch/xtensa/src/esp32/esp32_tim_lowerhalf.c b/arch/xtensa/src/esp32/esp32_tim_lowerhalf.c index 0b78c65a09..26f10faf64 100644 --- a/arch/xtensa/src/esp32/esp32_tim_lowerhalf.c +++ b/arch/xtensa/src/esp32/esp32_tim_lowerhalf.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/esp32/esp32_tim_lowerhalf.h + * arch/arm/src/esp32/esp32_tim_lowerhalf.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with diff --git a/arch/xtensa/src/esp32/esp32_wtd.c b/arch/xtensa/src/esp32/esp32_wtd.c new file mode 100644 index 0000000000..080bffbd9b --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_wtd.c @@ -0,0 +1,1006 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_wtd.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 "xtensa.h" +#include "hardware/esp32_tim.h" +#include "hardware/esp32_rtccntl.h" +#include "esp32_wtd.h" +#include "esp32_cpuint.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct esp32_wtd_priv_s + { + FAR struct esp32_wtd_ops_s *ops; + uint32_t base; /* WTD register base address */ + uint8_t periph; /* Peripheral ID */ + uint8_t irq; /* Interrupt ID */ + int cpuint; /* CPU interrupt assigned to this wtd */ + bool inuse; /* Flag indicating if this wtd is in use */ + }; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* WTD registers access *****************************************************/ + +static uint32_t esp32_wtd_getreg(FAR struct esp32_wtd_dev_s *dev, + uint32_t offset); +static void esp32_wtd_putreg(FAR struct esp32_wtd_dev_s *dev, + uint32_t offset, + uint32_t value); +static void esp32_wtd_modifyreg32(FAR struct esp32_wtd_dev_s *dev, + uint32_t offset, + uint32_t clearbits, + uint32_t setbits); + +/* WTD operations ***********************************************************/ + +static int esp32_wtd_start(FAR struct esp32_wtd_dev_s *dev); +static int esp32_wtd_stop(FAR struct esp32_wtd_dev_s *dev); +static int esp32_wtd_enablewp(FAR struct esp32_wtd_dev_s *dev); +static int esp32_wtd_disablewp(FAR struct esp32_wtd_dev_s *dev); +static int esp32_wtd_initconf(FAR struct esp32_wtd_dev_s *dev); +static int esp32_wtd_pre(FAR struct esp32_wtd_dev_s *dev, uint16_t value); +static int esp32_wtd_settimeout(FAR struct esp32_wtd_dev_s *dev, + uint32_t value, uint8_t stage); +static int esp32_wtd_feed_dog(FAR struct esp32_wtd_dev_s *dev); +static int esp32_wtd_set_stg_conf(FAR struct esp32_wtd_dev_s *dev, + uint8_t stage, uint8_t conf); +static uint16_t esp32_rtc_clk(FAR struct esp32_wtd_dev_s *dev); +static int esp32_wtd_setisr(FAR struct esp32_wtd_dev_s *dev, xcpt_t handler, + FAR void * arg); +static int esp32_wtd_enableint(FAR struct esp32_wtd_dev_s *dev); +static int esp32_wtd_disableint(FAR struct esp32_wtd_dev_s *dev); +static int esp32_wtd_ackint(FAR struct esp32_wtd_dev_s *dev); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* ESP32 WTD ops */ + +struct esp32_wtd_ops_s esp32_mwtd_ops = +{ + .start = esp32_wtd_start, + .stop = esp32_wtd_stop, + .initconf = esp32_wtd_initconf, + .enablewp = esp32_wtd_enablewp, + .disablewp = esp32_wtd_disablewp, + .pre = esp32_wtd_pre, + .settimeout = esp32_wtd_settimeout, + .feed = esp32_wtd_feed_dog, + .stg_conf = esp32_wtd_set_stg_conf, + .rtc_clk = NULL, + .setisr = esp32_wtd_setisr, + .enableint = esp32_wtd_enableint, + .disableint = esp32_wtd_disableint, + .ackint = esp32_wtd_ackint, +}; + +struct esp32_wtd_ops_s esp32_rwtd_ops = +{ + .start = esp32_wtd_start, + .stop = esp32_wtd_stop, + .initconf = esp32_wtd_initconf, + .enablewp = esp32_wtd_enablewp, + .disablewp = esp32_wtd_disablewp, + .pre = NULL, + .settimeout = esp32_wtd_settimeout, + .feed = esp32_wtd_feed_dog, + .stg_conf = esp32_wtd_set_stg_conf, + .rtc_clk = esp32_rtc_clk, + .setisr = esp32_wtd_setisr, + .enableint = esp32_wtd_enableint, + .disableint = esp32_wtd_disableint, + .ackint = esp32_wtd_ackint, +}; + +#ifdef CONFIG_ESP32_MWDT0 + +struct esp32_wtd_priv_s g_esp32_mwtd0_priv = +{ + .ops = &esp32_mwtd_ops, + .base = TIMG_WDTCONFIG0_REG(0), + .periph = ESP32_PERIPH_TG_WDT_LEVEL, /* Peripheral ID */ + .irq = ESP32_IRQ_TG_WDT_LEVEL, /* Interrupt ID */ + .cpuint = -ENOMEM, /* CPU interrupt assigned to this wtd */ + .inuse = false, +}; +#endif + +#ifdef CONFIG_ESP32_MWDT1 + +struct esp32_wtd_priv_s g_esp32_mwtd1_priv = +{ + .ops = &esp32_mwtd_ops, + .base = TIMG_WDTCONFIG0_REG(1), + .periph = ESP32_PERIPH_TG1_WDT_LEVEL, /* Peripheral ID */ + .irq = ESP32_IRQ_TG1_WDT_LEVEL, /* Interrupt ID */ + .cpuint = -ENOMEM, /* CPU interrupt assigned to this wtd */ + .inuse = false, +}; +#endif + +#ifdef CONFIG_ESP32_RWDT + +struct esp32_wtd_priv_s g_esp32_rwtd_priv = +{ + .ops = &esp32_rwtd_ops, + .base = RTC_CNTL_OPTIONS0_REG, + .periph = ESP32_PERIPH_RTC_CORE, /* Peripheral ID */ + .irq = ESP32_IRQ_RTC_CORE, /* Interrupt ID */ + .cpuint = -ENOMEM, /* CPU interrupt assigned to this wtd */ + .inuse = false, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_wtd_getreg + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static uint32_t esp32_wtd_getreg(FAR struct esp32_wtd_dev_s *dev, + uint32_t offset) +{ + DEBUGASSERT(dev); + + return getreg32(((struct esp32_wtd_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: esp32_wtd_putreg + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static void esp32_wtd_putreg(FAR struct esp32_wtd_dev_s *dev, + uint32_t offset, + uint32_t value) +{ + DEBUGASSERT(dev); + + putreg32(value, ((struct esp32_wtd_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: esp32_wtd_modifyreg32 + * + * Description: + * Modify a reg of 32 bits + * + ****************************************************************************/ + +static void esp32_wtd_modifyreg32(FAR struct esp32_wtd_dev_s *dev, + uint32_t offset, + uint32_t clearbits, + uint32_t setbits) +{ + DEBUGASSERT(dev); + + modifyreg32(((struct esp32_wtd_priv_s *)dev)->base + offset, + clearbits, setbits); +} + +/**************************************************************************** + * Name: esp32_wtd_start + * + * Description: + * Releases the counter + * + ****************************************************************************/ + +static int esp32_wtd_start(FAR struct esp32_wtd_dev_s *dev) +{ + DEBUGASSERT(dev); + + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == + RTC_CNTL_WDTCONFIG0_REG) + { + esp32_wtd_modifyreg32(dev, RWDT_CONFIG0_OFFSET, 0, RTC_CNTL_WDT_EN); + } + + /* If it is a MWDT */ + + else + { + esp32_wtd_modifyreg32(dev, MWDT_CONFIG0_OFFSET, 0, TIMG_WDT_EN); + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_set_stg_conf + * + * Description: + * It configures the action to be triggered by a stage on expiration. + * The available actions are: + * 0 - off + * 1 - interrupt + * 2 - reset CPU + * 3 - reset main System (CPU + Peripherals - RTC) + * 4 - reset main System and RTC ( NOTE: only available for RWDT) + * + ****************************************************************************/ + +static int esp32_wtd_set_stg_conf(FAR struct esp32_wtd_dev_s *dev, + uint8_t stage, uint8_t conf) +{ + int ret = OK; + uint32_t mask; + DEBUGASSERT(dev); + + switch (stage) + { + case 0: + { + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == + RTC_CNTL_WDTCONFIG0_REG) + { + mask = (uint32_t)conf << RTC_CNTL_WDT_STG0_S; + esp32_wtd_modifyreg32(dev, RWDT_CONFIG0_OFFSET, + RTC_CNTL_WDT_STG0_M, mask); + } + + /* If it is a MWDT */ + + else + { + mask = (uint32_t)conf << TIMG_WDT_STG0_S; + esp32_wtd_modifyreg32(dev, MWDT_CONFIG0_OFFSET, + TIMG_WDT_STG0_M, mask); + } + break; + } + + case 1: + { + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == + RTC_CNTL_WDTCONFIG0_REG) + { + mask = (uint32_t)conf << RTC_CNTL_WDT_STG1_S; + esp32_wtd_modifyreg32(dev, RWDT_CONFIG0_OFFSET, + RTC_CNTL_WDT_STG1_M, mask); + } + + /* If it is a MWDT */ + + else + { + mask = (uint32_t)conf << TIMG_WDT_STG1_S; + esp32_wtd_modifyreg32(dev, MWDT_CONFIG0_OFFSET, + TIMG_WDT_STG1_M, mask); + } + break; + } + + case 2: + { + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == + RTC_CNTL_WDTCONFIG0_REG) + { + mask = (uint32_t)conf << RTC_CNTL_WDT_STG2_S; + esp32_wtd_modifyreg32(dev, RWDT_CONFIG0_OFFSET, + RTC_CNTL_WDT_STG2_M, mask); + } + + /* If it is a MWDT */ + + else + { + mask = (uint32_t)conf << TIMG_WDT_STG2_S; + esp32_wtd_modifyreg32(dev, MWDT_CONFIG0_OFFSET, + TIMG_WDT_STG2_M, mask); + } + break; + } + + case 3: + { + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == + RTC_CNTL_WDTCONFIG0_REG) + { + mask = (uint32_t)conf << RTC_CNTL_WDT_STG3_S; + esp32_wtd_modifyreg32(dev, RWDT_CONFIG0_OFFSET, + RTC_CNTL_WDT_STG3_M, mask); + } + + /* If it is a MWDT */ + + else + { + mask = (uint32_t)conf << TIMG_WDT_STG3_S; + esp32_wtd_modifyreg32(dev, MWDT_CONFIG0_OFFSET, + TIMG_WDT_STG3_M, mask); + } + break; + } + + default: + { + tmrerr("ERROR: unsupported stage %d\n", stage); + ret = EINVAL; + goto errout; + } + } + + errout: + return ret; +} + +/**************************************************************************** + * Name: esp32_wtd_stop + * + * Description: + * Disables the watchdog + * + ****************************************************************************/ + +static int esp32_wtd_stop(FAR struct esp32_wtd_dev_s *dev) +{ + DEBUGASSERT(dev); + + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == RTC_CNTL_WDTCONFIG0_REG) + { + esp32_wtd_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_EN, 0); + } + + /* If it is a MWDT */ + + else + { + esp32_wtd_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_EN, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_enablewp + * + * Description: + * Enables write protection (WP) on registers against accidental writing. + * TRM recommends to change any WDT register thorugh this sequence: + * - Disable WP + * - Do the op + * - Reenable WP + * + ****************************************************************************/ + +static int esp32_wtd_enablewp(FAR struct esp32_wtd_dev_s *dev) +{ + DEBUGASSERT(dev); + + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == RTC_CNTL_WDTCONFIG0_REG) + { + esp32_wtd_putreg(dev, RWDT_WP_REG, 0); + } + + /* If it is a MWDT */ + + else + { + esp32_wtd_putreg(dev, MWDT_WP_REG, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_disablewp + * + * Description: + * Disables write protection (WP) on registers against accidental writing. + * TRM recommends to change any WDT register thorugh this sequence: + * - Disable WP + * - Do the op + * - Reenable WP + * + ****************************************************************************/ + +static int esp32_wtd_disablewp(FAR struct esp32_wtd_dev_s *dev) +{ + DEBUGASSERT(dev); + + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == RTC_CNTL_WDTCONFIG0_REG) + { + esp32_wtd_putreg(dev, RWDT_WP_REG, WRITE_PROTECTION_KEY); + } + + /* If it is a MWDT */ + + else + { + esp32_wtd_putreg(dev, MWDT_WP_REG, WRITE_PROTECTION_KEY); + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_initconf + * + * Description: + * It turn off all the stages and ensure Flash Boot Protection is disabled. + * In case of RWDT, it also turns off the WDT, in case it was already + * turned on before. NOTE: The main system reset does not reset RTC, so + * all the registers values are kept. + * + ****************************************************************************/ + +static int esp32_wtd_initconf(FAR struct esp32_wtd_dev_s *dev) +{ + uint32_t mask = 0; + + DEBUGASSERT(dev); + + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == RTC_CNTL_WDTCONFIG0_REG) + { + mask = RTC_CNTL_WDT_INT_ENA_M | RTC_CNTL_WDT_STG0_M + | RTC_CNTL_WDT_STG1_M | RTC_CNTL_WDT_STG2_M | RTC_CNTL_WDT_STG3_M + | RTC_CNTL_WDT_FLASHBOOT_MOD_EN_M; + esp32_wtd_modifyreg32(dev, RWDT_CONFIG0_OFFSET, mask, 0); + } + + /* If it is a MWDT */ + + else + { + mask = TIMG_WDT_STG0_M | TIMG_WDT_STG1_M | TIMG_WDT_STG2_M + | TIMG_WDT_STG3_M | TIMG_WDT_FLASHBOOT_MOD_EN_M; + esp32_wtd_modifyreg32(dev, MWDT_CONFIG0_OFFSET, mask, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_pre + * + * Description: + * Sets a prescale value. The MWDT clock period is 12.5 ns * value (pre). + * NOTE: There's no prescaler register for RWDT and its source clock is + * clocked from the RTC slow clock. + * + ****************************************************************************/ + +static int esp32_wtd_pre(FAR struct esp32_wtd_dev_s *dev, uint16_t pre) +{ + uint32_t mask = (uint32_t)pre << TIMG_WDT_CLK_PRESCALE_S; + + DEBUGASSERT(dev); + + esp32_wtd_modifyreg32(dev, MWDT_CLK_PRESCALE_OFFSET, + TIMG_WDT_CLK_PRESCALE_M, mask); + + return OK; +} + +/**************************************************************************** + * Name: esp32_rtc_clk + * + * Description: + * Check the RTC clock source and return the necessary cycles to complete + * 1 ms. NOTE: TODO. + * + ****************************************************************************/ + +static uint16_t esp32_rtc_clk(FAR struct esp32_wtd_dev_s *dev) +{ + uint32_t reg_value = 0; + uint8_t cycles_ms = 0; + uint32_t corrected_frequency = 0; + + DEBUGASSERT(dev); + + reg_value = esp32_wtd_getreg(dev, RCLK_CONF_REG_OFFSET); + + if ((reg_value & CK8M_D256_OUT_MASK) == CK8M_D256_OUT_MASK) + { + /* TODO: get the correct RTC frequency using the RTC driver API */ + } + else if ((reg_value & CK_XTAL_32K_MASK) == CK_XTAL_32K_MASK) + { + /* TODO: get the correct RTC frequency using the RTC driver API */ + } + else + { + /* TODO: get the correct RTC frequency using the RTC driver API */ + } + + return cycles_ms = (uint8_t)(corrected_frequency / 1000); +} + +/**************************************************************************** + * Name: esp32_wtd_settimeout + * + * Description: + * Sets the wdt timeout. + * + ****************************************************************************/ + +static int esp32_wtd_settimeout(FAR struct esp32_wtd_dev_s *dev, + uint32_t value, uint8_t stage) +{ + int ret = OK; + DEBUGASSERT(dev); + + switch (stage) + { + case 0: + { + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == + RTC_CNTL_WDTCONFIG0_REG) + { + esp32_wtd_putreg(dev, RWDT_STAGE0_TIMEOUT_OFFSET, value); + } + + /* If it is a MWDT */ + + else + { + esp32_wtd_putreg(dev, MWDT_STAGE0_TIMEOUT_OFFSET, value); + } + break; + } + + case 1: + { + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == + RTC_CNTL_WDTCONFIG0_REG) + { + esp32_wtd_putreg(dev, RWDT_STAGE1_TIMEOUT_OFFSET, value); + } + + /* If it is a MWDT */ + + else + { + esp32_wtd_putreg(dev, MWDT_STAGE1_TIMEOUT_OFFSET, value); + } + break; + } + + case 2: + { + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == + RTC_CNTL_WDTCONFIG0_REG) + { + esp32_wtd_putreg(dev, RWDT_STAGE2_TIMEOUT_OFFSET, value); + } + + /* If it is a MWDT */ + + else + { + esp32_wtd_putreg(dev, MWDT_STAGE2_TIMEOUT_OFFSET, value); + } + break; + } + + case 3: + { + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == + RTC_CNTL_WDTCONFIG0_REG) + { + esp32_wtd_putreg(dev, RWDT_STAGE3_TIMEOUT_OFFSET, value); + } + + /* If it is a MWDT */ + + else + { + esp32_wtd_putreg(dev, MWDT_STAGE3_TIMEOUT_OFFSET, value); + } + break; + } + + default: + { + tmrerr("ERROR: unsupported stage %d\n", stage); + ret = EINVAL; + goto errout; + } + } + + errout: + return ret; +} + +/**************************************************************************** + * Name: esp32_wtd_feed_dog + * + * Description: + * Feeds the dog. When software feeds the watchdog timer, it returns to + * stage 0 and its counter restarts from 0. + * + ****************************************************************************/ + +static int esp32_wtd_feed_dog(FAR struct esp32_wtd_dev_s *dev) +{ + DEBUGASSERT(dev); + + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == RTC_CNTL_WDTCONFIG0_REG) + { + esp32_wtd_putreg(dev, RWDT_FEED_OFFSET , FEED_DOG); + } + + /* If it is a MWDT */ + + else + { + esp32_wtd_putreg(dev, MWDT_FEED_OFFSET , FEED_DOG); + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_setisr + * + * Description: + * Allocates a Level CPU Interrupt, connects the peripheral source to this + * Interrupt, register the callback and enables the Interruption. It does + * the opposite if the handler and arg are NULL. + * + ****************************************************************************/ + +static int esp32_wtd_setisr(FAR struct esp32_wtd_dev_s *dev, xcpt_t handler, + FAR void *arg) +{ + FAR struct esp32_wtd_priv_s *wtd = NULL; + int ret = OK; + uint8_t cpu; + + DEBUGASSERT(dev); + + wtd = (FAR struct esp32_wtd_priv_s *)dev; + + /* Disable interrupt when callback is removed */ + + if (handler == NULL) + { + /* If a CPU Interrupt was previously allocated, then deallocate it */ + + if (wtd->cpuint >= 0) + { + /* Disable CPU Interrupt, free a previously allocated + * CPU Interrupt + */ + + up_disable_irq(wtd->cpuint); + cpu = up_cpu_index(); + esp32_detach_peripheral(cpu, wtd->periph, wtd->cpuint); + esp32_free_cpuint(wtd->cpuint); + irq_detach(wtd->irq); + } + + ret = OK; + goto errout; + } + + /* Otherwise set callback and enable interrupt */ + + else + { + /* Verify the available CPU Interrupt */ + + wtd->cpuint = esp32_alloc_levelint(1); + if (wtd->cpuint < 0) + { + tmrerr("ERROR: No CPU Interrupt available"); + ret = wtd->cpuint; + goto errout; + } + + /* Disable the provided CPU Interrupt to configure it */ + + up_disable_irq(wtd->cpuint); + + /* Attach a peripheral interrupt to the available CPU interrupt in + * the current core + */ + + cpu = up_cpu_index(); + esp32_attach_peripheral(cpu, wtd->periph, wtd->cpuint); + + /* Associate an IRQ Number (from the WDT) to an ISR */ + + ret = irq_attach(wtd->irq, handler, arg); + + if (ret != OK) + { + esp32_detach_peripheral(cpu, wtd->periph, wtd->cpuint); + esp32_free_cpuint(wtd->cpuint); + tmrerr("ERROR: Failed to associate an IRQ Number"); + goto errout; + } + + /* Enable the CPU Interrupt that is linked to the wdt */ + + up_enable_irq(wtd->cpuint); + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: esp32_wtd_enableint + * + * Description: + * Enables a Level Interrupt at timeout. + * + ****************************************************************************/ + +static int esp32_wtd_enableint(FAR struct esp32_wtd_dev_s *dev) +{ + DEBUGASSERT(dev); + + /* Set the level interrupt bit */ + + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == RTC_CNTL_WDTCONFIG0_REG) + { + /* Level Interrupt */ + + esp32_wtd_modifyreg32(dev, RWDT_CONFIG0_OFFSET, 0, + RTC_CNTL_WDT_LEVEL_INT_EN); + + /* Enable Interrupt */ + + esp32_wtd_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, 0, + RTC_CNTL_WDT_INT_ENA); + } + + /* If it is a MWDT */ + + else + { + /* Level Interrupt */ + + esp32_wtd_modifyreg32(dev, MWDT_CONFIG0_OFFSET, 0, + TIMG_WDT_LEVEL_INT_EN); + + /* Enable Interrupt */ + + esp32_wtd_modifyreg32(dev, MWDT_INT_ENA_REG_OFFSET, 0, + TIMG_WDT_INT_ENA); + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_disableint + * + * Description: + * Disables a Level Interrupt at timeout. + * + ****************************************************************************/ + +static int esp32_wtd_disableint(FAR struct esp32_wtd_dev_s *dev) +{ + DEBUGASSERT(dev); + + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == RTC_CNTL_WDTCONFIG0_REG) + { + /* Level Interrupt */ + + esp32_wtd_modifyreg32(dev, RWDT_CONFIG0_OFFSET, + RTC_CNTL_WDT_LEVEL_INT_EN, 0); + + /* Enable Interrupt */ + + esp32_wtd_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, + RTC_CNTL_WDT_INT_ENA, 0); + } + + /* If it is a MWDT */ + + else + { + /* Level Interrupt */ + + esp32_wtd_modifyreg32(dev, MWDT_CONFIG0_OFFSET, + TIMG_WDT_LEVEL_INT_EN, 0); + + /* Enable Interrupt */ + + esp32_wtd_modifyreg32(dev, MWDT_INT_ENA_REG_OFFSET, + TIMG_WDT_INT_ENA, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_ackint + * + * Description: + * Acknowledges an interrupt + * + ****************************************************************************/ + +static int esp32_wtd_ackint(FAR struct esp32_wtd_dev_s *dev) +{ + DEBUGASSERT(dev); + + /* If it is a RWDT */ + + if (((struct esp32_wtd_priv_s *)dev)->base == RTC_CNTL_WDTCONFIG0_REG) + { + esp32_wtd_putreg(dev, RWDT_INT_CLR_REG_OFFSET, RTC_CNTL_WDT_INT_CLR); + } + + /* If it is a MWDT */ + + else + { + esp32_wtd_putreg(dev, MWDT_INT_CLR_REG_OFFSET, TIMG_WDT_INT_CLR); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_wtd_init + * + * Description: + * Initialize WDT device + * + ****************************************************************************/ + +FAR struct esp32_wtd_dev_s *esp32_wtd_init(uint8_t wdt_id) +{ + FAR struct esp32_wtd_priv_s *wtd = NULL; + + /* Get wdt instance */ + + switch (wdt_id) + { +#ifdef CONFIG_ESP32_MWDT0 + case 0: + { + wtd = &g_esp32_mwtd0_priv; + break; + } + +#endif +#ifdef CONFIG_ESP32_MWDT1 + case 1: + { + wtd = &g_esp32_mwtd1_priv; + break; + } + +#endif +#ifdef CONFIG_ESP32_RWDT + case 2: + { + wtd = &g_esp32_rwtd_priv; + break; + } + +#endif + default: + { + tmrerr("ERROR: unsupported WDT %d\n", wdt_id); + goto errout; + } + } + + /* If some code is using it then sends an error message, + * Otherwise, inform it has been used. + */ + + if (wtd->inuse == true) + { + tmrerr("ERROR: WDT %d is already in use\n", wdt_id); + wtd = NULL; + } + else + { + wtd->inuse = true; + } + + errout: + return (FAR struct esp32_wtd_dev_s *)wtd; +} + +/**************************************************************************** + * Name: esp32_wtd_deinit + * + * Description: + * Deinit WDT device + * + ****************************************************************************/ + +int esp32_wtd_deinit(FAR struct esp32_wtd_dev_s *dev) +{ + FAR struct esp32_wtd_priv_s *wtd = NULL; + + DEBUGASSERT(dev); + + wtd = (FAR struct esp32_wtd_priv_s *)dev; + + wtd->inuse = false; + + return OK; +} diff --git a/arch/xtensa/src/esp32/esp32_wtd.h b/arch/xtensa/src/esp32/esp32_wtd.h new file mode 100644 index 0000000000..1b3daf46b0 --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_wtd.h @@ -0,0 +1,106 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_wtd.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_XTENSA_SRC_ESP32_ESP32_WTD_H +#define __ARCH_XTENSA_SRC_ESP32_ESP32_WTD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + + #define FEED_DOG 0xffffffff + +/* Helpers ******************************************************************/ + +#define ESP32_WTD_START(d) ((d)->ops->start(d)) +#define ESP32_WTD_STOP(d) ((d)->ops->stop(d)) +#define ESP32_WTD_LOCK(d) ((d)->ops->enablewp(d)) +#define ESP32_WTD_UNLOCK(d) ((d)->ops->disablewp(d)) +#define ESP32_WTD_INITCONF(d) ((d)->ops->initconf(d)) +#define ESP32_WTD_PRE(d, v) ((d)->ops->pre(d, v)) +#define ESP32_WTD_STO(d, v, s) ((d)->ops->settimeout(d, v, s)) +#define ESP32_WTD_FEED(d) ((d)->ops->feed(d)) +#define ESP32_WTD_STG_CONF(d, s, c) ((d)->ops->stg_conf(d, s, c)) +#define ESP32_RWDT_CLK(d) ((d)->ops->rtc_clk(d)) +#define ESP32_WTD_SETISR(d, hnd, arg) ((d)->ops->setisr(d, hnd, arg)) +#define ESP32_WTD_ENABLEINT(d) ((d)->ops->enableint(d)) +#define ESP32_WTD_DISABLEINT(d) ((d)->ops->disableint(d)) +#define ESP32_WTD_ACKINT(d) ((d)->ops->ackint(d)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* ESP32 WTD device */ + +struct esp32_wtd_dev_s +{ + struct esp32_wtd_ops_s *ops; +}; + +/* ESP32 WTD ops */ + +/* This is a struct containing the pointers to the wtd operations */ + +struct esp32_wtd_ops_s +{ + /* WTD tasks */ + + CODE int (*start)(FAR struct esp32_wtd_dev_s *dev); + CODE int (*stop)(FAR struct esp32_wtd_dev_s *dev); + + /* WTD configuration */ + + CODE int (*enablewp)(FAR struct esp32_wtd_dev_s *dev); + CODE int (*disablewp)(FAR struct esp32_wtd_dev_s *dev); + CODE int (*initconf)(FAR struct esp32_wtd_dev_s *dev); + CODE int (*pre)(FAR struct esp32_wtd_dev_s *dev, uint16_t value); + CODE int (*settimeout)(FAR struct esp32_wtd_dev_s *dev, + uint32_t value, uint8_t stage); + CODE int (*feed)(FAR struct esp32_wtd_dev_s *dev); + CODE int (*stg_conf)(FAR struct esp32_wtd_dev_s *dev, + uint8_t stage, uint8_t conf); + CODE uint16_t (*rtc_clk)(FAR struct esp32_wtd_dev_s *dev); + + /* WTD interrupts */ + + CODE int (*setisr)(FAR struct esp32_wtd_dev_s *dev, xcpt_t handler, + FAR void * arg); + CODE int (*enableint)(FAR struct esp32_wtd_dev_s *dev); + CODE int (*disableint)(FAR struct esp32_wtd_dev_s *dev); + CODE int (*ackint)(FAR struct esp32_wtd_dev_s *dev); +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +FAR struct esp32_wtd_dev_s *esp32_wtd_init(uint8_t wdt_id); +int esp32_wtd_deinit(FAR struct esp32_wtd_dev_s *dev); + +#endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_WTD_H */ diff --git a/arch/xtensa/src/esp32/esp32_wtd_lowerhalf.c b/arch/xtensa/src/esp32/esp32_wtd_lowerhalf.c new file mode 100644 index 0000000000..8e2a9f62bb --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_wtd_lowerhalf.c @@ -0,0 +1,718 @@ +/**************************************************************************** + * arch/arm/src/esp32/esp32_wtd_lowerhalf.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 "xtensa.h" +#include "hardware/esp32_soc.h" +#include "esp32_wtd.h" +#include "esp32_wtd_lowerhalf.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PRE_VALUE 40000 /* 40000 * 12.5 ns = 500 us */ + +/* Number of Cycles to have 1 ms period + * cycles = (1*10^-3 (s))*(f (Hz)) + */ + +#define MS_CYCLES_TIMER 2 /* 1 ms/(12.5 ns*PRE_VALUE) */ +#define STAGE_0 0 +#define STAGE_1 1 +#define STAGE_2 2 +#define STAGE_3 3 +#define RESET_SYSTEM_RTC 4 /* Reset Main System + RTC */ +#define RESET_SYSTEM_TIMER 3 /* Reset Main System */ +#define INTERRUPT_ON_TIMEOUT 1 +#define STAGES 4 +#define FULL_STAGE 0xffffffff /* ((2^32)-1) */ +#define MAX_MWDT_TIMEOUT_MS 0x7fffffff /* ((2^32)-1)/cycles */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure provides the private representation of the "lower-half" + * driver state structure. This structure must be cast-compatible with the + * well-known watchdog_lowerhalf_s structure. + */ + +struct esp32_wtd_lowerhalf_s +{ + FAR const struct watchdog_ops_s *ops; /* Lower half operations */ + FAR struct esp32_wtd_dev_s *wtd; /* esp32 watchdog driver */ + uint32_t timeout; /* The current timeout */ + enum wdt_peripherals peripheral; /* Indicates if it is from RTC or Timer Module */ + uint32_t lastreset; /* The last reset time */ + bool started; /* True: Timer has been started */ + xcpt_t handler; /* User Handler */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Interrupt handling *******************************************************/ + +static int esp32_wdt_handler(int irq, FAR void *context, FAR void *arg); + +/* "Lower half" driver methods **********************************************/ + +static int esp32_wtd_start(FAR struct watchdog_lowerhalf_s *lower); +static int esp32_wtd_stop(FAR struct watchdog_lowerhalf_s *lower); +static int esp32_wtd_keepalive(FAR struct watchdog_lowerhalf_s *lower); +static int esp32_wtd_getstatus(FAR struct watchdog_lowerhalf_s *lower, + FAR struct watchdog_status_s *status); +static int esp32_wtd_settimeout(FAR struct watchdog_lowerhalf_s *lower, + uint32_t timeout); +static xcpt_t esp32_wtd_capture(FAR struct watchdog_lowerhalf_s *lower, + xcpt_t handler); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* "Lower half" driver methods */ + +static const struct watchdog_ops_s g_esp32_wdg_ops = +{ + .start = esp32_wtd_start, + .stop = esp32_wtd_stop, + .keepalive = esp32_wtd_keepalive, + .getstatus = esp32_wtd_getstatus, + .settimeout = esp32_wtd_settimeout, + .capture = esp32_wtd_capture, + .ioctl = NULL, +}; + +#ifdef CONFIG_ESP32_MWDT0 +/* MWDT0 lower-half */ + +static struct esp32_wtd_lowerhalf_s g_esp32_mwdt0_lowerhalf = +{ + .ops = &g_esp32_wdg_ops, +}; +#endif + +#ifdef CONFIG_ESP32_MWDT1 +/* MWDT1 lower-half */ + +static struct esp32_wtd_lowerhalf_s g_esp32_mwdt1_lowerhalf = +{ + .ops = &g_esp32_wdg_ops, +}; +#endif + +#ifdef CONFIG_ESP32_RWDT +/* RWDT lower-half */ + +static struct esp32_wtd_lowerhalf_s g_esp32_rwdt_lowerhalf = +{ + .ops = &g_esp32_wdg_ops, +}; +#endif + +/**************************************************************************** + * Name: esp32_wtd_start + * + * Description: + * Start the watchdog timer, register a callback if there is one and + * enables interrupt, otherwise, configure it to reset system on + * expiration. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int esp32_wtd_start(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct esp32_wtd_lowerhalf_s *priv = + (FAR struct esp32_wtd_lowerhalf_s *)lower; + int ret = OK; + irqstate_t flags; + + wdinfo("Entry: started=%d\n"); + DEBUGASSERT(priv); + + if (priv->started == true) + { + /* Return EBUSY to indicate that the timer was already running */ + + ret = -EBUSY; + goto errout; + } + + /* If WDT was not started yet */ + + else + { + priv->started = true; + + /* Unlock WDT */ + + ESP32_WTD_UNLOCK(priv->wtd); + + /* No User Handler */ + + if (priv->handler == NULL) + { + /* Then configure it to reset on wdt expiration */ + + if (priv->peripheral == TIMER) + { + ESP32_WTD_STG_CONF(priv->wtd, STAGE_0, RESET_SYSTEM_TIMER); + } + else + { + ESP32_WTD_STG_CONF(priv->wtd, STAGE_0, RESET_SYSTEM_RTC); + } + } + + /* User handler was already provided */ + + else + { + /* Then configure it to call the user handler on wdt expiration */ + + ESP32_WTD_STG_CONF(priv->wtd, STAGE_0, INTERRUPT_ON_TIMEOUT); + + /* Set the lower half handler and enable interrupt */ + + flags = enter_critical_section(); + ESP32_WTD_SETISR(priv->wtd, esp32_wdt_handler, priv); + leave_critical_section(flags); + ESP32_WTD_ENABLEINT(priv->wtd); + } + flags = enter_critical_section(); + priv->lastreset = clock_systime_ticks(); + ESP32_WTD_START(priv->wtd); + leave_critical_section(flags); + + /* Lock it again */ + + ESP32_WTD_LOCK(priv->wtd); + } + errout: + return ret; +} + +/**************************************************************************** + * Name: esp32_wtd_stop + * + * Description: + * Stop the watchdog timer. In case a callback was previously configured, + * unregister and deallocate it. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * + ****************************************************************************/ + +static int esp32_wtd_stop(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct esp32_wtd_lowerhalf_s *priv = + (FAR struct esp32_wtd_lowerhalf_s *)lower; + irqstate_t flags; + + /* Unlock WDT */ + + ESP32_WTD_UNLOCK(priv->wtd); + + /* Disable the WDT */ + + ESP32_WTD_STOP(priv->wtd); + + /* In case there is some callback registered, disable and deallocate */ + + if (priv->handler != NULL) + { + ESP32_WTD_DISABLEINT(priv->wtd); + flags = enter_critical_section(); + ESP32_WTD_SETISR(priv->wtd, NULL, NULL); + leave_critical_section(flags); + } + + /* Lock it again */ + + ESP32_WTD_LOCK(priv->wtd); + + priv->started = false; + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_keepalive + * + * Description: + * Reset the watchdog timer, prevent any + * imminent watchdog timeouts. This is sometimes referred as "pinging" + * the watchdog timer or "petting the dog". + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * + * + ****************************************************************************/ + +static int esp32_wtd_keepalive(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct esp32_wtd_lowerhalf_s *priv = + (FAR struct esp32_wtd_lowerhalf_s *)lower; + irqstate_t flags; + + wdinfo("Entry\n"); + + /* Unlock */ + + ESP32_WTD_UNLOCK(priv->wtd); + + /* Feed the dog and updates the lastreset variable */ + + flags = enter_critical_section(); + priv->lastreset = clock_systime_ticks(); + ESP32_WTD_FEED(priv->wtd); + leave_critical_section(flags); + + /* Lock */ + + ESP32_WTD_LOCK(priv->wtd); + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_getstatus + * + * Description: + * Get the current watchdog timer status + * + * Input Parameters: + * lower - A pointer the publicly visible representation of + * the "lower-half" driver state structure. + * status - The location to return the watchdog status information. + * + ****************************************************************************/ + +static int esp32_wtd_getstatus(FAR struct watchdog_lowerhalf_s *lower, + FAR struct watchdog_status_s *status) +{ + FAR struct esp32_wtd_lowerhalf_s *priv = + (FAR struct esp32_wtd_lowerhalf_s *)lower; + uint32_t ticks; + uint32_t elapsed; + + DEBUGASSERT(priv); + + /* Flags */ + + status->flags = 0; + /* If no handler was settled, then RESET on expiration. + * Otherwise, call the user handler. + */ + + if (priv->handler == NULL) + { + status->flags |= WDFLAGS_RESET; + } + else + { + status->flags |= WDFLAGS_CAPTURE; + } + if (priv->started) + { + status->flags |= WDFLAGS_ACTIVE; + } + + /* Return the current timeout in milliseconds */ + + status->timeout = priv->timeout; + + /* Get the elapsed time since the last ping */ + + ticks = clock_systime_ticks() - priv->lastreset; + elapsed = (uint32_t)TICK2MSEC(ticks); + + if (elapsed < priv->timeout) + { + /* Return the approximate time until the watchdog timer expiration */ + + status->timeleft = priv->timeout - elapsed; + } + else + { + status->timeleft = 0; + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_settimeout + * + * Description: + * Set a new timeout value (and reset the watchdog timer) + * + * Input Parameters: + * lower - A pointer the publicly visible representation of + * the "lower-half" driver state structure. + * timeout - The new timeout value in milliseconds. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int esp32_wtd_settimeout(FAR struct watchdog_lowerhalf_s *lower, + uint32_t timeout) +{ + FAR struct esp32_wtd_lowerhalf_s *priv = + (FAR struct esp32_wtd_lowerhalf_s *)lower; + uint8_t rtc_cycles = 0; + uint32_t rtc_ms_max = 0; + + wdinfo("Entry: timeout=%d\n", timeout); + DEBUGASSERT(priv); + + /* Unlock WDT */ + + ESP32_WTD_UNLOCK(priv->wtd); + + /* Write the timeout value */ + + priv->timeout = timeout; + + /* Watchdog from Timer Module */ + + if (priv->peripheral == TIMER) + { + /* Is this timeout a valid value for Timer's WDT? */ + + if (timeout == 0 || timeout > MAX_MWDT_TIMEOUT_MS) + { + wderr("ERROR: Cannot represent timeout=%d > %d\n", + timeout, MAX_MWDT_TIMEOUT_MS); + return -ERANGE; + } + else + { + timeout = timeout*MS_CYCLES_TIMER; + ESP32_WTD_STO(priv->wtd, timeout, STAGE_0); + } + } + + /* Watchdog from RTC Module */ + + else + { + rtc_cycles = ESP32_RWDT_CLK(priv->wtd); + rtc_ms_max = (uint32_t)(FULL_STAGE / rtc_cycles); + + /* Is this timeout a valid value for RTC WDT? */ + + if (timeout == 0 || timeout > rtc_ms_max) + { + wderr("ERROR: Cannot represent timeout=%d > %d\n", + timeout, rtc_ms_max); + return -ERANGE; + } + else + { + timeout = timeout*rtc_cycles; + ESP32_WTD_STO(priv->wtd, timeout, STAGE_0); + } + } + + /* Reset the wdt */ + + ESP32_WTD_FEED(priv->wtd); + + /* Lock it again */ + + ESP32_WTD_LOCK(priv->wtd); + + return OK; +} + +/**************************************************************************** + * Name: esp32_wtd_capture + * + * Description: + * Don't reset on watchdog timer timeout; instead, call this user provider + * timeout handler. NOTE: Providing handler==NULL will restore the reset + * behavior. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * newhandler - The new watchdog expiration function pointer. If this + * function pointer is NULL, then the reset-on-expiration + * behavior is restored, + * + * Returned Value: + * The previous watchdog expiration function pointer or NULL if there was + * no previous function pointer, i.e., if the previous behavior was + * reset-on-expiration (NULL is also returned if an error occurs). + * + ****************************************************************************/ + +static xcpt_t esp32_wtd_capture(FAR struct watchdog_lowerhalf_s *lower, + xcpt_t handler) +{ + FAR struct esp32_wtd_lowerhalf_s *priv = + (FAR struct esp32_wtd_lowerhalf_s *)lower; + irqstate_t flags; + xcpt_t oldhandler; + + DEBUGASSERT(priv); + wdinfo("Entry: handler=%p\n", handler); + + /* Get the old handler to return it */ + + oldhandler = priv->handler; + + ESP32_WTD_UNLOCK(priv->wtd); + + flags = enter_critical_section(); + + /* Save the new user handler */ + + priv->handler = handler; + + /* There is a user callback and the timer has already been started. + * The user wants to set a callback after starting the wdt or wants to + * change the callback function once a callback has already been settled. + */ + + if (priv->handler != NULL && priv->started == true) + { + /* Deallocate the previous allocated interrupt + * If there is a previous allocated interrupt. + */ + + if (oldhandler != NULL) + { + ESP32_WTD_SETISR(priv->wtd, NULL, NULL); + } + else + { + /* If it was previous configured to reset on timeout + * then change to interrupt. + */ + + ESP32_WTD_STG_CONF(priv->wtd, STAGE_0, INTERRUPT_ON_TIMEOUT); + } + + /* Set the lower half handler and enable interrupt */ + + ESP32_WTD_SETISR(priv->wtd, esp32_wdt_handler, priv); + ESP32_WTD_ENABLEINT(priv->wtd); + } + + /* In case the user wants to disable the callback */ + + else + { + ESP32_WTD_DISABLEINT(priv->wtd); + ESP32_WTD_SETISR(priv->wtd, NULL, NULL); + + /* Then configure it to reset on wdt expiration */ + + if (priv->peripheral == TIMER) + { + ESP32_WTD_STG_CONF(priv->wtd, STAGE_0, RESET_SYSTEM_TIMER); + } + else + { + ESP32_WTD_STG_CONF(priv->wtd, STAGE_0, RESET_SYSTEM_RTC); + } + } + + leave_critical_section(flags); + ESP32_WTD_LOCK(priv->wtd); + return oldhandler; +} + +/* Interrupt handling *******************************************************/ + +static int esp32_wdt_handler(int irq, FAR void *context, FAR void *arg) +{ + FAR struct esp32_wtd_lowerhalf_s *priv = arg; + + ESP32_WTD_UNLOCK(priv->wtd); + + /* Updates last reset var and feed the dog to reload the counter and + * to allow the application to continue executing. + */ +#ifdef CONFIG_DEBUG_WATCHDOG + priv->lastreset = clock_systime_ticks(); +#endif + ESP32_WTD_FEED(priv->wtd); + + /* Run the user callback */ + + priv->handler(irq, context, NULL); + + ESP32_WTD_ACKINT(priv->wtd); /* Clear the Interrupt */ + ESP32_WTD_LOCK(priv->wtd); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_wtd_initialize + * + * Description: + * Initialize the WDT watchdog timer. The watchdog timer is initialized + * and registerd as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the watchdog. This should + * be of the form/dev/watchdog0 + * watchdog timer instance - A number do indicate which one is being used + * + * Returned Values: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int esp32_wtd_initialize(FAR const char *devpath, uint8_t wdt) +{ + struct esp32_wtd_lowerhalf_s *lower = NULL; + FAR void *handle = NULL; + int ret = OK; + + DEBUGASSERT(devpath); + + switch (wdt) + { +#ifdef CONFIG_ESP32_MWDT0 + case 0: + { + lower = &g_esp32_mwdt0_lowerhalf; + lower->peripheral = TIMER; + break; + } +#endif + +#ifdef CONFIG_ESP32_MWDT1 + case 1: + { + lower = &g_esp32_mwdt1_lowerhalf; + lower->peripheral = TIMER; + break; + } +#endif + +#ifdef CONFIG_ESP32_RWDT + case 2: + { + lower = &g_esp32_rwdt_lowerhalf; + lower->peripheral = RTC; + break; + } +#endif + + default: + { + ret = -ENODEV; + goto errout; + } + } + + /* Initialize the elements of lower half state structure */ + + lower->started = false; + lower->handler = NULL; + lower->timeout = 0; + lower->wtd = esp32_wtd_init(wdt); + + if (lower->wtd == NULL) + { + ret = -EINVAL; + goto errout; + } + + ESP32_WTD_UNLOCK(lower->wtd); + + /* Ensure stages are disabled and Flash boot protection was disabled */ + + ESP32_WTD_INITCONF(lower->wtd); + + /* If it is a Main System Watchdog Timer configure the Prescale to + * have a 500us period. + */ + + if (lower->peripheral == TIMER) + { + ESP32_WTD_PRE(lower->wtd, PRE_VALUE); + } + + ESP32_WTD_LOCK(lower->wtd); + + /* Register the watchdog driver as /dev/watchdogX. The returned value from + * watchdog_register is a handle that could be used with + * watchdog_unregister(). REVISIT: The returned handle is discarded here. + */ + + handle = watchdog_register(devpath, + (FAR struct watchdog_lowerhalf_s *)lower); + if (handle == NULL) + { + /* The actual cause of the failure may have been a failure to allocate + * perhaps a failure to register the watchdog driver (such as if the + * 'devpath' were not unique). We know here but we return EEXIST to + * indicate the failure (implying the non-unique devpath). + */ + + ret = -EEXIST; + goto errout; + } + +errout: + return ret; +} diff --git a/arch/xtensa/src/esp32/esp32_wtd_lowerhalf.h b/arch/xtensa/src/esp32/esp32_wtd_lowerhalf.h new file mode 100644 index 0000000000..517788c355 --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_wtd_lowerhalf.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_wtd_lowerhalf.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_XTENSA_SRC_ESP32_ESP32_WTD_LOWERHALF_H +#define __ARCH_XTENSA_SRC_ESP32_ESP32_WTD_LOWERHALF_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum wdt_peripherals +{ + RTC, + TIMER, +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_timer_initialize + ****************************************************************************/ + +int esp32_wtd_initialize(FAR const char *devpath, uint8_t timer); + +#endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_WTD_LOWERHALF_H */ diff --git a/arch/xtensa/src/esp32/hardware/esp32_rtccntl.h b/arch/xtensa/src/esp32/hardware/esp32_rtccntl.h index 2923016029..f5d479cef4 100644 --- a/arch/xtensa/src/esp32/hardware/esp32_rtccntl.h +++ b/arch/xtensa/src/esp32/hardware/esp32_rtccntl.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/xtensa/src/esp32/hardware/esp32_rtccnt.h + * arch/xtensa/src/esp32/hardware/esp32_rtccntl.h * * Adapted from use in NuttX by: * @@ -37,6 +37,26 @@ * Pre-processor Definitions ****************************************************************************/ +/* WTD defines */ + +/* Offset relative to each wathdog timer instance memory base */ + +/* RWDT */ +#define RWDT_CONFIG0_OFFSET 0x008c +#define RWDT_STAGE0_TIMEOUT_OFFSET 0x0090 +#define RWDT_STAGE1_TIMEOUT_OFFSET 0x0094 +#define RWDT_STAGE2_TIMEOUT_OFFSET 0x0098 +#define RWDT_STAGE3_TIMEOUT_OFFSET 0x009c +#define RWDT_WP_REG 0x00a4 +#define RWDT_FEED_OFFSET 0x00a0 +#define RCLK_CONF_REG_OFFSET 0x0070 +#define RWDT_INT_ENA_REG_OFFSET 0x003c +#define RWDT_INT_CLR_REG_OFFSET 0x0048 + +/* CLK */ +#define CK_XTAL_32K_MASK (BIT(30)) +#define CK8M_D256_OUT_MASK (BIT(31)) + #define RTC_CNTL_OPTIONS0_REG (DR_REG_RTCCNTL_BASE + 0x0) /* RTC_CNTL_SW_SYS_RST : WO ;bitpos:[31] ;default: 1'd0 ; */ diff --git a/arch/xtensa/src/esp32/hardware/esp32_soc.h b/arch/xtensa/src/esp32/hardware/esp32_soc.h index 3bda223763..2109315fad 100644 --- a/arch/xtensa/src/esp32/hardware/esp32_soc.h +++ b/arch/xtensa/src/esp32/hardware/esp32_soc.h @@ -197,7 +197,7 @@ #define APB_CLK_FREQ 80 * 1000000 /* Unit: Hz */ #define REF_CLK_FREQ (1000000) #define UART_CLK_FREQ APB_CLK_FREQ -#define WDT_CLK_FREQ APB_CLK_FREQ +#define MWDT_CLK_FREQ APB_CLK_FREQ #define TIMER_CLK_FREQ (80000000 >> 4) /* 80MHz divided by 16 */ #define SPI_CLK_DIV 4 #define TICKS_PER_US_ROM 26 /* CPU is 80MHz */ diff --git a/arch/xtensa/src/esp32/hardware/esp32_tim.h b/arch/xtensa/src/esp32/hardware/esp32_tim.h index e032252368..c2f1a8fdd5 100644 --- a/arch/xtensa/src/esp32/hardware/esp32_tim.h +++ b/arch/xtensa/src/esp32/hardware/esp32_tim.h @@ -46,6 +46,25 @@ #define TIM1_INT_ST_OFFSET 0x007c #define LOW_32_MASK 0xffffffff +/* WTD defines */ + +#define WRITE_PROTECTION_KEY 0x050d83aa1 + +/* Offset relative to each watchdog timer instance memory base */ + +#define MWDT_CONFIG0_OFFSET 0x0000 + +/* MWDTs */ + +#define MWDT_CLK_PRESCALE_OFFSET 0x0004 +#define MWDT_STAGE0_TIMEOUT_OFFSET 0x0008 +#define MWDT_STAGE1_TIMEOUT_OFFSET 0x000c +#define MWDT_STAGE2_TIMEOUT_OFFSET 0x0010 +#define MWDT_STAGE3_TIMEOUT_OFFSET 0x0014 +#define MWDT_WP_REG 0x001c +#define MWDT_FEED_OFFSET 0x0018 +#define MWDT_INT_ENA_REG_OFFSET 0x0050 +#define MWDT_INT_CLR_REG_OFFSET 0x005c /* The value that needs to be written to TIMG_WDT_WKEY to write-enable the wdt * registers */ diff --git a/boards/xtensa/esp32/esp32-core/configs/watchdog/defconfig b/boards/xtensa/esp32/esp32-core/configs/watchdog/defconfig new file mode 100644 index 0000000000..ee36d17eb5 --- /dev/null +++ b/boards/xtensa/esp32/esp32-core/configs/watchdog/defconfig @@ -0,0 +1,55 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_LEDS is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_CMDPARMS is not set +CONFIG_ARCH="xtensa" +CONFIG_ARCH_BOARD="esp32-core" +CONFIG_ARCH_BOARD_ESP32CORE=y +CONFIG_ARCH_CHIP="esp32" +CONFIG_ARCH_CHIP_ESP32=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_XTENSA=y +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_WATCHDOG=y +CONFIG_ESP32_MWDT0=y +CONFIG_ESP32_MWDT1=y +CONFIG_ESP32_UART0=y +CONFIG_EXAMPLES_WATCHDOG=y +CONFIG_EXPERIMENTAL=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=3072 +CONFIG_INTELHEX_BINARY=y +CONFIG_MAX_TASKS=16 +CONFIG_MM_REGIONS=2 +CONFIG_NFILE_DESCRIPTORS=8 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=114688 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_SPI=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_SYSTEM_NSH=y +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_USER_ENTRYPOINT="nsh_main" +CONFIG_WATCHDOG=y diff --git a/boards/xtensa/esp32/esp32-core/src/Makefile b/boards/xtensa/esp32/esp32-core/src/Makefile index 4b7204fb08..67d21b1ca5 100644 --- a/boards/xtensa/esp32/esp32-core/src/Makefile +++ b/boards/xtensa/esp32/esp32-core/src/Makefile @@ -70,6 +70,12 @@ ifeq ($(CONFIG_USERLED),y) CSRCS += esp32_userleds.c endif +ifeq ($(CONFIG_WATCHDOG),y) +ifeq ($(CONFIG_ESP32_WTD),y) +CSRCS += esp32_wtd.c +endif +endif + SCRIPTIN = $(SCRIPTDIR)$(DELIM)esp32.template.ld SCRIPTOUT = $(SCRIPTDIR)$(DELIM)esp32_out.ld diff --git a/boards/xtensa/esp32/esp32-core/src/esp32-core.h b/boards/xtensa/esp32/esp32-core/src/esp32-core.h index b7b678f962..0bce83f0f3 100644 --- a/boards/xtensa/esp32/esp32-core/src/esp32-core.h +++ b/boards/xtensa/esp32/esp32-core/src/esp32-core.h @@ -104,7 +104,18 @@ int esp32_spiflash_init(void); ****************************************************************************/ #ifdef CONFIG_TIMER -int esp32_timer_driver_setup(FAR const char *devpath, int timer); +int esp32_timer_driver_init(void); +#endif +/**************************************************************************** + * Name: esp32_wdt_driver_init + * + * Description: + * Initialize WATCHDOG driver. + * + ****************************************************************************/ + +#ifdef CONFIG_WATCHDOG +int esp32_wtd_driver_init(void); #endif #endif /* __ASSEMBLY__ */ diff --git a/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c b/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c index c0107248bb..c337c062de 100644 --- a/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c +++ b/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c @@ -49,6 +49,7 @@ #include #include #include +#include #ifdef CONFIG_TIMER # include @@ -72,22 +73,6 @@ * Pre-processor Definitions ****************************************************************************/ -#ifdef CONFIG_ESP32_TIMER0 -#define ESP32_TIMER0 (0) -#endif - -#ifdef CONFIG_ESP32_TIMER1 -#define ESP32_TIMER1 (1) -#endif - -#ifdef CONFIG_ESP32_TIMER2 -#define ESP32_TIMER2 (2) -#endif - -#ifdef CONFIG_ESP32_TIMER3 -#define ESP32_TIMER3 (3) -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -219,45 +204,15 @@ int esp32_bringup(void) #ifdef CONFIG_TIMER /* Configure TIMER driver */ -#ifdef CONFIG_ESP32_TIMER0 - ret = esp32_timer_driver_setup("/dev/timer0", ESP32_TIMER0); - if (ret < 0) - { - syslog(LOG_ERR, - "ERROR: Failed to initialize timer driver: %d\n", - ret); - } -#endif -#ifdef CONFIG_ESP32_TIMER1 - ret = esp32_timer_driver_setup("/dev/timer1", ESP32_TIMER1); + ret = esp32_timer_driver_init(); if (ret < 0) { syslog(LOG_ERR, - "ERROR: Failed to initialize timer driver: %d\n", + "ERROR: Failed to initialize timer drivers: %d\n", ret); } -#endif -#ifdef CONFIG_ESP32_TIMER2 - ret = esp32_timer_driver_setup("/dev/timer2", ESP32_TIMER2); - if (ret < 0) - { - syslog(LOG_ERR, - "ERROR: Failed to initialize timer driver: %d\n", - ret); - } -#endif - -#ifdef CONFIG_ESP32_TIMER3 - ret = esp32_timer_driver_setup("/dev/timer3", ESP32_TIMER3); - if (ret < 0) - { - syslog(LOG_ERR, - "ERROR: Failed to initialize timer driver: %d\n", - ret); - } -#endif #endif #ifdef CONFIG_USERLED @@ -270,6 +225,19 @@ int esp32_bringup(void) } #endif +#ifdef CONFIG_WATCHDOG + /* Configure WATCHDOG driver */ + + ret = esp32_wtd_driver_init(); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to initialize watchdog drivers: %d\n", + ret); + } + +#endif + /* If we got here then perhaps not all initialization was successful, but * at least enough succeeded to bring-up NSH with perhaps reduced * capabilities. diff --git a/boards/xtensa/esp32/esp32-core/src/esp32_timer.c b/boards/xtensa/esp32/esp32-core/src/esp32_timer.c index 8918740e3d..20c3e5995f 100644 --- a/boards/xtensa/esp32/esp32-core/src/esp32_timer.c +++ b/boards/xtensa/esp32/esp32-core/src/esp32_timer.c @@ -24,12 +24,30 @@ #include #include - #include - #include "esp32_tim_lowerhalf.h" - #include "esp32-core.h" +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_ESP32_TIMER0 +#define ESP32_TIMER0 (0) +#endif + +#ifdef CONFIG_ESP32_TIMER1 +#define ESP32_TIMER1 (1) +#endif + +#ifdef CONFIG_ESP32_TIMER2 +#define ESP32_TIMER2 (2) +#endif + +#ifdef CONFIG_ESP32_TIMER3 +#define ESP32_TIMER3 (3) +#endif /**************************************************************************** * Public Functions @@ -52,7 +70,53 @@ * ****************************************************************************/ -int esp32_timer_driver_setup(FAR const char *devpath, int timer) +int esp32_timer_driver_init(void) { - return esp32_timer_initialize(devpath, timer); + int ret = OK; + #ifdef CONFIG_ESP32_TIMER0 + ret = esp32_timer_initialize("/dev/timer0", ESP32_TIMER0); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to initialize timer driver: %d\n", + ret); + goto errout; + } +#endif + +#ifdef CONFIG_ESP32_TIMER1 + ret = esp32_timer_initialize("/dev/timer1", ESP32_TIMER1); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to initialize timer driver: %d\n", + ret); + goto errout; + } +#endif + +#ifdef CONFIG_ESP32_TIMER2 + ret = esp32_timer_initialize("/dev/timer2", ESP32_TIMER2); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to initialize timer driver: %d\n", + ret); + goto errout; + } +#endif + +#ifdef CONFIG_ESP32_TIMER3 + ret = esp32_timer_initialize("/dev/timer3", ESP32_TIMER3); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to initialize timer driver: %d\n", + ret); + goto errout; + } +#endif + +errout: + return ret; } diff --git a/boards/xtensa/esp32/esp32-core/src/esp32_wtd.c b/boards/xtensa/esp32/esp32-core/src/esp32_wtd.c new file mode 100644 index 0000000000..699704ab55 --- /dev/null +++ b/boards/xtensa/esp32/esp32-core/src/esp32_wtd.c @@ -0,0 +1,110 @@ +/**************************************************************************** + * boards/xtensa/esp32/esp32-core/src/esp32_wtd.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 "esp32_wtd_lowerhalf.h" +#include "esp32-core.h" +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_ESP32_MWDT0 +#define ESP32_MWDT0 (0) +#endif + +#ifdef CONFIG_ESP32_MWDT1 +#define ESP32_MWDT1 (1) +#endif + +#ifdef CONFIG_ESP32_RWDT +#define ESP32_RWDT (2) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_wtd_driver_init + * + * Description: + * Configure the timer driver. + * + * Input Parameters: + * devpath - The full path to the timer device. This should be of the + * form /dev/watchdogX + * wdt timer - The wdt timer's number. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int esp32_wtd_driver_init(void) +{ + int ret = OK; + +#ifdef CONFIG_ESP32_MWDT0 + ret = esp32_wtd_initialize("/dev/watchdog0", ESP32_MWDT0); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to initialize watchdog driver: %d\n", + ret); + goto errout; + } + +#endif + +#ifdef CONFIG_ESP32_MWDT1 + ret = esp32_wtd_initialize("/dev/watchdog1", ESP32_MWDT1); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to initialize watchdog driver: %d\n", + ret); + goto errout; + } + +#endif + +#ifdef CONFIG_ESP32_RWDT + ret = esp32_wtd_initialize("/dev/watchdog2", ESP32_RWDT); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to initialize watchdog driver: %d\n", + ret); + goto errout; + } + +#endif + +errout: + return ret; +}