From 237b34ef2da4cca6b412d0e85300a42ef506a0df Mon Sep 17 00:00:00 2001 From: Crist Xu Date: Mon, 27 Jul 2020 12:29:58 +0800 Subject: [PATCH] watchdog: Add watchdog driver Add watchdog driver for the RT1050/60 Signed-off-by: Crist Xu --- boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts | 5 + boards/arm/mimxrt1050_evk/mimxrt1050_evk.yaml | 1 + .../mimxrt1050_evk/mimxrt1050_evk_qspi.yaml | 1 + boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts | 5 + boards/arm/mimxrt1060_evk/mimxrt1060_evk.yaml | 1 + .../mimxrt1060_evk_hyperflash.yaml | 1 + drivers/watchdog/CMakeLists.txt | 1 + drivers/watchdog/Kconfig | 2 + drivers/watchdog/Kconfig.mcux_imx | 10 ++ drivers/watchdog/wdt_mcux_imx_wdog.c | 167 ++++++++++++++++++ dts/arm/nxp/nxp_rt.dtsi | 16 ++ dts/bindings/watchdog/nxp,imx-wdog.yaml | 18 ++ soc/arm/nxp_imx/rt/Kconfig.defconfig.series | 4 + .../watchdog/wdt_basic_api/src/test_wdt.c | 12 +- 14 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 drivers/watchdog/Kconfig.mcux_imx create mode 100644 drivers/watchdog/wdt_mcux_imx_wdog.c create mode 100644 dts/bindings/watchdog/nxp,imx-wdog.yaml diff --git a/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts b/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts index c66ff8f3ab1..05523ccb46e 100644 --- a/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts +++ b/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts @@ -16,6 +16,7 @@ led0 = &green_led; sw0 = &user_button; kscan0 = &touch_controller; + watchdog0 = &wdog0; }; chosen { @@ -156,3 +157,7 @@ arduino_serial: &lpuart3 {}; pwr-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; cd-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; }; + +&wdog0 { + status = "okay"; +}; diff --git a/boards/arm/mimxrt1050_evk/mimxrt1050_evk.yaml b/boards/arm/mimxrt1050_evk/mimxrt1050_evk.yaml index df5514d89bc..8210e3316dc 100644 --- a/boards/arm/mimxrt1050_evk/mimxrt1050_evk.yaml +++ b/boards/arm/mimxrt1050_evk/mimxrt1050_evk.yaml @@ -25,3 +25,4 @@ supported: - spi - usb_device - kscan:touch + - watchdog diff --git a/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.yaml b/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.yaml index 60fe3df9b31..9104eb727c9 100644 --- a/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.yaml +++ b/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.yaml @@ -24,3 +24,4 @@ supported: - sdhc - spi - usb_device + - watchdog diff --git a/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts b/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts index 315ae39b957..bed08cf5a07 100644 --- a/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts +++ b/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts @@ -16,6 +16,7 @@ led0 = &green_led; sw0 = &user_button; kscan0 = &touch_controller; + watchdog0 = &wdog0; }; chosen { @@ -153,3 +154,7 @@ arduino_serial: &lpuart3 {}; status = "okay"; bus-speed = <125000>; }; + +&wdog0 { + status = "okay"; +}; diff --git a/boards/arm/mimxrt1060_evk/mimxrt1060_evk.yaml b/boards/arm/mimxrt1060_evk/mimxrt1060_evk.yaml index 40446209108..6335b130b2d 100644 --- a/boards/arm/mimxrt1060_evk/mimxrt1060_evk.yaml +++ b/boards/arm/mimxrt1060_evk/mimxrt1060_evk.yaml @@ -26,3 +26,4 @@ supported: - kscan:touch - dma - can + - watchdog diff --git a/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.yaml b/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.yaml index 7acc4148b4e..421df62d65e 100644 --- a/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.yaml +++ b/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.yaml @@ -23,3 +23,4 @@ supported: - netif:eth - sdhc - usb_device + - watchdog diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index 745af7a681f..bbf9540b8e4 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -7,6 +7,7 @@ zephyr_sources_ifdef(CONFIG_WDT_SAM wdt_sam.c) zephyr_sources_ifdef(CONFIG_WDT_ESP32 wdt_esp32.c) zephyr_sources_ifdef(CONFIG_WDT_SAM0 wdt_sam0.c) zephyr_sources_ifdef(CONFIG_WDT_NRFX wdt_nrfx.c) +zephyr_sources_ifdef(CONFIG_WDT_MCUX_IMX_WDOG wdt_mcux_imx_wdog.c) zephyr_sources_ifdef(CONFIG_WDT_MCUX_WDOG wdt_mcux_wdog.c) zephyr_sources_ifdef(CONFIG_WDT_MCUX_WDOG32 wdt_mcux_wdog32.c) zephyr_sources_ifdef(CONFIG_WDT_MCUX_WWDT wdt_mcux_wwdt.c) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 5d7c4f76ad6..dde6f5fccf7 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -44,6 +44,8 @@ source "drivers/watchdog/Kconfig.nrfx" source "drivers/watchdog/Kconfig.mcux" +source "drivers/watchdog/Kconfig.mcux_imx" + source "drivers/watchdog/Kconfig.xec" source "drivers/watchdog/Kconfig.gecko" diff --git a/drivers/watchdog/Kconfig.mcux_imx b/drivers/watchdog/Kconfig.mcux_imx new file mode 100644 index 00000000000..4e8763d54a8 --- /dev/null +++ b/drivers/watchdog/Kconfig.mcux_imx @@ -0,0 +1,10 @@ +# Watchdog configuration options + +# Copyright (c) 2020, NXP +# SPDX-License-Identifier: Apache-2.0 + +config WDT_MCUX_IMX_WDOG + bool "MCUX IMX WDOG driver" + depends on HAS_MCUX + help + Enable the mcux imx wdog driver. diff --git a/drivers/watchdog/wdt_mcux_imx_wdog.c b/drivers/watchdog/wdt_mcux_imx_wdog.c new file mode 100644 index 00000000000..9e897db6258 --- /dev/null +++ b/drivers/watchdog/wdt_mcux_imx_wdog.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2020, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_imx_wdog + +#include +#include + +#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL +#include +LOG_MODULE_REGISTER(wdt_mcux_wdog); + +#define WDOG_TMOUT_SEC(x) ((x * 2 / MSEC_PER_SEC) - 1) + +struct mcux_wdog_config { + WDOG_Type *base; + void (*irq_config_func)(const struct device *dev); +}; + +struct mcux_wdog_data { + wdt_callback_t callback; + wdog_config_t wdog_config; + bool timeout_valid; +}; + +static int mcux_wdog_setup(const struct device *dev, uint8_t options) +{ + const struct mcux_wdog_config *config = dev->config; + struct mcux_wdog_data *data = dev->data; + WDOG_Type *base = config->base; + + if (!data->timeout_valid) { + LOG_ERR("No valid timeouts installed"); + return -EINVAL; + } + + data->wdog_config.workMode.enableStop = + (options & WDT_OPT_PAUSE_IN_SLEEP) == 0U; + + data->wdog_config.workMode.enableDebug = + (options & WDT_OPT_PAUSE_HALTED_BY_DBG) == 0U; + + WDOG_Init(base, &data->wdog_config); + LOG_DBG("Setup the watchdog"); + + return 0; +} + +static int mcux_wdog_disable(const struct device *dev) +{ + const struct mcux_wdog_config *config = dev->config; + struct mcux_wdog_data *data = dev->data; + WDOG_Type *base = config->base; + + WDOG_Deinit(base); + data->timeout_valid = false; + LOG_DBG("Disabled the watchdog"); + + return 0; +} + +static int mcux_wdog_install_timeout(const struct device *dev, + const struct wdt_timeout_cfg *cfg) +{ + struct mcux_wdog_data *data = dev->data; + + if (data->timeout_valid) { + LOG_ERR("No more timeouts can be installed"); + return -ENOMEM; + } + + WDOG_GetDefaultConfig(&data->wdog_config); + data->wdog_config.interruptTimeValue = 0U; + + data->wdog_config.timeoutValue = + WDOG_TMOUT_SEC(cfg->window.max); + + if (cfg->window.min) { + LOG_ERR("Invalid window.min, Do not support window model"); + return -EINVAL; + } + if (data->wdog_config.timeoutValue > 128) { + LOG_ERR("Invalid timeoutValue, valid (0.5s - 128.0s)"); + return -EINVAL; + } + + data->wdog_config.enableInterrupt = cfg->callback != NULL; + data->callback = cfg->callback; + data->timeout_valid = true; + + return 0; +} + +static int mcux_wdog_feed(const struct device *dev, int channel_id) +{ + const struct mcux_wdog_config *config = dev->config; + WDOG_Type *base = config->base; + + if (channel_id != 0) { + LOG_ERR("Invalid channel id"); + return -EINVAL; + } + + WDOG_Refresh(base); + LOG_DBG("Fed the watchdog"); + + return 0; +} + +static void mcux_wdog_isr(void *arg) +{ + const struct device *dev = (const struct device *)arg; + const struct mcux_wdog_config *config = dev->config; + struct mcux_wdog_data *data = dev->data; + WDOG_Type *base = config->base; + uint32_t flags; + + flags = WDOG_GetStatusFlags(base); + WDOG_ClearInterruptStatus(base, flags); + + if (data->callback) { + data->callback(dev, 0); + } +} + +static int mcux_wdog_init(const struct device *dev) +{ + const struct mcux_wdog_config *config = dev->config; + + config->irq_config_func(dev); + + return 0; +} + +static const struct wdt_driver_api mcux_wdog_api = { + .setup = mcux_wdog_setup, + .disable = mcux_wdog_disable, + .install_timeout = mcux_wdog_install_timeout, + .feed = mcux_wdog_feed, +}; + +static void mcux_wdog_config_func(const struct device *dev); + +static const struct mcux_wdog_config mcux_wdog_config = { + .base = (WDOG_Type *) DT_INST_REG_ADDR(0), + .irq_config_func = mcux_wdog_config_func, +}; + +static struct mcux_wdog_data mcux_wdog_data; + +DEVICE_AND_API_INIT(mcux_wdog, DT_INST_LABEL(0), + &mcux_wdog_init, + &mcux_wdog_data, &mcux_wdog_config, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &mcux_wdog_api); + +static void mcux_wdog_config_func(const struct device *dev) +{ + IRQ_CONNECT(DT_INST_IRQN(0), + DT_INST_IRQ(0, priority), + mcux_wdog_isr, DEVICE_GET(mcux_wdog), 0); + + irq_enable(DT_INST_IRQN(0)); +} diff --git a/dts/arm/nxp/nxp_rt.dtsi b/dts/arm/nxp/nxp_rt.dtsi index a39398f3807..57a59f3b361 100644 --- a/dts/arm/nxp/nxp_rt.dtsi +++ b/dts/arm/nxp/nxp_rt.dtsi @@ -671,6 +671,22 @@ #address-cells = <1>; #size-cells = <0>; }; + + wdog0: wdog@400b8000 { + compatible = "nxp,imx-wdog"; + reg = <0x400b8000 0xA>; + status = "disabled"; + interrupts = <92 0>; + label = "WDOG0"; + }; + + wdog1: wdog@400d0000 { + compatible = "nxp,imx-wdog"; + reg = <0x400d0000 0xA>; + status = "disabled"; + interrupts = <45 0>; + label = "WDOG1"; + }; }; }; diff --git a/dts/bindings/watchdog/nxp,imx-wdog.yaml b/dts/bindings/watchdog/nxp,imx-wdog.yaml new file mode 100644 index 00000000000..c8616ab916c --- /dev/null +++ b/dts/bindings/watchdog/nxp,imx-wdog.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2018, NXP +# SPDX-License-Identifier: Apache-2.0 + +description: imxRT watchdog + +compatible: "nxp,imx-wdog" + +include: base.yaml + +properties: + reg: + required: true + + label: + required: true + + interrupts: + required: true diff --git a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series index 2c6d9c093e5..e36de119bc7 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series +++ b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series @@ -58,6 +58,10 @@ config SPI_MCUX_LPSPI default y if HAS_MCUX_LPSPI depends on SPI +config WDT_MCUX_IMX_WDOG + default y + depends on WATCHDOG + if CODE_SEMC config FLASH_SIZE diff --git a/tests/drivers/watchdog/wdt_basic_api/src/test_wdt.c b/tests/drivers/watchdog/wdt_basic_api/src/test_wdt.c index c2fc44e4dbf..60e616331aa 100644 --- a/tests/drivers/watchdog/wdt_basic_api/src/test_wdt.c +++ b/tests/drivers/watchdog/wdt_basic_api/src/test_wdt.c @@ -125,20 +125,26 @@ static struct wdt_timeout_cfg m_cfg_wdt1; #define DATATYPE uint32_t #endif +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) +#define NOINIT_SECTION ".dtcm_noinit.test_wdt" +#else +#define NOINIT_SECTION ".noinit.test_wdt" +#endif + /* m_state indicates state of particular test. Used to check whether testcase * should go to reset state or check other values after reset. */ -volatile DATATYPE m_state __attribute__((section(".noinit.test_wdt"))); +volatile DATATYPE m_state __attribute__((section(NOINIT_SECTION))); /* m_testcase_index is incremented after each test to make test possible * switch to next testcase. */ -volatile DATATYPE m_testcase_index __attribute__((section(".noinit.test_wdt"))); +volatile DATATYPE m_testcase_index __attribute__((section(NOINIT_SECTION))); /* m_testvalue contains value set in interrupt callback to point whether * first or second interrupt was fired. */ -volatile DATATYPE m_testvalue __attribute__((section(".noinit.test_wdt"))); +volatile DATATYPE m_testvalue __attribute__((section(NOINIT_SECTION))); #if TEST_WDT_CALLBACK_1 static void wdt_int_cb0(const struct device *wdt_dev, int channel_id)