xref: /openbmc/qemu/tests/qtest/cmsdk-apb-watchdog-test.c (revision 9a0762c13283da7130cf27d174d5bbf4b7cc2acb)
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 
71583c9884SRoque Arcudia Hernandez static void test_watchdog(const void *ptr)
72583c9884SRoque Arcudia Hernandez {
73583c9884SRoque Arcudia Hernandez     const CMSDKAPBWatchdogTestArgs *args = ptr;
74583c9884SRoque Arcudia Hernandez     hwaddr wdog_base = args->wdog_base;
75583c9884SRoque Arcudia Hernandez     int64_t tick = args->tick;
76583c9884SRoque Arcudia Hernandez     g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
77583c9884SRoque Arcudia Hernandez     qtest_start(cmdline);
78583c9884SRoque Arcudia Hernandez 
79583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
80583c9884SRoque Arcudia Hernandez 
81583c9884SRoque Arcudia Hernandez     writel(wdog_base + WDOGCONTROL, 1);
82583c9884SRoque Arcudia Hernandez     writel(wdog_base + WDOGLOAD, 1000);
839cf5eb29SPeter Maydell 
849cf5eb29SPeter Maydell     /* Step to just past the 500th tick */
85583c9884SRoque Arcudia Hernandez     clock_step(500 * tick + 1);
86583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
87583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500);
889cf5eb29SPeter Maydell 
899cf5eb29SPeter Maydell     /* Just past the 1000th tick: timer should have fired */
90583c9884SRoque Arcudia Hernandez     clock_step(500 * tick);
91583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1);
92583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 0);
939cf5eb29SPeter Maydell 
949cf5eb29SPeter Maydell     /* VALUE reloads at following tick */
95583c9884SRoque Arcudia Hernandez     clock_step(tick);
96583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000);
979cf5eb29SPeter Maydell 
989cf5eb29SPeter Maydell     /* Writing any value to WDOGINTCLR clears the interrupt and reloads */
99583c9884SRoque Arcudia Hernandez     clock_step(500 * tick);
100583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500);
101583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1);
102583c9884SRoque Arcudia Hernandez     writel(wdog_base + WDOGINTCLR, 0);
103583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000);
104583c9884SRoque Arcudia Hernandez     g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
105583c9884SRoque Arcudia Hernandez 
106583c9884SRoque Arcudia Hernandez     qtest_end();
1079cf5eb29SPeter Maydell }
1089cf5eb29SPeter Maydell 
109583c9884SRoque Arcudia Hernandez /*
110583c9884SRoque Arcudia Hernandez  * This test can only be executed in the stellaris board since it relies on a
111583c9884SRoque Arcudia Hernandez  * component of the board to change the clocking parameters of the watchdog.
112583c9884SRoque Arcudia Hernandez  */
113583c9884SRoque Arcudia Hernandez static void test_clock_change(const void *ptr)
1147bbb12f3SPeter Maydell {
1157bbb12f3SPeter Maydell     uint32_t rcc;
116583c9884SRoque Arcudia Hernandez     const CMSDKAPBWatchdogTestArgs *args = ptr;
117583c9884SRoque Arcudia Hernandez     g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
118583c9884SRoque Arcudia Hernandez     qtest_start(cmdline);
1197bbb12f3SPeter Maydell 
1207bbb12f3SPeter Maydell     /*
1217bbb12f3SPeter Maydell      * Test that writing to the stellaris board's RCC register to
1227bbb12f3SPeter Maydell      * change the system clock frequency causes the watchdog
1237bbb12f3SPeter Maydell      * to change the speed it counts at.
1247bbb12f3SPeter Maydell      */
1257bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
1267bbb12f3SPeter Maydell 
1277bbb12f3SPeter Maydell     writel(WDOG_BASE + WDOGCONTROL, 1);
1287bbb12f3SPeter Maydell     writel(WDOG_BASE + WDOGLOAD, 1000);
1297bbb12f3SPeter Maydell 
1307bbb12f3SPeter Maydell     /* Step to just past the 500th tick */
1317bbb12f3SPeter Maydell     clock_step(80 * 500 + 1);
1327bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
1337bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
1347bbb12f3SPeter Maydell 
1357bbb12f3SPeter Maydell     /* Rewrite RCC.SYSDIV from 16 to 8, so the clock is now 40ns per tick */
1367bbb12f3SPeter Maydell     rcc = readl(SSYS_BASE + RCC);
13758045186SInès Varhol     g_assert_cmphex(extract32(rcc, SYSDIV_SHIFT, SYSDIV_LENGTH), ==, 0xf);
1387bbb12f3SPeter Maydell     rcc = deposit32(rcc, SYSDIV_SHIFT, SYSDIV_LENGTH, 7);
1397bbb12f3SPeter Maydell     writel(SSYS_BASE + RCC, rcc);
1407bbb12f3SPeter Maydell 
1417bbb12f3SPeter Maydell     /* Just past the 1000th tick: timer should have fired */
1427bbb12f3SPeter Maydell     clock_step(40 * 500);
1437bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
1447bbb12f3SPeter Maydell 
1457bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 0);
1467bbb12f3SPeter Maydell 
1477bbb12f3SPeter Maydell     /* VALUE reloads at following tick */
1487bbb12f3SPeter Maydell     clock_step(41);
1497bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
1507bbb12f3SPeter Maydell 
1517bbb12f3SPeter Maydell     /* Writing any value to WDOGINTCLR clears the interrupt and reloads */
1527bbb12f3SPeter Maydell     clock_step(40 * 500);
1537bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
1547bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
1557bbb12f3SPeter Maydell     writel(WDOG_BASE + WDOGINTCLR, 0);
1567bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
1577bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
158583c9884SRoque Arcudia Hernandez 
159583c9884SRoque Arcudia Hernandez     qtest_end();
1607bbb12f3SPeter Maydell }
1617bbb12f3SPeter Maydell 
1629cf5eb29SPeter Maydell int main(int argc, char **argv)
1639cf5eb29SPeter Maydell {
1649cf5eb29SPeter Maydell     int r;
1659cf5eb29SPeter Maydell 
1669cf5eb29SPeter Maydell     g_test_init(&argc, &argv, NULL);
167*9a0762c1SRoque Arcudia Hernandez     g_test_set_nonfatal_assertions();
1689cf5eb29SPeter Maydell 
169583c9884SRoque Arcudia Hernandez     if (qtest_has_machine(machine_info[MACHINE_LM3S811EVB].machine)) {
170583c9884SRoque Arcudia Hernandez         qtest_add_data_func("/cmsdk-apb-watchdog/watchdog",
171583c9884SRoque Arcudia Hernandez                             &machine_info[MACHINE_LM3S811EVB], test_watchdog);
172583c9884SRoque Arcudia Hernandez         qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_clock_change",
173583c9884SRoque Arcudia Hernandez                             &machine_info[MACHINE_LM3S811EVB],
1747bbb12f3SPeter Maydell                             test_clock_change);
175583c9884SRoque Arcudia Hernandez     }
176583c9884SRoque Arcudia Hernandez     if (qtest_has_machine(machine_info[MACHINE_MPS2_AN385].machine)) {
177583c9884SRoque Arcudia Hernandez         qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_mps2",
178583c9884SRoque Arcudia Hernandez                             &machine_info[MACHINE_MPS2_AN385], test_watchdog);
179583c9884SRoque Arcudia Hernandez     }
1809cf5eb29SPeter Maydell 
1819cf5eb29SPeter Maydell     r = g_test_run();
1829cf5eb29SPeter Maydell 
1839cf5eb29SPeter Maydell     return r;
1849cf5eb29SPeter Maydell }
185