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(nuvoton_numaker_wwdt)
102 #define WDT_NODE DT_INST(0, nuvoton_numaker_wwdt)
103 #define TIMEOUTS 1
104 #elif DT_HAS_COMPAT_STATUS_OKAY(andestech_atcwdt200)
105 #define WDT_NODE DT_INST(0, andestech_atcwdt200)
106 #define TIMEOUTS 0
107 #define WDT_TEST_MAX_WINDOW 200U
108 #endif
109 #if DT_HAS_COMPAT_STATUS_OKAY(raspberrypi_pico_watchdog)
110 #define WDT_TEST_MAX_WINDOW 8000U
111 #define TIMEOUTS 0
112 #endif
113 #if DT_HAS_COMPAT_STATUS_OKAY(intel_tco_wdt)
114 #define TIMEOUTS 0
115 #define WDT_TEST_MAX_WINDOW 3000U
116 #endif
117 
118 #define WDT_TEST_STATE_IDLE        0
119 #define WDT_TEST_STATE_CHECK_RESET 1
120 
121 #define WDT_TEST_CB0_TEST_VALUE    0x0CB0
122 #define WDT_TEST_CB1_TEST_VALUE    0x0CB1
123 
124 #ifndef WDT_TEST_MAX_WINDOW
125 #define WDT_TEST_MAX_WINDOW                2000U
126 #endif
127 
128 #ifndef TIMEOUTS
129 #define TIMEOUTS                   1
130 #endif
131 
132 #define TEST_WDT_CALLBACK_1        (TIMEOUTS > 0)
133 #define TEST_WDT_CALLBACK_2        (TIMEOUTS > 1)
134 
135 
136 static struct wdt_timeout_cfg m_cfg_wdt0;
137 #if TEST_WDT_CALLBACK_2
138 static struct wdt_timeout_cfg m_cfg_wdt1;
139 #endif
140 
141 #if defined(CONFIG_SOC_SERIES_STM32F7X) || defined(CONFIG_SOC_SERIES_STM32H7X)
142 /* STM32H7 and STM32F7 guarantee last write RAM retention over reset,
143  * only for 64bits
144  * See details in Application Note AN5342
145  */
146 #define DATATYPE uint64_t
147 #else
148 #define DATATYPE uint32_t
149 #endif
150 
151 #if DT_NODE_HAS_STATUS_OKAY(DT_CHOSEN(zephyr_dtcm))
152 #define NOINIT_SECTION ".dtcm_noinit.test_wdt"
153 #else
154 #define NOINIT_SECTION ".noinit.test_wdt"
155 #endif
156 
157 /* m_state indicates state of particular test. Used to check whether testcase
158  * should go to reset state or check other values after reset.
159  */
160 volatile DATATYPE m_state __attribute__((section(NOINIT_SECTION)));
161 
162 /* m_testcase_index is incremented after each test to make test possible
163  * switch to next testcase.
164  */
165 volatile DATATYPE m_testcase_index __attribute__((section(NOINIT_SECTION)));
166 
167 /* m_testvalue contains value set in interrupt callback to point whether
168  * first or second interrupt was fired.
169  */
170 volatile DATATYPE m_testvalue __attribute__((section(NOINIT_SECTION)));
171 
172 #if TEST_WDT_CALLBACK_1
wdt_int_cb0(const struct device * wdt_dev,int channel_id)173 static void wdt_int_cb0(const struct device *wdt_dev, int channel_id)
174 {
175 	ARG_UNUSED(wdt_dev);
176 	ARG_UNUSED(channel_id);
177 	m_testvalue += WDT_TEST_CB0_TEST_VALUE;
178 }
179 #endif
180 
181 #if TEST_WDT_CALLBACK_2
wdt_int_cb1(const struct device * wdt_dev,int channel_id)182 static void wdt_int_cb1(const struct device *wdt_dev, int channel_id)
183 {
184 	ARG_UNUSED(wdt_dev);
185 	ARG_UNUSED(channel_id);
186 	m_testvalue += WDT_TEST_CB1_TEST_VALUE;
187 }
188 #endif
189 
test_wdt_no_callback(void)190 static int test_wdt_no_callback(void)
191 {
192 	int err;
193 	const struct device *const wdt = DEVICE_DT_GET(WDT_NODE);
194 
195 	if (!device_is_ready(wdt)) {
196 		TC_PRINT("WDT device is not ready\n");
197 		return TC_FAIL;
198 	}
199 
200 	TC_PRINT("Testcase: %s\n", __func__);
201 
202 	if (m_state == WDT_TEST_STATE_CHECK_RESET) {
203 		m_state = WDT_TEST_STATE_IDLE;
204 		m_testcase_index = 1U;
205 		TC_PRINT("Testcase passed\n");
206 		return TC_PASS;
207 	}
208 
209 	m_cfg_wdt0.callback = NULL;
210 	m_cfg_wdt0.flags = WDT_FLAG_RESET_SOC;
211 	m_cfg_wdt0.window.max = WDT_TEST_MAX_WINDOW;
212 	err = wdt_install_timeout(wdt, &m_cfg_wdt0);
213 	if (err < 0) {
214 		TC_PRINT("Watchdog install error\n");
215 		return TC_FAIL;
216 	}
217 
218 	err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG);
219 	if (err == -ENOTSUP) {
220 		TC_PRINT("- pausing watchdog by debugger is not supported\n");
221 		err = wdt_setup(wdt, 0);
222 	}
223 	if (err < 0) {
224 		TC_PRINT("Watchdog setup error\n");
225 		return TC_FAIL;
226 	}
227 
228 	TC_PRINT("Waiting to restart MCU\n");
229 	m_testvalue = 0U;
230 	m_state = WDT_TEST_STATE_CHECK_RESET;
231 	while (1) {
232 		k_yield();
233 	}
234 }
235 
236 #if TEST_WDT_CALLBACK_1
test_wdt_callback_1(void)237 static int test_wdt_callback_1(void)
238 {
239 	int err;
240 	const struct device *const wdt = DEVICE_DT_GET(WDT_NODE);
241 
242 	if (!device_is_ready(wdt)) {
243 		TC_PRINT("WDT device is not ready\n");
244 		return TC_FAIL;
245 	}
246 
247 	TC_PRINT("Testcase: %s\n", __func__);
248 
249 	if (m_state == WDT_TEST_STATE_CHECK_RESET) {
250 		m_state = WDT_TEST_STATE_IDLE;
251 		m_testcase_index++;
252 		if (m_testvalue == WDT_TEST_CB0_TEST_VALUE) {
253 			TC_PRINT("Testcase passed\n");
254 			return TC_PASS;
255 		} else {
256 			return TC_FAIL;
257 		}
258 	}
259 
260 	m_testvalue = 0U;
261 	m_cfg_wdt0.flags = WDT_FLAG_RESET_SOC;
262 	m_cfg_wdt0.callback = wdt_int_cb0;
263 	m_cfg_wdt0.window.max = WDT_TEST_MAX_WINDOW;
264 	err = wdt_install_timeout(wdt, &m_cfg_wdt0);
265 	if (err < 0) {
266 		if (err == -ENOTSUP) {
267 			TC_PRINT("CB1 not supported on platform\n");
268 			m_testcase_index++;
269 			return TC_PASS;
270 
271 		}
272 		TC_PRINT("Watchdog install error\n");
273 		return TC_FAIL;
274 	}
275 
276 	err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG);
277 	if (err == -ENOTSUP) {
278 		TC_PRINT("- pausing watchdog by debugger is not supported\n");
279 		err = wdt_setup(wdt, 0);
280 	}
281 	if (err < 0) {
282 		TC_PRINT("Watchdog setup error\n");
283 		return TC_FAIL;
284 	}
285 
286 	TC_PRINT("Waiting to restart MCU\n");
287 	m_testvalue = 0U;
288 	m_state = WDT_TEST_STATE_CHECK_RESET;
289 	while (1) {
290 		k_yield();
291 	}
292 }
293 #endif
294 
295 #if TEST_WDT_CALLBACK_2
test_wdt_callback_2(void)296 static int test_wdt_callback_2(void)
297 {
298 	int err;
299 	const struct device *const wdt = DEVICE_DT_GET(WDT_NODE);
300 
301 	if (!device_is_ready(wdt)) {
302 		TC_PRINT("WDT device is not ready\n");
303 		return TC_FAIL;
304 	}
305 
306 	TC_PRINT("Testcase: %s\n", __func__);
307 
308 	if (m_state == WDT_TEST_STATE_CHECK_RESET) {
309 		m_state = WDT_TEST_STATE_IDLE;
310 		m_testcase_index++;
311 		if (m_testvalue == WDT_TEST_CB1_TEST_VALUE) {
312 			TC_PRINT("Testcase passed\n");
313 			return TC_PASS;
314 		} else {
315 			return TC_FAIL;
316 		}
317 	}
318 
319 
320 	m_testvalue = 0U;
321 	m_cfg_wdt0.callback = wdt_int_cb0;
322 	m_cfg_wdt0.flags = WDT_FLAG_RESET_SOC;
323 	m_cfg_wdt0.window.max = WDT_TEST_MAX_WINDOW;
324 	err = wdt_install_timeout(wdt, &m_cfg_wdt0);
325 
326 	if (err < 0) {
327 		TC_PRINT("Watchdog install error\n");
328 		return TC_FAIL;
329 	}
330 
331 	m_cfg_wdt1.callback = wdt_int_cb1;
332 	m_cfg_wdt1.flags = WDT_FLAG_RESET_SOC;
333 	m_cfg_wdt1.window.max = WDT_TEST_MAX_WINDOW;
334 	err = wdt_install_timeout(wdt, &m_cfg_wdt1);
335 	if (err < 0) {
336 		TC_PRINT("Watchdog install error\n");
337 		return TC_FAIL;
338 	}
339 
340 	err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG);
341 	if (err == -ENOTSUP) {
342 		TC_PRINT("- pausing watchdog by debugger is not supported\n");
343 		err = wdt_setup(wdt, 0);
344 	}
345 	if (err < 0) {
346 		TC_PRINT("Watchdog setup error\n");
347 		return TC_FAIL;
348 	}
349 
350 	TC_PRINT("Waiting to restart MCU\n");
351 	m_testvalue = 0U;
352 	m_state = WDT_TEST_STATE_CHECK_RESET;
353 
354 	while (1) {
355 		wdt_feed(wdt, 0);
356 		k_sleep(K_MSEC(100));
357 	}
358 }
359 #endif
360 
test_wdt_bad_window_max(void)361 static int test_wdt_bad_window_max(void)
362 {
363 	int err;
364 	const struct device *const wdt = DEVICE_DT_GET(WDT_NODE);
365 
366 	if (!device_is_ready(wdt)) {
367 		TC_PRINT("WDT device is not ready\n");
368 		return TC_FAIL;
369 	}
370 
371 	TC_PRINT("Testcase: %s\n", __func__);
372 
373 	m_cfg_wdt0.callback = NULL;
374 	m_cfg_wdt0.flags = WDT_FLAG_RESET_SOC;
375 	m_cfg_wdt0.window.max = 0U;
376 	err = wdt_install_timeout(wdt, &m_cfg_wdt0);
377 	if (err == -EINVAL) {
378 		return TC_PASS;
379 	}
380 
381 	return TC_FAIL;
382 }
383 
ZTEST(wdt_basic_test_suite,test_wdt)384 ZTEST(wdt_basic_test_suite, test_wdt)
385 {
386 	if ((m_testcase_index != 1U) && (m_testcase_index != 2U)) {
387 		zassert_true(test_wdt_no_callback() == TC_PASS);
388 	}
389 	if (m_testcase_index == 1U) {
390 #if TEST_WDT_CALLBACK_1
391 		zassert_true(test_wdt_callback_1() == TC_PASS);
392 #else
393 		m_testcase_index++;
394 #endif
395 	}
396 	if (m_testcase_index == 2U) {
397 #if TEST_WDT_CALLBACK_2
398 		zassert_true(test_wdt_callback_2() == TC_PASS);
399 #else
400 		m_testcase_index++;
401 #endif
402 	}
403 	if (m_testcase_index == 3U) {
404 		zassert_true(test_wdt_bad_window_max() == TC_PASS);
405 		m_testcase_index++;
406 	}
407 	if (m_testcase_index > 3) {
408 		m_state = WDT_TEST_STATE_IDLE;
409 	}
410 }
411