From a2b5af074424db50428aac0fb99d3d3cf290e647 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Wed, 9 Apr 2025 11:27:38 -0500 Subject: [PATCH 1/3] drivers: watchdog: Added Driver for the EWM Added a driver for the External Watchdog Driver Signed-off-by: Emilio Benavente --- drivers/watchdog/CMakeLists.txt | 1 + drivers/watchdog/Kconfig | 2 + drivers/watchdog/Kconfig.nxp_ewm | 9 ++ drivers/watchdog/wdt_nxp_ewm.c | 192 +++++++++++++++++++++++++++++ dts/bindings/watchdog/nxp,ewm.yaml | 32 +++++ soc/nxp/mcx/mcxw/soc.c | 4 + 6 files changed, 240 insertions(+) create mode 100644 drivers/watchdog/Kconfig.nxp_ewm create mode 100644 drivers/watchdog/wdt_nxp_ewm.c create mode 100644 dts/bindings/watchdog/nxp,ewm.yaml diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index 050cd1e72fa3..e690ef5d46cb 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -59,5 +59,6 @@ zephyr_library_sources_ifdef(CONFIG_WDT_ANDES_ATCWDT200 wdt_andes_atcwdt200.c) zephyr_library_sources_ifdef(CONFIG_WDT_NXP_FS26 wdt_nxp_fs26.c) zephyr_library_sources_ifdef(CONFIG_WDT_SHELL wdt_shell.c) zephyr_library_sources_ifdef(CONFIG_WDT_RENESAS_RA wdt_renesas_ra.c) +zephyr_library_sources_ifdef(CONFIG_WDT_NXP_EWM wdt_nxp_ewm.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE wdt_handlers.c) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 722931b60bc5..21cedff971f4 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -153,4 +153,6 @@ source "drivers/watchdog/Kconfig.renesas_ra" source "drivers/watchdog/Kconfig.wch" +source "drivers/watchdog/Kconfig.nxp_ewm" + endif # WATCHDOG diff --git a/drivers/watchdog/Kconfig.nxp_ewm b/drivers/watchdog/Kconfig.nxp_ewm new file mode 100644 index 000000000000..7b26336351d0 --- /dev/null +++ b/drivers/watchdog/Kconfig.nxp_ewm @@ -0,0 +1,9 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config WDT_NXP_EWM + bool "NXP EWM driver" + default y + depends on DT_HAS_NXP_EWM_ENABLED + help + Enable the nxp ewm driver. diff --git a/drivers/watchdog/wdt_nxp_ewm.c b/drivers/watchdog/wdt_nxp_ewm.c new file mode 100644 index 000000000000..32c697e3e223 --- /dev/null +++ b/drivers/watchdog/wdt_nxp_ewm.c @@ -0,0 +1,192 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_ewm + +#include +#include + +#include +LOG_MODULE_REGISTER(wdt_nxp_ewm); + +#define NXP_EWM_FEED_MAGIC_NUMBER 0x2CB4 +#define NXP_EWM_MAX_TIMEOUT_WINDOW 0xFE + +struct nxp_ewm_config { + EWM_Type *base; + void (*irq_config_func)(const struct device *dev); + bool is_input_enabled; + bool is_input_active_high; + uint8_t clk_divider; +}; + +struct nxp_ewm_data { + struct wdt_timeout_cfg timeout_cfg; + bool is_watchdog_setup; +}; + +static int nxp_ewm_setup(const struct device *dev, uint8_t options) +{ + const struct nxp_ewm_config *config = dev->config; + struct nxp_ewm_data *data = dev->data; + EWM_Type *base = config->base; + + if (data->is_watchdog_setup) { + /* Watchdog cannot be re-configured after enabled. */ + return -EBUSY; + } + + if (options) { + /* Unable to halt counter during debugging */ + return -ENOTSUP; + } + + data->is_watchdog_setup = true; + base->CMPL = EWM_CMPL_COMPAREL(data->timeout_cfg.window.min); + base->CMPH = EWM_CMPH_COMPAREH(data->timeout_cfg.window.max); + + /* + * base->CTRL should be the last thing touched due to + * the small watchdog window time. + * After this write, only the INTEN bit is writable until reset. + * + * EWM_CTRL_INTEN enables the interrupt signal + * EWM_CTRL_EWMEN enables the watchdog. + */ + base->CTRL |= EWM_CTRL_INEN(config->is_input_enabled) | + EWM_CTRL_ASSIN(config->is_input_active_high) | + EWM_CTRL_INTEN(1) | EWM_CTRL_EWMEN(1); + + return 0; +} + +static int nxp_ewm_disable(const struct device *dev) +{ + struct nxp_ewm_data *data = dev->data; + + if (!data->is_watchdog_setup) { + return -EFAULT; + } + + return -EPERM; +} + +static int nxp_ewm_install_timeout(const struct device *dev, + const struct wdt_timeout_cfg *cfg) +{ + struct nxp_ewm_data *data = dev->data; + + if (cfg->flags) { + return -ENOTSUP; + } + + if (data->is_watchdog_setup) { + return -ENOMEM; + } + + if (cfg && cfg->window.max <= NXP_EWM_MAX_TIMEOUT_WINDOW && + cfg->window.min <= cfg->window.max && + cfg->window.max > 0 && + cfg->window.min >= 0) { + data->timeout_cfg.window = cfg->window; + } else { + return -EINVAL; + } + +#if defined(CONFIG_WDT_MULTISTAGE) + if (cfg->next) { + return -EINVAL; + } +#endif + + if (cfg->callback) { + data->timeout_cfg.callback = cfg->callback; + } + + return 0; +} + +static int nxp_ewm_feed(const struct device *dev, int channel_id) +{ + ARG_UNUSED(channel_id); + const struct nxp_ewm_config *config = dev->config; + EWM_Type *base = config->base; + unsigned int key = irq_lock(); + + base->SERV = EWM_SERV_SERVICE(NXP_EWM_FEED_MAGIC_NUMBER); + base->SERV = EWM_SERV_SERVICE((uint8_t)(NXP_EWM_FEED_MAGIC_NUMBER >> 8)); + irq_unlock(key); + + return 0; +} + +static void nxp_ewm_isr(const struct device *dev) +{ + const struct nxp_ewm_config *config = dev->config; + struct nxp_ewm_data *data = dev->data; + EWM_Type *base = config->base; + + base->CTRL &= (~EWM_CTRL_INTEN_MASK); + + if (data->timeout_cfg.callback) { + data->timeout_cfg.callback(dev, 0); + } +} + +static int nxp_ewm_init(const struct device *dev) +{ + const struct nxp_ewm_config *config = dev->config; + EWM_Type *base = config->base; + + if (config->clk_divider >= 0 && config->clk_divider <= 0xFF) { + base->CLKPRESCALER = EWM_CLKPRESCALER_CLK_DIV(config->clk_divider); + } + config->irq_config_func(dev); + + return 0; +} + +static DEVICE_API(wdt, nxp_ewm_api) = { + .setup = nxp_ewm_setup, + .disable = nxp_ewm_disable, + .install_timeout = nxp_ewm_install_timeout, + .feed = nxp_ewm_feed, +}; + +#define WDT_EWM_INIT(n) \ + static void nxp_ewm_config_func_##n(const struct device *dev); \ + \ + static const struct nxp_ewm_config nxp_ewm_config_##n = { \ + .base = (EWM_Type *)DT_INST_REG_ADDR(n), \ + .irq_config_func = nxp_ewm_config_func_##n, \ + .is_input_enabled = DT_INST_PROP(n, input_trigger_en), \ + .is_input_active_high = \ + DT_INST_PROP(n, input_trigger_active_high), \ + .clk_divider = DT_INST_PROP(n, clk_divider), \ + }; \ + \ + static struct nxp_ewm_data nxp_ewm_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + nxp_ewm_init, \ + NULL, \ + &nxp_ewm_data_##n, &nxp_ewm_config_##n, \ + POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &nxp_ewm_api); \ + \ + static void nxp_ewm_config_func_##n(const struct device *dev) \ + { \ + ARG_UNUSED(dev); \ + \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + nxp_ewm_isr, DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + } + +DT_INST_FOREACH_STATUS_OKAY(WDT_EWM_INIT) diff --git a/dts/bindings/watchdog/nxp,ewm.yaml b/dts/bindings/watchdog/nxp,ewm.yaml new file mode 100644 index 000000000000..5bd1e6a36ebf --- /dev/null +++ b/dts/bindings/watchdog/nxp,ewm.yaml @@ -0,0 +1,32 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP External Watchdog Monitor + +compatible: "nxp,ewm" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + clk-divider: + type: int + description: Watchdog clock divider + required: true + + input_trigger_en: + type: boolean + description: | + When enabled the ewm_in signal can be used + to assert the ewm. + + input_trigger_active_high: + type: boolean + description: | + When enabled the ewm_in signal is active high. + The ewm_in signal is active low otherwise. diff --git a/soc/nxp/mcx/mcxw/soc.c b/soc/nxp/mcx/mcxw/soc.c index 94b22710234d..1032a5e3c5c4 100644 --- a/soc/nxp/mcx/mcxw/soc.c +++ b/soc/nxp/mcx/mcxw/soc.c @@ -188,6 +188,10 @@ __weak void clock_init(void) if (DT_NODE_HAS_COMPAT_STATUS(adc0, nxp_lpadc, okay)) { CLOCK_EnableClock(kCLOCK_Lpadc0); } + + if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(ewm0), nxp_ewm, okay)) { + CLOCK_EnableClock(kCLOCK_Ewm0); + } } static void vbat_init(void) From 670e5eaab29a9f9490d15033cc9a0e9b7966a336 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Wed, 9 Apr 2025 11:29:41 -0500 Subject: [PATCH 2/3] dts: arm: nxp: mcxw71_common: Added EWM Support Added EWM Support for MCXW71 and MCXW72 Signed-off-by: Emilio Benavente --- dts/arm/nxp/nxp_mcxw7x_common.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dts/arm/nxp/nxp_mcxw7x_common.dtsi b/dts/arm/nxp/nxp_mcxw7x_common.dtsi index 7e0a42c40572..e7a4b2b30302 100644 --- a/dts/arm/nxp/nxp_mcxw7x_common.dtsi +++ b/dts/arm/nxp/nxp_mcxw7x_common.dtsi @@ -343,6 +343,14 @@ clock-frequency = <32768>; prescaler = <32768>; }; + + ewm0: ewm@13000 { + compatible = "nxp,ewm"; + reg = <0x13000 0x6>; + status = "disabled"; + interrupts = <18 0>; + clk-divider = <0x0>; + }; }; &fast_peripheral0 { From 1a10121a02eec31bb136a6dc08169b3393f5e009 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Wed, 9 Apr 2025 14:49:17 -0500 Subject: [PATCH 3/3] tests: drivers: watchdog: Enable reset none testing for ewm Enabled the wdt_basic_reset_none to test boards using the EWM. Signed-off-by: Emilio Benavente --- .../watchdog/wdt_basic_reset_none/Kconfig | 22 +++++++++++++++++++ .../boards/mcxw7x_ewm.overlay | 14 ++++++++++++ .../watchdog/wdt_basic_reset_none/src/main.c | 20 ++++++++++++----- .../wdt_basic_reset_none/testcase.yaml | 11 ++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 tests/drivers/watchdog/wdt_basic_reset_none/Kconfig create mode 100644 tests/drivers/watchdog/wdt_basic_reset_none/boards/mcxw7x_ewm.overlay diff --git a/tests/drivers/watchdog/wdt_basic_reset_none/Kconfig b/tests/drivers/watchdog/wdt_basic_reset_none/Kconfig new file mode 100644 index 000000000000..8bce14f84e58 --- /dev/null +++ b/tests/drivers/watchdog/wdt_basic_reset_none/Kconfig @@ -0,0 +1,22 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config TEST_WDT_MAX_WINDOW_TIME + int "Watchdog Max Value" + default 1000 + help + Set the watchdog max window time to feed the watchdog. + The units for this value will change based on the watchdog + driver being tested. Most drivers represent this as milliseconds + due to the max window reaching the millisecond feed window. + +config TEST_WDT_SLEEP_TIME + int "Watchdog Sleep Time" + default 500 + help + Set the test sleep time between watchdog feeds. + The units for this value will change based on the watchdog + driver being tested. Most drivers represent this as milliseconds + due to the max window reaching the millisecond feed window. diff --git a/tests/drivers/watchdog/wdt_basic_reset_none/boards/mcxw7x_ewm.overlay b/tests/drivers/watchdog/wdt_basic_reset_none/boards/mcxw7x_ewm.overlay new file mode 100644 index 000000000000..0bab9a648cc0 --- /dev/null +++ b/tests/drivers/watchdog/wdt_basic_reset_none/boards/mcxw7x_ewm.overlay @@ -0,0 +1,14 @@ +/* + * Copyright 2025 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + watchdog0 = &ewm0; + }; +}; + +&ewm0 { + status = "okay"; +}; diff --git a/tests/drivers/watchdog/wdt_basic_reset_none/src/main.c b/tests/drivers/watchdog/wdt_basic_reset_none/src/main.c index 9fa3e0bd7528..9fa744d0bba8 100644 --- a/tests/drivers/watchdog/wdt_basic_reset_none/src/main.c +++ b/tests/drivers/watchdog/wdt_basic_reset_none/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright 2022 NXP + * Copyright 2022, 2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,10 +20,18 @@ #endif #define WDT_FEED_TRIES 2 -#define WDT_MAX_WINDOW 1000 -#define WDT_TIMEOUT K_MSEC(1100) -#define SLEEP_TIME K_MSEC(500) #define WDT_TEST_CB_TEST_VALUE 0xCB +#define WDT_TIMEOUT_VALUE CONFIG_TEST_WDT_MAX_WINDOW_TIME + 10 + +#if defined(CONFIG_WDT_NXP_EWM) +#define WDT_SETUP_FLAGS 0 +#define WDT_TIMEOUT K_TICKS(WDT_TIMEOUT_VALUE) +#define SLEEP_TIME K_TICKS(CONFIG_TEST_WDT_SLEEP_TIME) +#else +#define WDT_SETUP_FLAGS WDT_OPT_PAUSE_HALTED_BY_DBG +#define WDT_TIMEOUT K_MSEC(WDT_TIMEOUT_VALUE) +#define SLEEP_TIME K_MSEC(CONFIG_TEST_WDT_SLEEP_TIME) +#endif static struct wdt_timeout_cfg m_cfg_wdt0; static volatile int wdt_interrupted_flag; @@ -49,7 +57,7 @@ static int test_wdt_callback_reset_none(void) } m_cfg_wdt0.window.min = 0U; - m_cfg_wdt0.window.max = WDT_MAX_WINDOW; + m_cfg_wdt0.window.max = CONFIG_TEST_WDT_MAX_WINDOW_TIME; m_cfg_wdt0.flags = WDT_FLAG_RESET_NONE; m_cfg_wdt0.callback = wdt_callback; @@ -62,7 +70,7 @@ static int test_wdt_callback_reset_none(void) return TC_FAIL; } - err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG); + err = wdt_setup(wdt, WDT_SETUP_FLAGS); if (err != 0) { TC_PRINT("Watchdog setup error\n"); return TC_FAIL; diff --git a/tests/drivers/watchdog/wdt_basic_reset_none/testcase.yaml b/tests/drivers/watchdog/wdt_basic_reset_none/testcase.yaml index 75a140b9685d..3f1220dabbf6 100644 --- a/tests/drivers/watchdog/wdt_basic_reset_none/testcase.yaml +++ b/tests/drivers/watchdog/wdt_basic_reset_none/testcase.yaml @@ -10,3 +10,14 @@ tests: - drivers - watchdog depends_on: watchdog + drivers.watchdog.reset_none_ewm: + filter: dt_compat_enabled("nxp,ewm") + platform_allow: + - frdm_mcxw71 + - frdm_mcxw72/mcxw727c/cpu0 + integration_platforms: + - frdm_mcxw71 + extra_args: DTC_OVERLAY_FILE="boards/mcxw7x_ewm.overlay" + extra_configs: + - CONFIG_TEST_WDT_MAX_WINDOW_TIME=254 + - CONFIG_TEST_WDT_SLEEP_TIME=68