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