xref: /openbmc/qemu/tests/qtest/cmsdk-apb-watchdog-test.c (revision e6459afb1ff4d86b361b14f4a2fc43f0d2b4d679)
19cf5eb29SPeter Maydell /*
29cf5eb29SPeter Maydell  * QTest testcase for the CMSDK APB watchdog device
39cf5eb29SPeter Maydell  *
49cf5eb29SPeter Maydell  * Copyright (c) 2021 Linaro Limited
59cf5eb29SPeter Maydell  *
69cf5eb29SPeter Maydell  * This program is free software; you can redistribute it and/or modify it
79cf5eb29SPeter Maydell  * under the terms of the GNU General Public License as published by the
89cf5eb29SPeter Maydell  * Free Software Foundation; either version 2 of the License, or
99cf5eb29SPeter Maydell  * (at your option) any later version.
109cf5eb29SPeter Maydell  *
119cf5eb29SPeter Maydell  * This program is distributed in the hope that it will be useful, but WITHOUT
129cf5eb29SPeter Maydell  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
139cf5eb29SPeter Maydell  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
149cf5eb29SPeter Maydell  * for more details.
159cf5eb29SPeter Maydell  */
169cf5eb29SPeter Maydell 
179cf5eb29SPeter Maydell #include "qemu/osdep.h"
18583c9884SRoque Arcudia Hernandez #include "exec/hwaddr.h"
197bbb12f3SPeter Maydell #include "qemu/bitops.h"
209cf5eb29SPeter Maydell #include "libqtest-single.h"
219cf5eb29SPeter Maydell 
229cf5eb29SPeter Maydell #define WDOG_BASE 0x40000000
23583c9884SRoque Arcudia Hernandez #define WDOG_BASE_MPS2 0x40008000
249cf5eb29SPeter Maydell 
259cf5eb29SPeter Maydell #define WDOGLOAD 0
269cf5eb29SPeter Maydell #define WDOGVALUE 4
279cf5eb29SPeter Maydell #define WDOGCONTROL 8
289cf5eb29SPeter Maydell #define WDOGINTCLR 0xc
299cf5eb29SPeter Maydell #define WDOGRIS 0x10
309cf5eb29SPeter Maydell #define WDOGMIS 0x14
319cf5eb29SPeter Maydell #define WDOGLOCK 0xc00
329cf5eb29SPeter Maydell 
337bbb12f3SPeter Maydell #define SSYS_BASE 0x400fe000
347bbb12f3SPeter Maydell #define RCC 0x60
357bbb12f3SPeter Maydell #define SYSDIV_SHIFT 23
367bbb12f3SPeter Maydell #define SYSDIV_LENGTH 4
377bbb12f3SPeter Maydell 
38583c9884SRoque Arcudia Hernandez #define WDOGLOAD_DEFAULT 0xFFFFFFFF
39583c9884SRoque Arcudia Hernandez #define WDOGVALUE_DEFAULT 0xFFFFFFFF
409cf5eb29SPeter Maydell 
41583c9884SRoque Arcudia Hernandez typedef struct CMSDKAPBWatchdogTestArgs {
42583c9884SRoque Arcudia Hernandez     int64_t tick;
43583c9884SRoque Arcudia Hernandez     hwaddr wdog_base;
44583c9884SRoque Arcudia Hernandez     const char *machine;
45583c9884SRoque Arcudia Hernandez } CMSDKAPBWatchdogTestArgs;
46583c9884SRoque Arcudia Hernandez 
47583c9884SRoque Arcudia Hernandez enum {
48583c9884SRoque Arcudia Hernandez     MACHINE_LM3S811EVB,
49583c9884SRoque Arcudia Hernandez     MACHINE_MPS2_AN385,
50583c9884SRoque Arcudia Hernandez };
51583c9884SRoque Arcudia Hernandez 
52583c9884SRoque Arcudia Hernandez /*
53583c9884SRoque Arcudia Hernandez  * lm3s811evb watchdog; at board startup this runs at 200MHz / 16 == 12.5MHz,
54583c9884SRoque Arcudia Hernandez  * which is 80ns per tick.
55583c9884SRoque Arcudia Hernandez  *
56583c9884SRoque Arcudia Hernandez  * IoTKit/ARMSSE dualtimer; driven at 25MHz in mps2-an385, so 40ns per tick
57583c9884SRoque Arcudia Hernandez  */
58583c9884SRoque Arcudia Hernandez static const CMSDKAPBWatchdogTestArgs machine_info[] = {
59583c9884SRoque Arcudia Hernandez     [MACHINE_LM3S811EVB] = {
60583c9884SRoque Arcudia Hernandez         .tick = 80,
61583c9884SRoque Arcudia Hernandez         .wdog_base = WDOG_BASE,
62583c9884SRoque Arcudia Hernandez         .machine = "lm3s811evb",
63583c9884SRoque Arcudia Hernandez     },
64583c9884SRoque Arcudia Hernandez     [MACHINE_MPS2_AN385] = {
65583c9884SRoque Arcudia Hernandez         .tick = 40,
66583c9884SRoque Arcudia Hernandez         .wdog_base = WDOG_BASE_MPS2,
67583c9884SRoque Arcudia Hernandez         .machine = "mps2-an385",
68583c9884SRoque Arcudia Hernandez     },
69583c9884SRoque Arcudia Hernandez };
70583c9884SRoque Arcudia Hernandez 
system_reset(QTestState * qtest)71*b0a10091SRoque Arcudia Hernandez static void system_reset(QTestState *qtest)
72*b0a10091SRoque Arcudia Hernandez {
73*b0a10091SRoque Arcudia Hernandez     QDict *resp;
74*b0a10091SRoque Arcudia Hernandez 
75*b0a10091SRoque Arcudia Hernandez     resp = qtest_qmp(qtest, "{'execute': 'system_reset'}");
76*b0a10091SRoque Arcudia Hernandez     g_assert(qdict_haskey(resp, "return"));
77*b0a10091SRoque Arcudia Hernandez     qobject_unref(resp);
78*b0a10091SRoque Arcudia Hernandez     qtest_qmp_eventwait(qtest, "RESET");
79*b0a10091SRoque Arcudia Hernandez }
80*b0a10091SRoque Arcudia Hernandez 
test_watchdog(const void * ptr)81583c9884SRoque Arcudia Hernandez static void test_watchdog(const void *ptr)
82583c9884SRoque Arcudia Hernandez {
83583c9884SRoque Arcudia Hernandez     const CMSDKAPBWatchdogTestArgs *args = ptr;
84583c9884SRoque Arcudia Hernandez     hwaddr wdog_base = args->wdog_base;
85583c9884SRoque Arcudia Hernandez     int64_t tick = args->tick;
86583c9884SRoque Arcudia Hernandez     g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
87583c9884SRoque Arcudia Hernandez     qtest_start(cmdline);
88583c9884SRoque Arcudia Hernandez 
89583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
90583c9884SRoque Arcudia Hernandez 
91583c9884SRoque Arcudia Hernandez     writel(wdog_base + WDOGCONTROL, 1);
92583c9884SRoque Arcudia Hernandez     writel(wdog_base + WDOGLOAD, 1000);
939cf5eb29SPeter Maydell 
949cf5eb29SPeter Maydell     /* Step to just past the 500th tick */
95583c9884SRoque Arcudia Hernandez     clock_step(500 * tick + 1);
96583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
97583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500);
989cf5eb29SPeter Maydell 
999cf5eb29SPeter Maydell     /* Just past the 1000th tick: timer should have fired */
100583c9884SRoque Arcudia Hernandez     clock_step(500 * tick);
101583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1);
102583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 0);
1039cf5eb29SPeter Maydell 
1049cf5eb29SPeter Maydell     /* VALUE reloads at following tick */
105583c9884SRoque Arcudia Hernandez     clock_step(tick);
106583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000);
1079cf5eb29SPeter Maydell 
1089cf5eb29SPeter Maydell     /* Writing any value to WDOGINTCLR clears the interrupt and reloads */
109583c9884SRoque Arcudia Hernandez     clock_step(500 * tick);
110583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500);
111583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1);
112583c9884SRoque Arcudia Hernandez     writel(wdog_base + WDOGINTCLR, 0);
113583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000);
114583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
115583c9884SRoque Arcudia Hernandez 
116583c9884SRoque Arcudia Hernandez     qtest_end();
1179cf5eb29SPeter Maydell }
1189cf5eb29SPeter Maydell 
119583c9884SRoque Arcudia Hernandez /*
120583c9884SRoque Arcudia Hernandez  * This test can only be executed in the stellaris board since it relies on a
121583c9884SRoque Arcudia Hernandez  * component of the board to change the clocking parameters of the watchdog.
122583c9884SRoque Arcudia Hernandez  */
test_clock_change(const void * ptr)123583c9884SRoque Arcudia Hernandez static void test_clock_change(const void *ptr)
1247bbb12f3SPeter Maydell {
1257bbb12f3SPeter Maydell     uint32_t rcc;
126583c9884SRoque Arcudia Hernandez     const CMSDKAPBWatchdogTestArgs *args = ptr;
127583c9884SRoque Arcudia Hernandez     g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
128583c9884SRoque Arcudia Hernandez     qtest_start(cmdline);
1297bbb12f3SPeter Maydell 
1307bbb12f3SPeter Maydell     /*
1317bbb12f3SPeter Maydell      * Test that writing to the stellaris board's RCC register to
1327bbb12f3SPeter Maydell      * change the system clock frequency causes the watchdog
1337bbb12f3SPeter Maydell      * to change the speed it counts at.
1347bbb12f3SPeter Maydell      */
1357bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
1367bbb12f3SPeter Maydell 
1377bbb12f3SPeter Maydell     writel(WDOG_BASE + WDOGCONTROL, 1);
1387bbb12f3SPeter Maydell     writel(WDOG_BASE + WDOGLOAD, 1000);
1397bbb12f3SPeter Maydell 
1407bbb12f3SPeter Maydell     /* Step to just past the 500th tick */
1417bbb12f3SPeter Maydell     clock_step(80 * 500 + 1);
1427bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
1437bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
1447bbb12f3SPeter Maydell 
1457bbb12f3SPeter Maydell     /* Rewrite RCC.SYSDIV from 16 to 8, so the clock is now 40ns per tick */
1467bbb12f3SPeter Maydell     rcc = readl(SSYS_BASE + RCC);
14758045186SInès Varhol     g_assert_cmphex(extract32(rcc, SYSDIV_SHIFT, SYSDIV_LENGTH), ==, 0xf);
1487bbb12f3SPeter Maydell     rcc = deposit32(rcc, SYSDIV_SHIFT, SYSDIV_LENGTH, 7);
1497bbb12f3SPeter Maydell     writel(SSYS_BASE + RCC, rcc);
1507bbb12f3SPeter Maydell 
1517bbb12f3SPeter Maydell     /* Just past the 1000th tick: timer should have fired */
1527bbb12f3SPeter Maydell     clock_step(40 * 500);
1537bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
1547bbb12f3SPeter Maydell 
1557bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 0);
1567bbb12f3SPeter Maydell 
1577bbb12f3SPeter Maydell     /* VALUE reloads at following tick */
1587bbb12f3SPeter Maydell     clock_step(41);
1597bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
1607bbb12f3SPeter Maydell 
1617bbb12f3SPeter Maydell     /* Writing any value to WDOGINTCLR clears the interrupt and reloads */
1627bbb12f3SPeter Maydell     clock_step(40 * 500);
1637bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
1647bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
1657bbb12f3SPeter Maydell     writel(WDOG_BASE + WDOGINTCLR, 0);
1667bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
1677bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
168583c9884SRoque Arcudia Hernandez 
169583c9884SRoque Arcudia Hernandez     qtest_end();
1707bbb12f3SPeter Maydell }
1717bbb12f3SPeter Maydell 
172*b0a10091SRoque Arcudia Hernandez /* Tests the counter is not running after reset. */
test_watchdog_reset(const void * ptr)173*b0a10091SRoque Arcudia Hernandez static void test_watchdog_reset(const void *ptr)
174*b0a10091SRoque Arcudia Hernandez {
175*b0a10091SRoque Arcudia Hernandez     const CMSDKAPBWatchdogTestArgs *args = ptr;
176*b0a10091SRoque Arcudia Hernandez     hwaddr wdog_base = args->wdog_base;
177*b0a10091SRoque Arcudia Hernandez     int64_t tick = args->tick;
178*b0a10091SRoque Arcudia Hernandez     g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
179*b0a10091SRoque Arcudia Hernandez     qtest_start(cmdline);
180*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
181*b0a10091SRoque Arcudia Hernandez 
182*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
183*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
184*b0a10091SRoque Arcudia Hernandez 
185*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0);
186*b0a10091SRoque Arcudia Hernandez 
187*b0a10091SRoque Arcudia Hernandez     /*
188*b0a10091SRoque Arcudia Hernandez      * The counter should not be running if WDOGCONTROL.INTEN has not been set,
189*b0a10091SRoque Arcudia Hernandez      * as it is the case after a cold reset.
190*b0a10091SRoque Arcudia Hernandez      */
191*b0a10091SRoque Arcudia Hernandez     clock_step(15 * tick + 1);
192*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
193*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
194*b0a10091SRoque Arcudia Hernandez 
195*b0a10091SRoque Arcudia Hernandez     /* Let the counter run before reset */
196*b0a10091SRoque Arcudia Hernandez     writel(wdog_base + WDOGLOAD, 3000);
197*b0a10091SRoque Arcudia Hernandez     writel(wdog_base + WDOGCONTROL, 1);
198*b0a10091SRoque Arcudia Hernandez 
199*b0a10091SRoque Arcudia Hernandez     /* Verify it is running */
200*b0a10091SRoque Arcudia Hernandez     clock_step(1000 * tick + 1);
201*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 3000);
202*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 2000);
203*b0a10091SRoque Arcudia Hernandez 
204*b0a10091SRoque Arcudia Hernandez     system_reset(global_qtest);
205*b0a10091SRoque Arcudia Hernandez 
206*b0a10091SRoque Arcudia Hernandez     /* Check defaults after reset */
207*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
208*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
209*b0a10091SRoque Arcudia Hernandez 
210*b0a10091SRoque Arcudia Hernandez     /* The counter should not be running after reset. */
211*b0a10091SRoque Arcudia Hernandez     clock_step(1000 * tick + 1);
212*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
213*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
214*b0a10091SRoque Arcudia Hernandez 
215*b0a10091SRoque Arcudia Hernandez     qtest_end();
216*b0a10091SRoque Arcudia Hernandez }
217*b0a10091SRoque Arcudia Hernandez 
218*b0a10091SRoque Arcudia Hernandez /*
219*b0a10091SRoque Arcudia Hernandez  * Tests inten works as the counter enable based on this description:
220*b0a10091SRoque Arcudia Hernandez  *
221*b0a10091SRoque Arcudia Hernandez  * Enable the interrupt event, WDOGINT. Set HIGH to enable the counter and the
222*b0a10091SRoque Arcudia Hernandez  * interrupt, or LOW to disable the counter and interrupt. Reloads the counter
223*b0a10091SRoque Arcudia Hernandez  * from the value in WDOGLOAD when the interrupt is enabled, after previously
224*b0a10091SRoque Arcudia Hernandez  * being disabled.
225*b0a10091SRoque Arcudia Hernandez  */
test_watchdog_inten(const void * ptr)226*b0a10091SRoque Arcudia Hernandez static void test_watchdog_inten(const void *ptr)
227*b0a10091SRoque Arcudia Hernandez {
228*b0a10091SRoque Arcudia Hernandez     const CMSDKAPBWatchdogTestArgs *args = ptr;
229*b0a10091SRoque Arcudia Hernandez     hwaddr wdog_base = args->wdog_base;
230*b0a10091SRoque Arcudia Hernandez     int64_t tick = args->tick;
231*b0a10091SRoque Arcudia Hernandez     g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
232*b0a10091SRoque Arcudia Hernandez     qtest_start(cmdline);
233*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
234*b0a10091SRoque Arcudia Hernandez 
235*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
236*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
237*b0a10091SRoque Arcudia Hernandez 
238*b0a10091SRoque Arcudia Hernandez     /*
239*b0a10091SRoque Arcudia Hernandez      * When WDOGLOAD is written to, the count is immediately restarted from the
240*b0a10091SRoque Arcudia Hernandez      * new value.
241*b0a10091SRoque Arcudia Hernandez      *
242*b0a10091SRoque Arcudia Hernandez      * Note: the counter should not be running as long as WDOGCONTROL.INTEN is
243*b0a10091SRoque Arcudia Hernandez      * not set
244*b0a10091SRoque Arcudia Hernandez      */
245*b0a10091SRoque Arcudia Hernandez     writel(wdog_base + WDOGLOAD, 4000);
246*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
247*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
248*b0a10091SRoque Arcudia Hernandez     clock_step(500 * tick + 1);
249*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
250*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
251*b0a10091SRoque Arcudia Hernandez 
252*b0a10091SRoque Arcudia Hernandez     /* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */
253*b0a10091SRoque Arcudia Hernandez     writel(wdog_base + WDOGCONTROL, 1);
254*b0a10091SRoque Arcudia Hernandez     clock_step(500 * tick + 1);
255*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
256*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500);
257*b0a10091SRoque Arcudia Hernandez 
258*b0a10091SRoque Arcudia Hernandez     /* or LOW to disable the counter and interrupt. */
259*b0a10091SRoque Arcudia Hernandez     writel(wdog_base + WDOGCONTROL, 0);
260*b0a10091SRoque Arcudia Hernandez     clock_step(100 * tick);
261*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
262*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500);
263*b0a10091SRoque Arcudia Hernandez 
264*b0a10091SRoque Arcudia Hernandez     /*
265*b0a10091SRoque Arcudia Hernandez      * Reloads the counter from the value in WDOGLOAD when the interrupt is
266*b0a10091SRoque Arcudia Hernandez      * enabled, after previously being disabled.
267*b0a10091SRoque Arcudia Hernandez      */
268*b0a10091SRoque Arcudia Hernandez     writel(wdog_base + WDOGCONTROL, 1);
269*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
270*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
271*b0a10091SRoque Arcudia Hernandez 
272*b0a10091SRoque Arcudia Hernandez     /* Test counter is still on */
273*b0a10091SRoque Arcudia Hernandez     clock_step(50 * tick + 1);
274*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
275*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3950);
276*b0a10091SRoque Arcudia Hernandez 
277*b0a10091SRoque Arcudia Hernandez     /*
278*b0a10091SRoque Arcudia Hernandez      * When WDOGLOAD is written to, the count is immediately restarted from the
279*b0a10091SRoque Arcudia Hernandez      * new value.
280*b0a10091SRoque Arcudia Hernandez      *
281*b0a10091SRoque Arcudia Hernandez      * Note: the counter should be running since WDOGCONTROL.INTEN is set
282*b0a10091SRoque Arcudia Hernandez      */
283*b0a10091SRoque Arcudia Hernandez     writel(wdog_base + WDOGLOAD, 5000);
284*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000);
285*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 5000);
286*b0a10091SRoque Arcudia Hernandez     clock_step(4999 * tick + 1);
287*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000);
288*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1);
289*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
290*b0a10091SRoque Arcudia Hernandez 
291*b0a10091SRoque Arcudia Hernandez     /* Finally disable and check the conditions don't change */
292*b0a10091SRoque Arcudia Hernandez     writel(wdog_base + WDOGCONTROL, 0);
293*b0a10091SRoque Arcudia Hernandez     clock_step(10 * tick);
294*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000);
295*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1);
296*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
297*b0a10091SRoque Arcudia Hernandez 
298*b0a10091SRoque Arcudia Hernandez     qtest_end();
299*b0a10091SRoque Arcudia Hernandez }
300*b0a10091SRoque Arcudia Hernandez 
301*b0a10091SRoque Arcudia Hernandez /*
302*b0a10091SRoque Arcudia Hernandez  * Tests the following custom behavior:
303*b0a10091SRoque Arcudia Hernandez  *
304*b0a10091SRoque Arcudia Hernandez  * The Luminary version of this device ignores writes to this register after the
305*b0a10091SRoque Arcudia Hernandez  * guest has enabled interrupts (so they can only be disabled again via reset).
306*b0a10091SRoque Arcudia Hernandez  */
test_watchdog_inten_luminary(const void * ptr)307*b0a10091SRoque Arcudia Hernandez static void test_watchdog_inten_luminary(const void *ptr)
308*b0a10091SRoque Arcudia Hernandez {
309*b0a10091SRoque Arcudia Hernandez     const CMSDKAPBWatchdogTestArgs *args = ptr;
310*b0a10091SRoque Arcudia Hernandez     hwaddr wdog_base = args->wdog_base;
311*b0a10091SRoque Arcudia Hernandez     int64_t tick = args->tick;
312*b0a10091SRoque Arcudia Hernandez     g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
313*b0a10091SRoque Arcudia Hernandez     qtest_start(cmdline);
314*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
315*b0a10091SRoque Arcudia Hernandez 
316*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
317*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
318*b0a10091SRoque Arcudia Hernandez 
319*b0a10091SRoque Arcudia Hernandez     /*
320*b0a10091SRoque Arcudia Hernandez      * When WDOGLOAD is written to, the count is immediately restarted from the
321*b0a10091SRoque Arcudia Hernandez      * new value.
322*b0a10091SRoque Arcudia Hernandez      *
323*b0a10091SRoque Arcudia Hernandez      * Note: the counter should not be running as long as WDOGCONTROL.INTEN is
324*b0a10091SRoque Arcudia Hernandez      * not set
325*b0a10091SRoque Arcudia Hernandez      */
326*b0a10091SRoque Arcudia Hernandez     writel(wdog_base + WDOGLOAD, 4000);
327*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
328*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
329*b0a10091SRoque Arcudia Hernandez     clock_step(500 * tick + 1);
330*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
331*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
332*b0a10091SRoque Arcudia Hernandez 
333*b0a10091SRoque Arcudia Hernandez     /* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */
334*b0a10091SRoque Arcudia Hernandez     writel(wdog_base + WDOGCONTROL, 1);
335*b0a10091SRoque Arcudia Hernandez     clock_step(500 * tick + 1);
336*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
337*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500);
338*b0a10091SRoque Arcudia Hernandez 
339*b0a10091SRoque Arcudia Hernandez     /*
340*b0a10091SRoque Arcudia Hernandez      * The Luminary version of this device ignores writes to this register after
341*b0a10091SRoque Arcudia Hernandez      * the guest has enabled interrupts
342*b0a10091SRoque Arcudia Hernandez      */
343*b0a10091SRoque Arcudia Hernandez     writel(wdog_base + WDOGCONTROL, 0);
344*b0a10091SRoque Arcudia Hernandez     clock_step(100 * tick);
345*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
346*b0a10091SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3400);
347*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0x1);
348*b0a10091SRoque Arcudia Hernandez 
349*b0a10091SRoque Arcudia Hernandez     /* They can only be disabled again via reset */
350*b0a10091SRoque Arcudia Hernandez     system_reset(global_qtest);
351*b0a10091SRoque Arcudia Hernandez 
352*b0a10091SRoque Arcudia Hernandez     /* Check defaults after reset */
353*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
354*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
355*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0);
356*b0a10091SRoque Arcudia Hernandez 
357*b0a10091SRoque Arcudia Hernandez     /* The counter should not be running after reset. */
358*b0a10091SRoque Arcudia Hernandez     clock_step(1000 * tick + 1);
359*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
360*b0a10091SRoque Arcudia Hernandez     g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
361*b0a10091SRoque Arcudia Hernandez 
362*b0a10091SRoque Arcudia Hernandez     qtest_end();
363*b0a10091SRoque Arcudia Hernandez }
364*b0a10091SRoque Arcudia Hernandez 
main(int argc,char ** argv)3659cf5eb29SPeter Maydell int main(int argc, char **argv)
3669cf5eb29SPeter Maydell {
3679cf5eb29SPeter Maydell     int r;
3689cf5eb29SPeter Maydell 
3699cf5eb29SPeter Maydell     g_test_init(&argc, &argv, NULL);
3709a0762c1SRoque Arcudia Hernandez     g_test_set_nonfatal_assertions();
3719cf5eb29SPeter Maydell 
372583c9884SRoque Arcudia Hernandez     if (qtest_has_machine(machine_info[MACHINE_LM3S811EVB].machine)) {
373583c9884SRoque Arcudia Hernandez         qtest_add_data_func("/cmsdk-apb-watchdog/watchdog",
374583c9884SRoque Arcudia Hernandez                             &machine_info[MACHINE_LM3S811EVB], test_watchdog);
375583c9884SRoque Arcudia Hernandez         qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_clock_change",
376583c9884SRoque Arcudia Hernandez                             &machine_info[MACHINE_LM3S811EVB],
3777bbb12f3SPeter Maydell                             test_clock_change);
378*b0a10091SRoque Arcudia Hernandez         qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_reset",
379*b0a10091SRoque Arcudia Hernandez                             &machine_info[MACHINE_LM3S811EVB],
380*b0a10091SRoque Arcudia Hernandez                             test_watchdog_reset);
381*b0a10091SRoque Arcudia Hernandez         qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_inten_luminary",
382*b0a10091SRoque Arcudia Hernandez                             &machine_info[MACHINE_LM3S811EVB],
383*b0a10091SRoque Arcudia Hernandez                             test_watchdog_inten_luminary);
384583c9884SRoque Arcudia Hernandez     }
385583c9884SRoque Arcudia Hernandez     if (qtest_has_machine(machine_info[MACHINE_MPS2_AN385].machine)) {
386583c9884SRoque Arcudia Hernandez         qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_mps2",
387583c9884SRoque Arcudia Hernandez                             &machine_info[MACHINE_MPS2_AN385], test_watchdog);
388*b0a10091SRoque Arcudia Hernandez         qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_reset_mps2",
389*b0a10091SRoque Arcudia Hernandez                             &machine_info[MACHINE_MPS2_AN385],
390*b0a10091SRoque Arcudia Hernandez                             test_watchdog_reset);
391*b0a10091SRoque Arcudia Hernandez         qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_inten",
392*b0a10091SRoque Arcudia Hernandez                             &machine_info[MACHINE_MPS2_AN385],
393*b0a10091SRoque Arcudia Hernandez                             test_watchdog_inten);
394583c9884SRoque Arcudia Hernandez     }
3959cf5eb29SPeter Maydell 
3969cf5eb29SPeter Maydell     r = g_test_run();
3979cf5eb29SPeter Maydell 
3989cf5eb29SPeter Maydell     return r;
3999cf5eb29SPeter Maydell }
400