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