diff --git a/cpu/fe310/Makefile.features b/cpu/fe310/Makefile.features index d55eea478d..b439b69c3b 100644 --- a/cpu/fe310/Makefile.features +++ b/cpu/fe310/Makefile.features @@ -4,4 +4,5 @@ FEATURES_PROVIDED += cpp FEATURES_PROVIDED += periph_cpuid FEATURES_PROVIDED += periph_gpio periph_gpio_irq FEATURES_PROVIDED += periph_pm +FEATURES_PROVIDED += periph_wdt FEATURES_PROVIDED += ssp diff --git a/cpu/fe310/include/periph_cpu.h b/cpu/fe310/include/periph_cpu.h index c944f9ee39..58a918e2aa 100644 --- a/cpu/fe310/include/periph_cpu.h +++ b/cpu/fe310/include/periph_cpu.h @@ -138,6 +138,28 @@ typedef struct { i2c_speed_t speed; /**< I2C speed */ } i2c_conf_t; +/** + * @name WDT upper and lower bound times in ms + * @{ + */ +#define NWDT_TIME_LOWER_LIMIT (1) +/* Ensure the internal "count" variable stays within the uint32 bounds. + This variable corresponds to max_time * RTC_FREQ / MS_PER_SEC. On fe310, + RTC_FREQ is 32768Hz. The 15 right shift is equivalent to a division by RTC_FREQ. + */ +#define NWDT_TIME_UPPER_LIMIT ((UINT32_MAX >> 15) * MS_PER_SEC + 1) +/** @} */ + +/** + * @brief WDT interrupt priority: use highest priority + */ +#define WDT_INTR_PRIORITY (PLIC_NUM_PRIORITIES) + +/** + * @brief WDT can be stopped + */ +#define WDT_HAS_STOP (1) + #ifdef __cplusplus } #endif diff --git a/cpu/fe310/periph/wdt.c b/cpu/fe310/periph/wdt.c new file mode 100644 index 0000000000..2c717a2081 --- /dev/null +++ b/cpu/fe310/periph/wdt.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2019 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_fe310 + * @ingroup drivers_periph_wdt + * @{ + * + * @file + * @brief Implementation of the watchdog peripheral interface + * + * @author Alexandre Abadie + * + * @} + */ + +#include +#include + +#include "cpu.h" +#include "timex.h" + +#include "periph/wdt.h" + +#include "vendor/aon.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +void wdt_start(void) +{ + DEBUG("[wdt] start watchdog\n"); + + AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE; + AON_REG(AON_WDOGCFG) |= AON_WDOGCFG_ENCOREAWAKE; +} + +void wdt_stop(void) +{ + DEBUG("[wdt] stop watchdog\n"); + + AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE; + AON_REG(AON_WDOGCFG) &= ~(AON_WDOGCFG_ENCOREAWAKE); +} + +void wdt_kick(void) +{ + DEBUG("[wdt] reload the watchdog\n"); + + AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE; + AON_REG(AON_WDOGFEED) = AON_WDOGFEED_VALUE; +} + +static inline uint8_t _scale(uint32_t count) +{ + uint8_t scale = 0; + while (count > (UINT16_MAX - 1)) { + count >>= 1; + scale++; + } + + return scale; +} + +static inline uint8_t _setup(uint32_t min_time, uint32_t max_time) +{ + (void)min_time; + + /* Windowed wdt not supported */ + assert(min_time == 0); + + /* Check reset time limit */ + assert((max_time > NWDT_TIME_LOWER_LIMIT) || \ + (max_time < NWDT_TIME_UPPER_LIMIT)); + + uint32_t count = ((uint32_t)max_time * RTC_FREQ) / MS_PER_SEC; + uint8_t scale = _scale(count); + + AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE; + AON_REG(AON_WDOGCMP) = count; + + return scale; +} + +void wdt_setup_reboot(uint32_t min_time, uint32_t max_time) +{ + uint8_t scale = _setup(min_time, max_time); + + AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE; + AON_REG(AON_WDOGCFG) = AON_WDOGCFG_RSTEN | AON_WDOGCFG_ZEROCMP | scale; + + DEBUG("[wdt] watchdog setup complete\n"); +}