1 /*
2  * Copyright (c) 2018 Nordic Semiconductor.
3  * Copyright 2025 NXP
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /*
9  * @addtogroup t_wdt_basic
10  * @{
11  * @defgroup t_wdt_timeout test_wdt_timeout_capabilities
12  * @brief TestPurpose: verify Watchdog Timer install/setup/feed can work,
13  *        and reset can be triggered when timeout
14  * @details
15  * There are three tests. Each test provide watchdog installation, setup and
16  * wait for reset. Three variables are placed in noinit section to prevent
17  * clearing them during board reset.These variables save number of the current
18  * test case, current test state and value to check if test passed or not.
19  *
20  * - Test Steps - test_wdt_no_callback
21  *   -# Get device.
22  *   -# Check if the state was changed and test should be finished.
23  *   -# Set callback to NULL value.
24  *   -# Install watchdog with current configuration.
25  *   -# Setup watchdog with no additions options.
26  *   -# Wait for reset.
27  * - Expected Results
28  *   -# If reset comes, the same testcase should be executed but state should
29  *      be set to finish value and test should return with success.
30  *
31  * - Test Steps - test_wdt_callback_1
32  *   -# Get device.
33  *   -# Check if the state was changed. If so check testvalue if interrupt
34  *      occurred.
35  *   -# Set callback as pointer to wdt_int_cb0.
36  *   -# Install watchdog with current configuration.
37  *   -# Setup watchdog with no additions options.
38  *   -# Wait for reset.
39  * - Expected Results
40  *   -# If reset comes, the same testcase should be executed but state should be
41  *      set to finish value and test checks if m_testvalue was set in interrupt
42  *      right before reset.
43  *
44  * - Test Steps - test_wdt_callback_2
45  *   -# Get device.
46  *   -# Check if the state was changed. If so check testvalue if interrupt
47  *      occurred.
48  *   -# Install two watchdogs: set pointer to wdt_int_cb0 as callback for first
49  *      watchdog and wdt_int_cb1 for second one.
50  *   -# Install watchdog with current configuration.
51  *   -# Setup watchdog with no additions options.
52  *   -# Wait for reset and feed first watchdog.
53  * - Expected Results
54  *   -# If reset comes, the same testcase should be executed but state should be
55  *      set to finish value and test checks if m_testvalue was set in callback
56  *      of second watchdog right before reset.
57  *
58  * @}
59  */
60 
61 #include <zephyr/drivers/watchdog.h>
62 #include <zephyr/kernel.h>
63 #include <zephyr/ztest.h>
64 
65 /*
66  * To use this test, either the devicetree's /aliases must have a
67  * 'watchdog0' property, or one of the following watchdog compatibles
68  * must have an enabled node.
69  */
70 #if DT_NODE_HAS_STATUS_OKAY(DT_ALIAS(watchdog0))
71 #define WDT_NODE DT_ALIAS(watchdog0)
72 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_window_watchdog)
73 #define WDT_NODE DT_INST(0, st_stm32_window_watchdog)
74 #define TIMEOUTS 0
75 #define WDT_TEST_MAX_WINDOW 200
76 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_watchdog)
77 #define WDT_NODE DT_INST(0, st_stm32_watchdog)
78 #define TIMEOUTS 0
79 #elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_wdt)
80 #define WDT_NODE DT_INST(0, nordic_nrf_wdt)
81 #define TIMEOUTS 2
82 #elif DT_HAS_COMPAT_STATUS_OKAY(espressif_esp32_watchdog)
83 #define WDT_NODE DT_INST(0, espressif_esp32_watchdog)
84 #elif DT_HAS_COMPAT_STATUS_OKAY(silabs_gecko_wdog)
85 #define WDT_NODE DT_INST(0, silabs_gecko_wdog)
86 #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_wdog32)
87 #define WDT_NODE DT_INST(0, nxp_wdog32)
88 #elif DT_HAS_COMPAT_STATUS_OKAY(microchip_xec_watchdog)
89 #define WDT_NODE DT_INST(0, microchip_xec_watchdog)
90 #elif DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_watchdog)
91 #define WDT_NODE DT_INST(0, nuvoton_npcx_watchdog)
92 #elif DT_HAS_COMPAT_STATUS_OKAY(ti_cc32xx_watchdog)
93 #define WDT_NODE DT_INST(0, ti_cc32xx_watchdog)
94 #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_imx_wdog)
95 #define WDT_NODE DT_INST(0, nxp_imx_wdog)
96 #elif DT_HAS_COMPAT_STATUS_OKAY(gd_gd32_wwdgt)
97 #define WDT_NODE DT_INST(0, gd_gd32_wwdgt)
98 #elif DT_HAS_COMPAT_STATUS_OKAY(gd_gd32_fwdgt)
99 #define WDT_NODE DT_INST(0, gd_gd32_fwdgt)
100 #elif DT_HAS_COMPAT_STATUS_OKAY(zephyr_counter_watchdog)
101 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_counter_watchdog)
102 #elif DT_HAS_COMPAT_STATUS_OKAY(silabs_siwx91x_wdt)
103 #define WDT_NODE DT_INST(0, silabs_siwx91x_wdt)
104 #elif DT_HAS_COMPAT_STATUS_OKAY(nuvoton_numaker_wwdt)
105 #define WDT_NODE DT_INST(0, nuvoton_numaker_wwdt)
106 #define TIMEOUTS 1
107 #elif DT_HAS_COMPAT_STATUS_OKAY(andestech_atcwdt200)
108 #define WDT_NODE DT_INST(0, andestech_atcwdt200)
109 #define TIMEOUTS 0
110 #define WDT_TEST_MAX_WINDOW 200U
111 #endif
112 #if DT_HAS_COMPAT_STATUS_OKAY(raspberrypi_pico_watchdog)
113 #define WDT_TEST_MAX_WINDOW 8000U
114 #define TIMEOUTS 0
115 #endif
116 #if DT_HAS_COMPAT_STATUS_OKAY(intel_tco_wdt)
117 #define TIMEOUTS 0
118 #define WDT_TEST_MAX_WINDOW 3000U
119 #endif
120 #if DT_HAS_COMPAT_STATUS_OKAY(nxp_wdog32)
121 #define WDT_TEST_MAX_WINDOW 1000U
122 #endif
123 
124 #define WDT_TEST_STATE_IDLE        0
125 #define WDT_TEST_STATE_CHECK_RESET 1
126 
127 #define WDT_TEST_CB0_TEST_VALUE    0x0CB0
128 #define WDT_TEST_CB1_TEST_VALUE    0x0CB1
129 
130 #ifndef WDT_TEST_MAX_WINDOW
131 #define WDT_TEST_MAX_WINDOW                2000U
132 #endif
133 
134 #ifndef TIMEOUTS
135 #define TIMEOUTS                   1
136 #endif
137 
138 #if !(defined(CONFIG_HAS_WDT_NO_CALLBACKS) && CONFIG_HAS_WDT_NO_CALLBACKS)
139 #define TEST_WDT_CALLBACK_1        (TIMEOUTS > 0)
140 #define TEST_WDT_CALLBACK_2        (TIMEOUTS > 1)
141 #endif
142 
143 
144 static struct wdt_timeout_cfg m_cfg_wdt0;
145 #if TEST_WDT_CALLBACK_2
146 static struct wdt_timeout_cfg m_cfg_wdt1;
147 #endif
148 
149 #if defined(CONFIG_SOC_SERIES_STM32F7X) || defined(CONFIG_SOC_SERIES_STM32H7X)
150 /* STM32H7 and STM32F7 guarantee last write RAM retention over reset,
151  * only for 64bits
152  * See details in Application Note AN5342
153  */
154 #define DATATYPE uint64_t
155 #else
156 #define DATATYPE uint32_t
157 #endif
158 
159 #if DT_NODE_HAS_STATUS_OKAY(DT_CHOSEN(zephyr_dtcm))
160 #define NOINIT_SECTION ".dtcm_noinit.test_wdt"
161 #else
162 #define NOINIT_SECTION ".noinit.test_wdt"
163 #endif
164 
165 /* m_state indicates state of particular test. Used to check whether testcase
166  * should go to reset state or check other values after reset.
167  */
168 volatile DATATYPE m_state __attribute__((section(NOINIT_SECTION)));
169 
170 /* m_testcase_index is incremented after each test to make test possible
171  * switch to next testcase.
172  */
173 volatile DATATYPE m_testcase_index __attribute__((section(NOINIT_SECTION)));
174 
175 /* m_testvalue contains value set in interrupt callback to point whether
176  * first or second interrupt was fired.
177  */
178 volatile DATATYPE m_testvalue __attribute__((section(NOINIT_SECTION)));
179 
180 #if TEST_WDT_CALLBACK_1
wdt_int_cb0(const struct device * wdt_dev,int channel_id)181 static void wdt_int_cb0(const struct device *wdt_dev, int channel_id)
182 {
183 	ARG_UNUSED(wdt_dev);
184 	ARG_UNUSED(channel_id);
185 	m_testvalue += WDT_TEST_CB0_TEST_VALUE;
186 }
187 #endif
188 
189 #if TEST_WDT_CALLBACK_2
wdt_int_cb1(const struct device * wdt_dev,int channel_id)190 static void wdt_int_cb1(const struct device *wdt_dev, int channel_id)
191 {
192 	ARG_UNUSED(wdt_dev);
193 	ARG_UNUSED(channel_id);
194 	m_testvalue += WDT_TEST_CB1_TEST_VALUE;
195 }
196 #endif
197 
test_wdt_no_callback(void)198 static int test_wdt_no_callback(void)
199 {
200 	int err;
201 	const struct device *const wdt = DEVICE_DT_GET(WDT_NODE);
202 
203 	if (!device_is_ready(wdt)) {
204 		TC_PRINT("WDT device is not ready\n");
205 		return TC_FAIL;
206 	}
207 
208 	TC_PRINT("Testcase: %s\n", __func__);
209 
210 	if (m_state == WDT_TEST_STATE_CHECK_RESET) {
211 		m_state = WDT_TEST_STATE_IDLE;
212 		m_testcase_index = 1U;
213 		TC_PRINT("Testcase passed\n");
214 		return TC_PASS;
215 	}
216 
217 	m_cfg_wdt0.callback = NULL;
218 	m_cfg_wdt0.flags = WDT_FLAG_RESET_SOC;
219 	m_cfg_wdt0.window.max = WDT_TEST_MAX_WINDOW;
220 	err = wdt_install_timeout(wdt, &m_cfg_wdt0);
221 	if (err < 0) {
222 		TC_PRINT("Watchdog install error\n");
223 		return TC_FAIL;
224 	}
225 
226 	err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG);
227 	if (err == -ENOTSUP) {
228 		TC_PRINT("- pausing watchdog by debugger is not supported\n");
229 		err = wdt_setup(wdt, 0);
230 	}
231 	if (err < 0) {
232 		TC_PRINT("Watchdog setup error\n");
233 		return TC_FAIL;
234 	}
235 
236 	TC_PRINT("Waiting to restart MCU\n");
237 	m_testvalue = 0U;
238 	m_state = WDT_TEST_STATE_CHECK_RESET;
239 	while (1) {
240 		k_yield();
241 	}
242 }
243 
244 #if TEST_WDT_CALLBACK_1
test_wdt_callback_1(void)245 static int test_wdt_callback_1(void)
246 {
247 	int err;
248 	const struct device *const wdt = DEVICE_DT_GET(WDT_NODE);
249 
250 	if (!device_is_ready(wdt)) {
251 		TC_PRINT("WDT device is not ready\n");
252 		return TC_FAIL;
253 	}
254 
255 	TC_PRINT("Testcase: %s\n", __func__);
256 
257 	if (m_state == WDT_TEST_STATE_CHECK_RESET) {
258 		m_state = WDT_TEST_STATE_IDLE;
259 		m_testcase_index++;
260 		if (m_testvalue == WDT_TEST_CB0_TEST_VALUE) {
261 			TC_PRINT("Testcase passed\n");
262 			return TC_PASS;
263 		} else {
264 			return TC_FAIL;
265 		}
266 	}
267 
268 	err = wdt_disable(wdt);
269 	if (err < 0 && err != -EPERM && err != -EFAULT) {
270 		TC_PRINT("Watchdog disable error\n");
271 		return TC_FAIL;
272 	}
273 
274 	m_testvalue = 0U;
275 	m_cfg_wdt0.flags = WDT_FLAG_RESET_SOC;
276 	m_cfg_wdt0.callback = wdt_int_cb0;
277 	m_cfg_wdt0.window.max = WDT_TEST_MAX_WINDOW;
278 	err = wdt_install_timeout(wdt, &m_cfg_wdt0);
279 	if (err < 0) {
280 		if (err == -ENOTSUP) {
281 			TC_PRINT("CB1 not supported on platform\n");
282 			m_testcase_index++;
283 			return TC_PASS;
284 
285 		}
286 		TC_PRINT("Watchdog install error\n");
287 		return TC_FAIL;
288 	}
289 
290 	err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG);
291 	if (err == -ENOTSUP) {
292 		TC_PRINT("- pausing watchdog by debugger is not supported\n");
293 		err = wdt_setup(wdt, 0);
294 	}
295 	if (err < 0) {
296 		TC_PRINT("Watchdog setup error\n");
297 		return TC_FAIL;
298 	}
299 
300 	TC_PRINT("Waiting to restart MCU\n");
301 	m_testvalue = 0U;
302 	m_state = WDT_TEST_STATE_CHECK_RESET;
303 	while (1) {
304 		k_yield();
305 	}
306 }
307 #endif
308 
309 #if TEST_WDT_CALLBACK_2
test_wdt_callback_2(void)310 static int test_wdt_callback_2(void)
311 {
312 	int err;
313 	const struct device *const wdt = DEVICE_DT_GET(WDT_NODE);
314 
315 	if (!device_is_ready(wdt)) {
316 		TC_PRINT("WDT device is not ready\n");
317 		return TC_FAIL;
318 	}
319 
320 	TC_PRINT("Testcase: %s\n", __func__);
321 
322 	if (m_state == WDT_TEST_STATE_CHECK_RESET) {
323 		m_state = WDT_TEST_STATE_IDLE;
324 		m_testcase_index++;
325 		if (m_testvalue == WDT_TEST_CB1_TEST_VALUE) {
326 			TC_PRINT("Testcase passed\n");
327 			return TC_PASS;
328 		} else {
329 			return TC_FAIL;
330 		}
331 	}
332 
333 	err = wdt_disable(wdt);
334 	if (err < 0 && err != -EPERM && err != -EFAULT) {
335 		TC_PRINT("Watchdog disable error\n");
336 		return TC_FAIL;
337 	}
338 
339 	m_testvalue = 0U;
340 	m_cfg_wdt0.callback = wdt_int_cb0;
341 	m_cfg_wdt0.flags = WDT_FLAG_RESET_SOC;
342 	m_cfg_wdt0.window.max = WDT_TEST_MAX_WINDOW;
343 	err = wdt_install_timeout(wdt, &m_cfg_wdt0);
344 
345 	if (err < 0) {
346 		TC_PRINT("Watchdog install error\n");
347 		return TC_FAIL;
348 	}
349 
350 	m_cfg_wdt1.callback = wdt_int_cb1;
351 	m_cfg_wdt1.flags = WDT_FLAG_RESET_SOC;
352 	m_cfg_wdt1.window.max = WDT_TEST_MAX_WINDOW;
353 	err = wdt_install_timeout(wdt, &m_cfg_wdt1);
354 	if (err < 0) {
355 		TC_PRINT("Watchdog install error\n");
356 		return TC_FAIL;
357 	}
358 
359 	err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG);
360 	if (err == -ENOTSUP) {
361 		TC_PRINT("- pausing watchdog by debugger is not supported\n");
362 		err = wdt_setup(wdt, 0);
363 	}
364 	if (err < 0) {
365 		TC_PRINT("Watchdog setup error\n");
366 		return TC_FAIL;
367 	}
368 
369 	TC_PRINT("Waiting to restart MCU\n");
370 	m_testvalue = 0U;
371 	m_state = WDT_TEST_STATE_CHECK_RESET;
372 
373 	while (1) {
374 		wdt_feed(wdt, 0);
375 		k_sleep(K_MSEC(100));
376 	}
377 }
378 #endif
379 
test_wdt_bad_window_max(void)380 static int test_wdt_bad_window_max(void)
381 {
382 	int err;
383 	const struct device *const wdt = DEVICE_DT_GET(WDT_NODE);
384 
385 	if (!device_is_ready(wdt)) {
386 		TC_PRINT("WDT device is not ready\n");
387 		return TC_FAIL;
388 	}
389 
390 	TC_PRINT("Testcase: %s\n", __func__);
391 
392 	err = wdt_disable(wdt);
393 	if (err < 0 && err != -EPERM && err != -EFAULT) {
394 		TC_PRINT("Watchdog disable error\n");
395 		return TC_FAIL;
396 	}
397 
398 	m_cfg_wdt0.callback = NULL;
399 	m_cfg_wdt0.flags = WDT_FLAG_RESET_SOC;
400 	m_cfg_wdt0.window.max = 0U;
401 	err = wdt_install_timeout(wdt, &m_cfg_wdt0);
402 	if (err == -EINVAL) {
403 		return TC_PASS;
404 	}
405 
406 	return TC_FAIL;
407 }
408 
test_wdt_enable_wait_mode(void)409 static int test_wdt_enable_wait_mode(void)
410 {
411 #ifndef CONFIG_PM
412 	TC_PRINT("Testcase: %s\n", __func__);
413 	ztest_test_skip();
414 	m_state = WDT_TEST_STATE_IDLE;
415 	return TC_SKIP;
416 #else
417 	int err;
418 	int wdt_channel_id;
419 	const struct device *const wdt = DEVICE_DT_GET(WDT_NODE);
420 
421 	if (!device_is_ready(wdt)) {
422 		TC_PRINT("WDT device is not ready\n");
423 		return TC_FAIL;
424 	}
425 
426 	TC_PRINT("Testcase: %s\n", __func__);
427 
428 	if (m_state == WDT_TEST_STATE_CHECK_RESET) {
429 		m_state = WDT_TEST_STATE_IDLE;
430 		TC_PRINT("Testcase passed\n");
431 		return TC_PASS;
432 	}
433 
434 	struct wdt_timeout_cfg wdt_config = {
435 		/* Reset SoC when watchdog timer expires. */
436 		.flags = WDT_FLAG_RESET_SOC,
437 
438 		/* Expire watchdog after max window */
439 		.window.min = 0U,
440 		.window.max = 1000U,
441 	};
442 
443 	wdt_channel_id = wdt_install_timeout(wdt, &wdt_config);
444 	if (wdt_channel_id < 0) {
445 		printk("Watchdog install error\n");
446 		return TC_FAIL;
447 	}
448 
449 	err = wdt_setup(wdt, (WDT_OPT_PAUSE_HALTED_BY_DBG | WDT_OPT_PAUSE_IN_SLEEP));
450 	if (err < 0) {
451 		printk("Watchdog setup error\n");
452 		ztest_test_skip();
453 		return TC_SKIP;
454 	}
455 
456 	for (int i = 0; i < 20; ++i) {
457 		printk("Feeding watchdog... %d\n", i);
458 		wdt_feed(wdt, 0);
459 		k_sleep(K_MSEC(2000));
460 	}
461 
462 	TC_PRINT("Waiting to restart MCU\n");
463 	m_testvalue = 0U;
464 	m_state = WDT_TEST_STATE_CHECK_RESET;
465 	while (1) {
466 		k_yield();
467 	}
468 
469 	return TC_PASS;
470 #endif
471 }
472 
ZTEST(wdt_basic_test_suite,test_wdt)473 ZTEST(wdt_basic_test_suite, test_wdt)
474 {
475 	if ((m_testcase_index != 1U) && (m_testcase_index != 2U)
476 		&& (m_testcase_index != 3U)) {
477 		zassert_true(test_wdt_no_callback() == TC_PASS);
478 	}
479 	if (m_testcase_index == 1U) {
480 #if TEST_WDT_CALLBACK_1
481 		zassert_true(test_wdt_callback_1() == TC_PASS);
482 #else
483 		m_testcase_index++;
484 #endif
485 	}
486 	if (m_testcase_index == 2U) {
487 #if TEST_WDT_CALLBACK_2
488 		zassert_true(test_wdt_callback_2() == TC_PASS);
489 #else
490 		m_testcase_index++;
491 #endif
492 	}
493 	if (m_testcase_index == 3U) {
494 		zassert_true(test_wdt_enable_wait_mode() == TC_PASS);
495 		m_testcase_index++;
496 	}
497 	if (m_testcase_index == 4U) {
498 		zassert_true(test_wdt_bad_window_max() == TC_PASS);
499 		m_testcase_index++;
500 	}
501 	if (m_testcase_index > 4) {
502 		m_state = WDT_TEST_STATE_IDLE;
503 	}
504 }
505