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 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 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 */ 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. */ 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 */ 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 */ 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 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