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"
18*7bbb12f3SPeter Maydell #include "qemu/bitops.h"
199cf5eb29SPeter Maydell #include "libqtest-single.h"
209cf5eb29SPeter Maydell 
219cf5eb29SPeter Maydell /*
229cf5eb29SPeter Maydell  * lm3s811evb watchdog; at board startup this runs at 200MHz / 16 == 12.5MHz,
239cf5eb29SPeter Maydell  * which is 80ns per tick.
249cf5eb29SPeter Maydell  */
259cf5eb29SPeter Maydell #define WDOG_BASE 0x40000000
269cf5eb29SPeter Maydell 
279cf5eb29SPeter Maydell #define WDOGLOAD 0
289cf5eb29SPeter Maydell #define WDOGVALUE 4
299cf5eb29SPeter Maydell #define WDOGCONTROL 8
309cf5eb29SPeter Maydell #define WDOGINTCLR 0xc
319cf5eb29SPeter Maydell #define WDOGRIS 0x10
329cf5eb29SPeter Maydell #define WDOGMIS 0x14
339cf5eb29SPeter Maydell #define WDOGLOCK 0xc00
349cf5eb29SPeter Maydell 
35*7bbb12f3SPeter Maydell #define SSYS_BASE 0x400fe000
36*7bbb12f3SPeter Maydell #define RCC 0x60
37*7bbb12f3SPeter Maydell #define SYSDIV_SHIFT 23
38*7bbb12f3SPeter Maydell #define SYSDIV_LENGTH 4
39*7bbb12f3SPeter Maydell 
test_watchdog(void)409cf5eb29SPeter Maydell static void test_watchdog(void)
419cf5eb29SPeter Maydell {
429cf5eb29SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
439cf5eb29SPeter Maydell 
449cf5eb29SPeter Maydell     writel(WDOG_BASE + WDOGCONTROL, 1);
459cf5eb29SPeter Maydell     writel(WDOG_BASE + WDOGLOAD, 1000);
469cf5eb29SPeter Maydell 
479cf5eb29SPeter Maydell     /* Step to just past the 500th tick */
489cf5eb29SPeter Maydell     clock_step(500 * 80 + 1);
499cf5eb29SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
509cf5eb29SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
519cf5eb29SPeter Maydell 
529cf5eb29SPeter Maydell     /* Just past the 1000th tick: timer should have fired */
539cf5eb29SPeter Maydell     clock_step(500 * 80);
549cf5eb29SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
559cf5eb29SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 0);
569cf5eb29SPeter Maydell 
579cf5eb29SPeter Maydell     /* VALUE reloads at following tick */
589cf5eb29SPeter Maydell     clock_step(80);
599cf5eb29SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
609cf5eb29SPeter Maydell 
619cf5eb29SPeter Maydell     /* Writing any value to WDOGINTCLR clears the interrupt and reloads */
629cf5eb29SPeter Maydell     clock_step(500 * 80);
639cf5eb29SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
649cf5eb29SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
659cf5eb29SPeter Maydell     writel(WDOG_BASE + WDOGINTCLR, 0);
669cf5eb29SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
679cf5eb29SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
689cf5eb29SPeter Maydell }
699cf5eb29SPeter Maydell 
test_clock_change(void)70*7bbb12f3SPeter Maydell static void test_clock_change(void)
71*7bbb12f3SPeter Maydell {
72*7bbb12f3SPeter Maydell     uint32_t rcc;
73*7bbb12f3SPeter Maydell 
74*7bbb12f3SPeter Maydell     /*
75*7bbb12f3SPeter Maydell      * Test that writing to the stellaris board's RCC register to
76*7bbb12f3SPeter Maydell      * change the system clock frequency causes the watchdog
77*7bbb12f3SPeter Maydell      * to change the speed it counts at.
78*7bbb12f3SPeter Maydell      */
79*7bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
80*7bbb12f3SPeter Maydell 
81*7bbb12f3SPeter Maydell     writel(WDOG_BASE + WDOGCONTROL, 1);
82*7bbb12f3SPeter Maydell     writel(WDOG_BASE + WDOGLOAD, 1000);
83*7bbb12f3SPeter Maydell 
84*7bbb12f3SPeter Maydell     /* Step to just past the 500th tick */
85*7bbb12f3SPeter Maydell     clock_step(80 * 500 + 1);
86*7bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
87*7bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
88*7bbb12f3SPeter Maydell 
89*7bbb12f3SPeter Maydell     /* Rewrite RCC.SYSDIV from 16 to 8, so the clock is now 40ns per tick */
90*7bbb12f3SPeter Maydell     rcc = readl(SSYS_BASE + RCC);
91*7bbb12f3SPeter Maydell     g_assert_cmpuint(extract32(rcc, SYSDIV_SHIFT, SYSDIV_LENGTH), ==, 0xf);
92*7bbb12f3SPeter Maydell     rcc = deposit32(rcc, SYSDIV_SHIFT, SYSDIV_LENGTH, 7);
93*7bbb12f3SPeter Maydell     writel(SSYS_BASE + RCC, rcc);
94*7bbb12f3SPeter Maydell 
95*7bbb12f3SPeter Maydell     /* Just past the 1000th tick: timer should have fired */
96*7bbb12f3SPeter Maydell     clock_step(40 * 500);
97*7bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
98*7bbb12f3SPeter Maydell 
99*7bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 0);
100*7bbb12f3SPeter Maydell 
101*7bbb12f3SPeter Maydell     /* VALUE reloads at following tick */
102*7bbb12f3SPeter Maydell     clock_step(41);
103*7bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
104*7bbb12f3SPeter Maydell 
105*7bbb12f3SPeter Maydell     /* Writing any value to WDOGINTCLR clears the interrupt and reloads */
106*7bbb12f3SPeter Maydell     clock_step(40 * 500);
107*7bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
108*7bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
109*7bbb12f3SPeter Maydell     writel(WDOG_BASE + WDOGINTCLR, 0);
110*7bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
111*7bbb12f3SPeter Maydell     g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
112*7bbb12f3SPeter Maydell }
113*7bbb12f3SPeter Maydell 
main(int argc,char ** argv)1149cf5eb29SPeter Maydell int main(int argc, char **argv)
1159cf5eb29SPeter Maydell {
1169cf5eb29SPeter Maydell     int r;
1179cf5eb29SPeter Maydell 
1189cf5eb29SPeter Maydell     g_test_init(&argc, &argv, NULL);
1199cf5eb29SPeter Maydell 
1209cf5eb29SPeter Maydell     qtest_start("-machine lm3s811evb");
1219cf5eb29SPeter Maydell 
1229cf5eb29SPeter Maydell     qtest_add_func("/cmsdk-apb-watchdog/watchdog", test_watchdog);
123*7bbb12f3SPeter Maydell     qtest_add_func("/cmsdk-apb-watchdog/watchdog_clock_change",
124*7bbb12f3SPeter Maydell                    test_clock_change);
1259cf5eb29SPeter Maydell 
1269cf5eb29SPeter Maydell     r = g_test_run();
1279cf5eb29SPeter Maydell 
1289cf5eb29SPeter Maydell     qtest_end();
1299cf5eb29SPeter Maydell 
1309cf5eb29SPeter Maydell     return r;
1319cf5eb29SPeter Maydell }
132