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