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"
20 #include "libqos/libqtest.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
;
176 for (int wtclk
= 0; wtclk
< 4; ++wtclk
) {
177 for (int wtis
= 0; wtis
< 4; ++wtis
) {
178 QTestState
*qts
= qtest_init("-machine quanta-gsj");
180 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
181 watchdog_write_wtcr(qts
, wd
,
182 WTCLK(wtclk
) | WTE
| WTIF
| WTIS(wtis
) | WTIE
| WTR
);
184 * The interrupt doesn't fire until watchdog_interrupt_steps()
187 qtest_clock_step(qts
, watchdog_interrupt_steps(qts
, wd
) - 1);
188 g_assert_false(watchdog_read_wtcr(qts
, wd
) & WTIF
);
189 g_assert_false(qtest_get_irq(qts
, wd
->irq
));
190 qtest_clock_step(qts
, 1);
191 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
192 g_assert_true(qtest_get_irq(qts
, wd
->irq
));
200 * Check a watchdog doesn't fire if corresponding flags (WTIE and WTRE) are not
203 static void test_enabling_flags(gconstpointer watchdog
)
205 const Watchdog
*wd
= watchdog
;
209 /* Neither WTIE or WTRE is set, no interrupt or reset should happen */
210 qts
= qtest_init("-machine quanta-gsj");
211 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
212 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTE
| WTIF
| WTRF
| WTR
);
213 qtest_clock_step(qts
, watchdog_interrupt_steps(qts
, wd
));
214 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
215 g_assert_false(qtest_get_irq(qts
, wd
->irq
));
216 qtest_clock_step(qts
, watchdog_calculate_steps(RESET_CYCLES
,
217 watchdog_prescaler(qts
, wd
)));
218 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
219 g_assert_false(watchdog_read_wtcr(qts
, wd
) & WTRF
);
222 /* Only WTIE is set, interrupt is triggered but reset should not happen */
223 qts
= qtest_init("-machine quanta-gsj");
224 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
225 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTE
| WTIF
| WTIE
| WTRF
| WTR
);
226 qtest_clock_step(qts
, watchdog_interrupt_steps(qts
, wd
));
227 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
228 g_assert_true(qtest_get_irq(qts
, wd
->irq
));
229 qtest_clock_step(qts
, watchdog_calculate_steps(RESET_CYCLES
,
230 watchdog_prescaler(qts
, wd
)));
231 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
232 g_assert_false(watchdog_read_wtcr(qts
, wd
) & WTRF
);
235 /* Only WTRE is set, interrupt is triggered but reset should not happen */
236 qts
= qtest_init("-machine quanta-gsj");
237 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
238 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTE
| WTIF
| WTRE
| WTRF
| WTR
);
239 qtest_clock_step(qts
, watchdog_interrupt_steps(qts
, wd
));
240 g_assert_true(watchdog_read_wtcr(qts
, wd
) & WTIF
);
241 g_assert_false(qtest_get_irq(qts
, wd
->irq
));
242 qtest_clock_step(qts
, watchdog_calculate_steps(RESET_CYCLES
,
243 watchdog_prescaler(qts
, wd
)));
244 rsp
= get_watchdog_action(qts
);
245 g_assert_false(strcmp(qdict_get_str(rsp
, "action"), "reset"));
247 qtest_qmp_eventwait(qts
, "RESET");
251 * The case when both flags are set is already tested in
252 * test_reset_action().
256 /* Check a watchdog can pause and resume by setting WTE bits */
257 static void test_pause(gconstpointer watchdog
)
259 const Watchdog
*wd
= watchdog
;
261 int64_t remaining_steps
, steps
;
263 qts
= qtest_init("-machine quanta-gsj");
264 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
265 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTE
| WTIF
| WTIE
| WTRF
| WTR
);
266 remaining_steps
= watchdog_interrupt_steps(qts
, wd
);
267 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==, WTCLK(0) | WTE
| WTIE
);
269 /* Run for half of the execution period. */
270 steps
= remaining_steps
/ 2;
271 remaining_steps
-= steps
;
272 qtest_clock_step(qts
, steps
);
274 /* Pause the watchdog */
275 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTIE
);
276 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==, WTCLK(0) | WTIE
);
278 /* Run for a long period of time, the watchdog shouldn't fire */
279 qtest_clock_step(qts
, steps
<< 4);
280 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==, WTCLK(0) | WTIE
);
281 g_assert_false(qtest_get_irq(qts
, wd
->irq
));
283 /* Resume the watchdog */
284 watchdog_write_wtcr(qts
, wd
, WTCLK(0) | WTE
| WTIE
);
285 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==, WTCLK(0) | WTE
| WTIE
);
287 /* Run for the reset of the execution period, the watchdog should fire */
288 qtest_clock_step(qts
, remaining_steps
);
289 g_assert_cmphex(watchdog_read_wtcr(qts
, wd
), ==,
290 WTCLK(0) | WTE
| WTIF
| WTIE
);
291 g_assert_true(qtest_get_irq(qts
, wd
->irq
));
296 static void watchdog_add_test(const char *name
, const Watchdog
* wd
,
299 g_autofree
char *full_name
= g_strdup_printf(
300 "npcm7xx_watchdog_timer[%d]/%s", watchdog_index(wd
), name
);
301 qtest_add_data_func(full_name
, wd
, fn
);
303 #define add_test(name, td) watchdog_add_test(#name, td, test_##name)
305 int main(int argc
, char **argv
)
307 g_test_init(&argc
, &argv
, NULL
);
308 g_test_set_nonfatal_assertions();
310 for (int i
= 0; i
< ARRAY_SIZE(watchdog_list
); ++i
) {
311 const Watchdog
*wd
= &watchdog_list
[i
];
314 add_test(reset_action
, wd
);
315 add_test(prescaler
, wd
);
316 add_test(enabling_flags
, wd
);