2 * QTests for Nuvoton NPCM7xx Timer Watchdog Modules.
4 * Copyright 2020 Google LLC
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #include "qemu/osdep.h"
18 #include "qemu/timer.h"
21 #include "qapi/qmp/qdict.h"
23 #define WTCR_OFFSET 0x1c
24 #define REF_HZ (25000000)
27 #define WTCLK(rv) ((rv) << 10)
30 #define WTIS(rv) ((rv) << 4)
36 typedef struct Watchdog
{
41 static const Watchdog watchdog_list
[] = {
44 .base_addr
= 0xf0008000
48 .base_addr
= 0xf0009000
52 .base_addr
= 0xf000a000
56 static int watchdog_index(const Watchdog
*wd
)
58 ptrdiff_t diff
= wd
- watchdog_list
;
60 g_assert(diff
>= 0 && diff
< ARRAY_SIZE(watchdog_list
));
65 static uint32_t watchdog_read_wtcr(QTestState
*qts
, const Watchdog
*wd
)
67 return qtest_readl(qts
, wd
->base_addr
+ WTCR_OFFSET
);
70 static void watchdog_write_wtcr(QTestState
*qts
, const Watchdog
*wd
,
73 qtest_writel(qts
, wd
->base_addr
+ WTCR_OFFSET
, value
);
76 static uint32_t watchdog_prescaler(QTestState
*qts
, const Watchdog
*wd
)
78 switch (extract32(watchdog_read_wtcr(qts
, wd
), 10, 2)) {
88 g_assert_not_reached();
92 static QDict
*get_watchdog_action(QTestState
*qts
)
94 QDict
*ev
= qtest_qmp_eventwait_ref(qts
, "WATCHDOG");
97 data
= qdict_get_qdict(ev
, "data");
103 #define RESET_CYCLES 1024
104 static uint32_t watchdog_interrupt_cycles(QTestState
*qts
, const Watchdog
*wd
)
106 uint32_t wtis
= extract32(watchdog_read_wtcr(qts
, wd
), 4, 2);
107 return 1 << (14 + 2 * wtis
);
110 static int64_t watchdog_calculate_steps(uint32_t count
, uint32_t prescale
)
112 return (NANOSECONDS_PER_SECOND
/ REF_HZ
) * count
* prescale
;
115 static int64_t watchdog_interrupt_steps(QTestState
*qts
, const Watchdog
*wd
)
117 return watchdog_calculate_steps(watchdog_interrupt_cycles(qts
, wd
),
118 watchdog_prescaler(qts
, wd
));
121 /* Check wtcr can be reset to default value */
122 static void test_init(gconstpointer watchdog
)
124 const Watchdog
*wd
= watchdog
;
125 QTestState
*qts
= qtest_init("-machine quanta-gsj");
127 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
129 watchdog_write_wtcr(qts
, wd
, WTCLK(1) | WTRF
| WTIF
| WTR
);
130 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==, WTCLK(1));
135 /* Check a watchdog can generate interrupt and reset actions */
136 static void test_reset_action(gconstpointer watchdog
)
138 const Watchdog
*wd
= watchdog
;
139 QTestState
*qts
= qtest_init("-machine quanta-gsj");
142 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
144 watchdog_write_wtcr(qts
, wd
,
145 WTCLK(0) | WTE
| WTRF
| WTRE
| WTIF
| WTIE
| WTR
);
146 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==,
147 WTCLK(0) | WTE
| WTRE
| WTIE
);
149 /* Check a watchdog can generate an interrupt */
150 qtest_clock_step(qts
, watchdog_interrupt_steps(qts
, wd
));
151 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==,
152 WTCLK(0) | WTE
| WTIF
| WTIE
| WTRE
);
153 g_assert_true(qtest_get_irq(qts
, wd
->irq
));
155 /* Check a watchdog can generate a reset signal */
156 qtest_clock_step(qts
, watchdog_calculate_steps(RESET_CYCLES
,
157 watchdog_prescaler(qts
, wd
)));
158 ad
= get_watchdog_action(qts
);
159 /* The signal is a reset signal */
160 g_assert_false(strcmp(qdict_get_str(ad
, "action"), "reset"));
162 qtest_qmp_eventwait(qts
, "RESET");
164 * Make sure WTCR is reset to default except for WTRF bit which shouldn't
167 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==, WTCLK(1) | WTRF
);
171 /* Check a watchdog works with all possible WTCLK prescalers and WTIS cycles */
172 static void test_prescaler(gconstpointer watchdog
)
174 const Watchdog
*wd
= watchdog
;
175 int inc
= g_test_quick() ? 3 : 1;
177 for (int wtclk
= 0; wtclk
< 4; wtclk
+= inc
) {
178 for (int wtis
= 0; wtis
< 4; wtis
+= inc
) {
179 QTestState
*qts
= qtest_init("-machine quanta-gsj");
181 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
182 watchdog_write_wtcr(qts
, wd
,
183 WTCLK(wtclk
) | WTE
| WTIF
| WTIS(wtis
) | WTIE
| WTR
);
185 * The interrupt doesn't fire until watchdog_interrupt_steps()
188 qtest_clock_step(qts
, watchdog_interrupt_steps(qts
, wd
) - 1);
189 g_assert_false(watchdog_read_wtcr(qts
, wd
) & WTIF
);
190 g_assert_false(qtest_get_irq(qts
, wd
->irq
));
191 qtest_clock_step(qts
, 1);
192 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
193 g_assert_true(qtest_get_irq(qts
, wd
->irq
));
201 * Check a watchdog doesn't fire if corresponding flags (WTIE and WTRE) are not
204 static void test_enabling_flags(gconstpointer watchdog
)
206 const Watchdog
*wd
= watchdog
;
210 /* Neither WTIE or WTRE is set, no interrupt or reset should happen */
211 qts
= qtest_init("-machine quanta-gsj");
212 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
213 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTE
| WTIF
| WTRF
| WTR
);
214 qtest_clock_step(qts
, watchdog_interrupt_steps(qts
, wd
));
215 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
216 g_assert_false(qtest_get_irq(qts
, wd
->irq
));
217 qtest_clock_step(qts
, watchdog_calculate_steps(RESET_CYCLES
,
218 watchdog_prescaler(qts
, wd
)));
219 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
220 g_assert_false(watchdog_read_wtcr(qts
, wd
) & WTRF
);
223 /* Only WTIE is set, interrupt is triggered but reset should not happen */
224 qts
= qtest_init("-machine quanta-gsj");
225 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
226 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTE
| WTIF
| WTIE
| WTRF
| WTR
);
227 qtest_clock_step(qts
, watchdog_interrupt_steps(qts
, wd
));
228 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
229 g_assert_true(qtest_get_irq(qts
, wd
->irq
));
230 qtest_clock_step(qts
, watchdog_calculate_steps(RESET_CYCLES
,
231 watchdog_prescaler(qts
, wd
)));
232 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
233 g_assert_false(watchdog_read_wtcr(qts
, wd
) & WTRF
);
236 /* Only WTRE is set, interrupt is triggered but reset should not happen */
237 qts
= qtest_init("-machine quanta-gsj");
238 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
239 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTE
| WTIF
| WTRE
| WTRF
| WTR
);
240 qtest_clock_step(qts
, watchdog_interrupt_steps(qts
, wd
));
241 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
242 g_assert_false(qtest_get_irq(qts
, wd
->irq
));
243 qtest_clock_step(qts
, watchdog_calculate_steps(RESET_CYCLES
,
244 watchdog_prescaler(qts
, wd
)));
245 rsp
= get_watchdog_action(qts
);
246 g_assert_false(strcmp(qdict_get_str(rsp
, "action"), "reset"));
248 qtest_qmp_eventwait(qts
, "RESET");
252 * The case when both flags are set is already tested in
253 * test_reset_action().
257 /* Check a watchdog can pause and resume by setting WTE bits */
258 static void test_pause(gconstpointer watchdog
)
260 const Watchdog
*wd
= watchdog
;
262 int64_t remaining_steps
, steps
;
264 qts
= qtest_init("-machine quanta-gsj");
265 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
266 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTE
| WTIF
| WTIE
| WTRF
| WTR
);
267 remaining_steps
= watchdog_interrupt_steps(qts
, wd
);
268 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==, WTCLK(0) | WTE
| WTIE
);
270 /* Run for half of the execution period. */
271 steps
= remaining_steps
/ 2;
272 remaining_steps
-= steps
;
273 qtest_clock_step(qts
, steps
);
275 /* Pause the watchdog */
276 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTIE
);
277 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==, WTCLK(0) | WTIE
);
279 /* Run for a long period of time, the watchdog shouldn't fire */
280 qtest_clock_step(qts
, steps
<< 4);
281 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==, WTCLK(0) | WTIE
);
282 g_assert_false(qtest_get_irq(qts
, wd
->irq
));
284 /* Resume the watchdog */
285 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTE
| WTIE
);
286 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==, WTCLK(0) | WTE
| WTIE
);
288 /* Run for the reset of the execution period, the watchdog should fire */
289 qtest_clock_step(qts
, remaining_steps
);
290 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==,
291 WTCLK(0) | WTE
| WTIF
| WTIE
);
292 g_assert_true(qtest_get_irq(qts
, wd
->irq
));
297 static void watchdog_add_test(const char *name
, const Watchdog
* wd
,
300 g_autofree
char *full_name
= g_strdup_printf(
301 "npcm7xx_watchdog_timer[%d]/%s", watchdog_index(wd
), name
);
302 qtest_add_data_func(full_name
, wd
, fn
);
304 #define add_test(name, td) watchdog_add_test(#name, td, test_##name)
306 int main(int argc
, char **argv
)
308 g_test_init(&argc
, &argv
, NULL
);
309 g_test_set_nonfatal_assertions();
311 for (int i
= 0; i
< ARRAY_SIZE(watchdog_list
); ++i
) {
312 const Watchdog
*wd
= &watchdog_list
[i
];
315 add_test(reset_action
, wd
);
316 add_test(prescaler
, wd
);
317 add_test(enabling_flags
, wd
);