1 /* 2 * QTest testcase for the CMSDK APB watchdog device 3 * 4 * Copyright (c) 2021 Linaro Limited 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * for more details. 15 */ 16 17 #include "qemu/osdep.h" 18 #include "exec/hwaddr.h" 19 #include "qemu/bitops.h" 20 #include "libqtest-single.h" 21 22 #define WDOG_BASE 0x40000000 23 #define WDOG_BASE_MPS2 0x40008000 24 25 #define WDOGLOAD 0 26 #define WDOGVALUE 4 27 #define WDOGCONTROL 8 28 #define WDOGINTCLR 0xc 29 #define WDOGRIS 0x10 30 #define WDOGMIS 0x14 31 #define WDOGLOCK 0xc00 32 33 #define SSYS_BASE 0x400fe000 34 #define RCC 0x60 35 #define SYSDIV_SHIFT 23 36 #define SYSDIV_LENGTH 4 37 38 #define WDOGLOAD_DEFAULT 0xFFFFFFFF 39 #define WDOGVALUE_DEFAULT 0xFFFFFFFF 40 41 typedef struct CMSDKAPBWatchdogTestArgs { 42 int64_t tick; 43 hwaddr wdog_base; 44 const char *machine; 45 } CMSDKAPBWatchdogTestArgs; 46 47 enum { 48 MACHINE_LM3S811EVB, 49 MACHINE_MPS2_AN385, 50 }; 51 52 /* 53 * lm3s811evb watchdog; at board startup this runs at 200MHz / 16 == 12.5MHz, 54 * which is 80ns per tick. 55 * 56 * IoTKit/ARMSSE dualtimer; driven at 25MHz in mps2-an385, so 40ns per tick 57 */ 58 static const CMSDKAPBWatchdogTestArgs machine_info[] = { 59 [MACHINE_LM3S811EVB] = { 60 .tick = 80, 61 .wdog_base = WDOG_BASE, 62 .machine = "lm3s811evb", 63 }, 64 [MACHINE_MPS2_AN385] = { 65 .tick = 40, 66 .wdog_base = WDOG_BASE_MPS2, 67 .machine = "mps2-an385", 68 }, 69 }; 70 71 static void system_reset(QTestState *qtest) 72 { 73 QDict *resp; 74 75 resp = qtest_qmp(qtest, "{'execute': 'system_reset'}"); 76 g_assert(qdict_haskey(resp, "return")); 77 qobject_unref(resp); 78 qtest_qmp_eventwait(qtest, "RESET"); 79 } 80 81 static void test_watchdog(const void *ptr) 82 { 83 const CMSDKAPBWatchdogTestArgs *args = ptr; 84 hwaddr wdog_base = args->wdog_base; 85 int64_t tick = args->tick; 86 g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine); 87 qtest_start(cmdline); 88 89 g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); 90 91 writel(wdog_base + WDOGCONTROL, 1); 92 writel(wdog_base + WDOGLOAD, 1000); 93 94 /* Step to just past the 500th tick */ 95 clock_step(500 * tick + 1); 96 g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); 97 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500); 98 99 /* Just past the 1000th tick: timer should have fired */ 100 clock_step(500 * tick); 101 g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1); 102 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 0); 103 104 /* VALUE reloads at following tick */ 105 clock_step(tick); 106 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000); 107 108 /* Writing any value to WDOGINTCLR clears the interrupt and reloads */ 109 clock_step(500 * tick); 110 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500); 111 g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1); 112 writel(wdog_base + WDOGINTCLR, 0); 113 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000); 114 g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); 115 116 qtest_end(); 117 } 118 119 /* 120 * This test can only be executed in the stellaris board since it relies on a 121 * component of the board to change the clocking parameters of the watchdog. 122 */ 123 static void test_clock_change(const void *ptr) 124 { 125 uint32_t rcc; 126 const CMSDKAPBWatchdogTestArgs *args = ptr; 127 g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine); 128 qtest_start(cmdline); 129 130 /* 131 * Test that writing to the stellaris board's RCC register to 132 * change the system clock frequency causes the watchdog 133 * to change the speed it counts at. 134 */ 135 g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0); 136 137 writel(WDOG_BASE + WDOGCONTROL, 1); 138 writel(WDOG_BASE + WDOGLOAD, 1000); 139 140 /* Step to just past the 500th tick */ 141 clock_step(80 * 500 + 1); 142 g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0); 143 g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500); 144 145 /* Rewrite RCC.SYSDIV from 16 to 8, so the clock is now 40ns per tick */ 146 rcc = readl(SSYS_BASE + RCC); 147 g_assert_cmphex(extract32(rcc, SYSDIV_SHIFT, SYSDIV_LENGTH), ==, 0xf); 148 rcc = deposit32(rcc, SYSDIV_SHIFT, SYSDIV_LENGTH, 7); 149 writel(SSYS_BASE + RCC, rcc); 150 151 /* Just past the 1000th tick: timer should have fired */ 152 clock_step(40 * 500); 153 g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1); 154 155 g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 0); 156 157 /* VALUE reloads at following tick */ 158 clock_step(41); 159 g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000); 160 161 /* Writing any value to WDOGINTCLR clears the interrupt and reloads */ 162 clock_step(40 * 500); 163 g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500); 164 g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1); 165 writel(WDOG_BASE + WDOGINTCLR, 0); 166 g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000); 167 g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0); 168 169 qtest_end(); 170 } 171 172 /* Tests the counter is not running after reset. */ 173 static void test_watchdog_reset(const void *ptr) 174 { 175 const CMSDKAPBWatchdogTestArgs *args = ptr; 176 hwaddr wdog_base = args->wdog_base; 177 int64_t tick = args->tick; 178 g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine); 179 qtest_start(cmdline); 180 g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); 181 182 g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); 183 g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); 184 185 g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0); 186 187 /* 188 * The counter should not be running if WDOGCONTROL.INTEN has not been set, 189 * as it is the case after a cold reset. 190 */ 191 clock_step(15 * tick + 1); 192 g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); 193 g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); 194 195 /* Let the counter run before reset */ 196 writel(wdog_base + WDOGLOAD, 3000); 197 writel(wdog_base + WDOGCONTROL, 1); 198 199 /* Verify it is running */ 200 clock_step(1000 * tick + 1); 201 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 3000); 202 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 2000); 203 204 system_reset(global_qtest); 205 206 /* Check defaults after reset */ 207 g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); 208 g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); 209 210 /* The counter should not be running after reset. */ 211 clock_step(1000 * tick + 1); 212 g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); 213 g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); 214 215 qtest_end(); 216 } 217 218 /* 219 * Tests inten works as the counter enable based on this description: 220 * 221 * Enable the interrupt event, WDOGINT. Set HIGH to enable the counter and the 222 * interrupt, or LOW to disable the counter and interrupt. Reloads the counter 223 * from the value in WDOGLOAD when the interrupt is enabled, after previously 224 * being disabled. 225 */ 226 static void test_watchdog_inten(const void *ptr) 227 { 228 const CMSDKAPBWatchdogTestArgs *args = ptr; 229 hwaddr wdog_base = args->wdog_base; 230 int64_t tick = args->tick; 231 g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine); 232 qtest_start(cmdline); 233 g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); 234 235 g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); 236 g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); 237 238 /* 239 * When WDOGLOAD is written to, the count is immediately restarted from the 240 * new value. 241 * 242 * Note: the counter should not be running as long as WDOGCONTROL.INTEN is 243 * not set 244 */ 245 writel(wdog_base + WDOGLOAD, 4000); 246 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); 247 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000); 248 clock_step(500 * tick + 1); 249 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); 250 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000); 251 252 /* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */ 253 writel(wdog_base + WDOGCONTROL, 1); 254 clock_step(500 * tick + 1); 255 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); 256 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500); 257 258 /* or LOW to disable the counter and interrupt. */ 259 writel(wdog_base + WDOGCONTROL, 0); 260 clock_step(100 * tick); 261 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); 262 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500); 263 264 /* 265 * Reloads the counter from the value in WDOGLOAD when the interrupt is 266 * enabled, after previously being disabled. 267 */ 268 writel(wdog_base + WDOGCONTROL, 1); 269 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); 270 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000); 271 272 /* Test counter is still on */ 273 clock_step(50 * tick + 1); 274 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); 275 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3950); 276 277 /* 278 * When WDOGLOAD is written to, the count is immediately restarted from the 279 * new value. 280 * 281 * Note: the counter should be running since WDOGCONTROL.INTEN is set 282 */ 283 writel(wdog_base + WDOGLOAD, 5000); 284 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000); 285 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 5000); 286 clock_step(4999 * tick + 1); 287 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000); 288 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1); 289 g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); 290 291 /* Finally disable and check the conditions don't change */ 292 writel(wdog_base + WDOGCONTROL, 0); 293 clock_step(10 * tick); 294 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000); 295 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1); 296 g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); 297 298 qtest_end(); 299 } 300 301 /* 302 * Tests the following custom behavior: 303 * 304 * The Luminary version of this device ignores writes to this register after the 305 * guest has enabled interrupts (so they can only be disabled again via reset). 306 */ 307 static void test_watchdog_inten_luminary(const void *ptr) 308 { 309 const CMSDKAPBWatchdogTestArgs *args = ptr; 310 hwaddr wdog_base = args->wdog_base; 311 int64_t tick = args->tick; 312 g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine); 313 qtest_start(cmdline); 314 g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0); 315 316 g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); 317 g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); 318 319 /* 320 * When WDOGLOAD is written to, the count is immediately restarted from the 321 * new value. 322 * 323 * Note: the counter should not be running as long as WDOGCONTROL.INTEN is 324 * not set 325 */ 326 writel(wdog_base + WDOGLOAD, 4000); 327 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); 328 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000); 329 clock_step(500 * tick + 1); 330 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); 331 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000); 332 333 /* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */ 334 writel(wdog_base + WDOGCONTROL, 1); 335 clock_step(500 * tick + 1); 336 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); 337 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500); 338 339 /* 340 * The Luminary version of this device ignores writes to this register after 341 * the guest has enabled interrupts 342 */ 343 writel(wdog_base + WDOGCONTROL, 0); 344 clock_step(100 * tick); 345 g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000); 346 g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3400); 347 g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0x1); 348 349 /* They can only be disabled again via reset */ 350 system_reset(global_qtest); 351 352 /* Check defaults after reset */ 353 g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); 354 g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); 355 g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0); 356 357 /* The counter should not be running after reset. */ 358 clock_step(1000 * tick + 1); 359 g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT); 360 g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT); 361 362 qtest_end(); 363 } 364 365 int main(int argc, char **argv) 366 { 367 int r; 368 369 g_test_init(&argc, &argv, NULL); 370 g_test_set_nonfatal_assertions(); 371 372 if (qtest_has_machine(machine_info[MACHINE_LM3S811EVB].machine)) { 373 qtest_add_data_func("/cmsdk-apb-watchdog/watchdog", 374 &machine_info[MACHINE_LM3S811EVB], test_watchdog); 375 qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_clock_change", 376 &machine_info[MACHINE_LM3S811EVB], 377 test_clock_change); 378 qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_reset", 379 &machine_info[MACHINE_LM3S811EVB], 380 test_watchdog_reset); 381 qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_inten_luminary", 382 &machine_info[MACHINE_LM3S811EVB], 383 test_watchdog_inten_luminary); 384 } 385 if (qtest_has_machine(machine_info[MACHINE_MPS2_AN385].machine)) { 386 qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_mps2", 387 &machine_info[MACHINE_MPS2_AN385], test_watchdog); 388 qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_reset_mps2", 389 &machine_info[MACHINE_MPS2_AN385], 390 test_watchdog_reset); 391 qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_inten", 392 &machine_info[MACHINE_MPS2_AN385], 393 test_watchdog_inten); 394 } 395 396 r = g_test_run(); 397 398 return r; 399 } 400