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