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