diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index bd6fbf465d1..16147815e70 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -33,6 +33,6 @@ zephyr_library_sources_ifdef(CONFIG_WDT_NXP_S32 wdt_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_WDT_SMARTBOND wdt_smartbond.c) zephyr_library_sources_ifdef(CONFIG_WDT_TI_TPS382X wdt_ti_tps382x.c) -zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c) +zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c wdt_dw_common.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE wdt_handlers.c) diff --git a/drivers/watchdog/wdt_dw.c b/drivers/watchdog/wdt_dw.c index a31911c5572..f41b3b1b2cd 100644 --- a/drivers/watchdog/wdt_dw.c +++ b/drivers/watchdog/wdt_dw.c @@ -13,11 +13,10 @@ #include #include "wdt_dw.h" +#include "wdt_dw_common.h" LOG_MODULE_REGISTER(wdt_dw, CONFIG_WDT_LOG_LEVEL); -#define WDT_DW_FLAG_CONFIGURED 0x80000000 - #define WDT_IS_INST_IRQ_EN(inst) DT_NODE_HAS_PROP(DT_DRV_INST(inst), interrupts) #define WDT_CHECK_INTERRUPT_USED(inst) WDT_IS_INST_IRQ_EN(inst) || #define WDT_DW_INTERRUPT_SUPPORT DT_INST_FOREACH_STATUS_OKAY(WDT_CHECK_INTERRUPT_USED) 0 @@ -44,55 +43,21 @@ static int dw_wdt_setup(const struct device *dev, uint8_t options) { const struct dw_wdt_dev_cfg *const dev_config = dev->config; struct dw_wdt_dev_data *const dev_data = dev->data; - uint32_t period; - if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) { - LOG_ERR("Pausing watchdog by debugger is not supported."); - return -ENOTSUP; - } - - if (options & WDT_OPT_PAUSE_IN_SLEEP) { - LOG_ERR("Pausing watchdog in sleep is not supported."); - return -ENOTSUP; - } - - if (!(dev_data->config & WDT_DW_FLAG_CONFIGURED)) { - LOG_ERR("Timeout not installed."); - return -ENOTSUP; - } - - /* Configure timeout */ - period = dev_data->config & ~WDT_DW_FLAG_CONFIGURED; - - if (dw_wdt_dual_timeout_period_get(dev_config->base)) { - dw_wdt_timeout_period_init_set(dev_config->base, period); - } - - dw_wdt_timeout_period_set(dev_config->base, period); + dw_wdt_check_options(options); #if WDT_DW_INTERRUPT_SUPPORT /* Configure response mode */ dw_wdt_response_mode_set(dev_config->base, !!dev_data->callback); #endif - /* Enable watchdog */ - dw_wdt_enable(dev_config->base); - dw_wdt_counter_restart(dev_config->base); - - return 0; -} - -static int dw_wdt_disable(const struct device *dev) -{ - return -ENOTSUP; + return dw_wdt_configure(dev_config->base, dev_data->config); } static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *config) { const struct dw_wdt_dev_cfg *const dev_config = dev->config; struct dw_wdt_dev_data *const dev_data = dev->data; - uint64_t period64; - uint32_t period; #if WDT_DW_INTERRUPT_SUPPORT if (config->callback && !dev_config->irq_config) { @@ -103,36 +68,17 @@ static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_tim return -ENOTSUP; } - /* Window timeout is not supported by this driver */ - if (config->window.min) { - LOG_ERR("Window timeout is not supported."); - return -ENOTSUP; - } - if (config->flags) { LOG_ERR("Watchdog behavior is not configurable."); return -ENOTSUP; } - period64 = (uint64_t)dev_config->clk_freq * config->window.max; - period64 /= 1000; - if (!period64 || (period64 >> 31)) { - LOG_ERR("Window max is out of range."); - return -EINVAL; - } - - period = period64 - 1; - period = ilog2(period); - - if (period >= dw_wdt_cnt_width_get(dev_config->base)) { - LOG_ERR("Watchdog timeout too long."); - return -EINVAL; - } - - /* The minimum counter value is 64k, maximum 2G */ - dev_data->config = WDT_DW_FLAG_CONFIGURED | (period >= 15 ? period - 15 : 0); +#ifdef WDT_DW_INTERRUPT_SUPPORT dev_data->callback = config->callback; - return 0; +#endif + + return dw_wdt_calc_period(dev_config->base, dev_config->clk_freq, config, + &dev_data->config); } static int dw_wdt_feed(const struct device *dev, int channel_id) @@ -159,14 +105,11 @@ static const struct wdt_driver_api dw_wdt_api = { static int dw_wdt_init(const struct device *dev) { const struct dw_wdt_dev_cfg *const dev_config = dev->config; + int ret; - /* Check component type */ - if (dw_wdt_comp_type_get(dev_config->base) != WDT_COMP_TYPE_VALUE) { - LOG_ERR("Invalid component type %x", dw_wdt_comp_type_get(dev_config->base)); - return -ENODEV; - } - - dw_wdt_reset_pulse_length_set(dev_config->base, dev_config->reset_pulse_length); + ret = dw_wdt_probe(dev_config->base, dev_config->reset_pulse_length); + if (ret) + return ret; #if WDT_DW_INTERRUPT_SUPPORT if (dev_config->irq_config) { diff --git a/drivers/watchdog/wdt_dw_common.c b/drivers/watchdog/wdt_dw_common.c new file mode 100644 index 00000000000..7c7a1532d15 --- /dev/null +++ b/drivers/watchdog/wdt_dw_common.c @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (c) 2023 Intel Corporation + * + * Author: Adrian Warecki + */ + +#include +#include +#include +#include + +#include "wdt_dw_common.h" +#include "wdt_dw.h" + +LOG_MODULE_REGISTER(wdt_dw_common, CONFIG_WDT_LOG_LEVEL); + +#define WDT_DW_FLAG_CONFIGURED 0x80000000 + +int dw_wdt_check_options(const uint8_t options) +{ + if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) { + LOG_ERR("Pausing watchdog by debugger is not supported."); + return -ENOTSUP; + } + + if (options & WDT_OPT_PAUSE_IN_SLEEP) { + LOG_ERR("Pausing watchdog in sleep is not supported."); + return -ENOTSUP; + } + + return 0; +} + +int dw_wdt_configure(const uint32_t base, const uint32_t config) +{ + uint32_t period; + + if (!(config & WDT_DW_FLAG_CONFIGURED)) { + LOG_ERR("Timeout not installed."); + return -ENOTSUP; + } + + /* Configure timeout */ + period = config & ~WDT_DW_FLAG_CONFIGURED; + + if (dw_wdt_dual_timeout_period_get(base)) { + dw_wdt_timeout_period_init_set(base, period); + } + + dw_wdt_timeout_period_set(base, period); + + /* Enable watchdog */ + dw_wdt_enable(base); + dw_wdt_counter_restart(base); + + return 0; +} + +int dw_wdt_calc_period(const uint32_t base, const uint32_t clk_freq, + const struct wdt_timeout_cfg *config, uint32_t *period_out) +{ + uint64_t period64; + uint32_t period; + + /* Window timeout is not supported by this driver */ + if (config->window.min) { + LOG_ERR("Window timeout is not supported."); + return -ENOTSUP; + } + + period64 = (uint64_t)clk_freq * config->window.max; + period64 /= 1000; + if (!period64 || (period64 >> 31)) { + LOG_ERR("Window max is out of range."); + return -EINVAL; + } + + period = period64 - 1; + period = ilog2(period); + + if (period >= dw_wdt_cnt_width_get(base)) { + LOG_ERR("Watchdog timeout too long."); + return -EINVAL; + } + + /* The minimum counter value is 64k, maximum 2G */ + *period_out = WDT_DW_FLAG_CONFIGURED | (period >= 15 ? period - 15 : 0); + return 0; +} + +int dw_wdt_probe(const uint32_t base, const uint32_t reset_pulse_length) +{ + /* Check component type */ + const uint32_t type = dw_wdt_comp_type_get(base); + + if (type != WDT_COMP_TYPE_VALUE) { + LOG_ERR("Invalid component type %x", type); + return -ENODEV; + } + + dw_wdt_reset_pulse_length_set(base, reset_pulse_length); + + return 0; +} + +int dw_wdt_disable(const struct device *dev) +{ + return -ENOTSUP; +} diff --git a/drivers/watchdog/wdt_dw_common.h b/drivers/watchdog/wdt_dw_common.h new file mode 100644 index 00000000000..04aaa70c1a9 --- /dev/null +++ b/drivers/watchdog/wdt_dw_common.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (c) 2023 Intel Corporation + * + * Author: Adrian Warecki + */ + +#ifndef ZEPHYR_DRIVERS_WATCHDOG_WDT_DW_COMMON_H_ +#define ZEPHYR_DRIVERS_WATCHDOG_WDT_DW_COMMON_H_ + +#include + +/** + * @brief Check watchdog configuration options + * + * Check options value passed to a watchdog setup function. Returns error if unsupported option + * is used. + * + * @param options options value passed to a watchdog setup function. + * @return Error code, 0 on success. + */ +int dw_wdt_check_options(const uint8_t options); + +/** + * @brief Configure watchdog device + * + * @param base Device base address. + * @param config device configuration word + * @return Error code, 0 on success. + */ +int dw_wdt_configure(const uint32_t base, const uint32_t config); + +/** + * @brief Calculate period + * + * @param [in]base Device base address. + * @param [in]clk_freq frequency of a clock used by watchdog device + * @param [in]config pointer to a watchdog configuration structure + * @param [out]period_out pointer to a variable in which the period configuration word will be + * placed + * @return Error code, 0 on success. + */ +int dw_wdt_calc_period(const uint32_t base, const uint32_t clk_freq, + const struct wdt_timeout_cfg *config, uint32_t *period_out); + +/** + * @brief Watchdog probe + * + * Checks device id register and configure a reset pulse length. + * + * @param base Device base address. + * @param reset_pulse_length Length of a reset pulse produced by watchdog + * @return Error code, 0 on success. + */ +int dw_wdt_probe(const uint32_t base, const uint32_t reset_pulse_length); + +/** + * @brief Watchdog disable function + * + * @param dev Device structure. + * @return -ENOTSUP. The hardware does not support disabling. + */ +int dw_wdt_disable(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_WATCHDOG_WDT_DW_COMMON_H_ */