qemu/tests/qtest/npcm7xx_timer-test.c
<<
>>
Prefs
   1/*
   2 * QTest testcase for the Nuvoton NPCM7xx Timer
   3 *
   4 * Copyright 2020 Google LLC
   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 "qemu/timer.h"
  19#include "libqtest-single.h"
  20
  21#define TIM_REF_HZ      (25000000)
  22
  23/* Bits in TCSRx */
  24#define CEN             BIT(30)
  25#define IE              BIT(29)
  26#define MODE_ONESHOT    (0 << 27)
  27#define MODE_PERIODIC   (1 << 27)
  28#define CRST            BIT(26)
  29#define CACT            BIT(25)
  30#define PRESCALE(x)     (x)
  31
  32/* Registers shared between all timers in a module. */
  33#define TISR    0x18
  34#define WTCR    0x1c
  35# define WTCLK(x)       ((x) << 10)
  36
  37/* Power-on default; used to re-initialize timers before each test. */
  38#define TCSR_DEFAULT    PRESCALE(5)
  39
  40/* Register offsets for a timer within a timer block. */
  41typedef struct Timer {
  42    unsigned int tcsr_offset;
  43    unsigned int ticr_offset;
  44    unsigned int tdr_offset;
  45} Timer;
  46
  47/* A timer block containing 5 timers. */
  48typedef struct TimerBlock {
  49    int irq_base;
  50    uint64_t base_addr;
  51} TimerBlock;
  52
  53/* Testdata for testing a particular timer within a timer block. */
  54typedef struct TestData {
  55    const TimerBlock *tim;
  56    const Timer *timer;
  57} TestData;
  58
  59const TimerBlock timer_block[] = {
  60    {
  61        .irq_base   = 32,
  62        .base_addr  = 0xf0008000,
  63    },
  64    {
  65        .irq_base   = 37,
  66        .base_addr  = 0xf0009000,
  67    },
  68    {
  69        .irq_base   = 42,
  70        .base_addr  = 0xf000a000,
  71    },
  72};
  73
  74const Timer timer[] = {
  75    {
  76        .tcsr_offset    = 0x00,
  77        .ticr_offset    = 0x08,
  78        .tdr_offset     = 0x10,
  79    }, {
  80        .tcsr_offset    = 0x04,
  81        .ticr_offset    = 0x0c,
  82        .tdr_offset     = 0x14,
  83    }, {
  84        .tcsr_offset    = 0x20,
  85        .ticr_offset    = 0x28,
  86        .tdr_offset     = 0x30,
  87    }, {
  88        .tcsr_offset    = 0x24,
  89        .ticr_offset    = 0x2c,
  90        .tdr_offset     = 0x34,
  91    }, {
  92        .tcsr_offset    = 0x40,
  93        .ticr_offset    = 0x48,
  94        .tdr_offset     = 0x50,
  95    },
  96};
  97
  98/* Returns the index of the timer block. */
  99static int tim_index(const TimerBlock *tim)
 100{
 101    ptrdiff_t diff = tim - timer_block;
 102
 103    g_assert(diff >= 0 && diff < ARRAY_SIZE(timer_block));
 104
 105    return diff;
 106}
 107
 108/* Returns the index of a timer within a timer block. */
 109static int timer_index(const Timer *t)
 110{
 111    ptrdiff_t diff = t - timer;
 112
 113    g_assert(diff >= 0 && diff < ARRAY_SIZE(timer));
 114
 115    return diff;
 116}
 117
 118/* Returns the irq line for a given timer. */
 119static int tim_timer_irq(const TestData *td)
 120{
 121    return td->tim->irq_base + timer_index(td->timer);
 122}
 123
 124/* Register read/write accessors. */
 125
 126static void tim_write(const TestData *td,
 127                      unsigned int offset, uint32_t value)
 128{
 129    writel(td->tim->base_addr + offset, value);
 130}
 131
 132static uint32_t tim_read(const TestData *td, unsigned int offset)
 133{
 134    return readl(td->tim->base_addr + offset);
 135}
 136
 137static void tim_write_tcsr(const TestData *td, uint32_t value)
 138{
 139    tim_write(td, td->timer->tcsr_offset, value);
 140}
 141
 142static uint32_t tim_read_tcsr(const TestData *td)
 143{
 144    return tim_read(td, td->timer->tcsr_offset);
 145}
 146
 147static void tim_write_ticr(const TestData *td, uint32_t value)
 148{
 149    tim_write(td, td->timer->ticr_offset, value);
 150}
 151
 152static uint32_t tim_read_ticr(const TestData *td)
 153{
 154    return tim_read(td, td->timer->ticr_offset);
 155}
 156
 157static uint32_t tim_read_tdr(const TestData *td)
 158{
 159    return tim_read(td, td->timer->tdr_offset);
 160}
 161
 162/* Returns the number of nanoseconds to count the given number of cycles. */
 163static int64_t tim_calculate_step(uint32_t count, uint32_t prescale)
 164{
 165    return (1000000000LL / TIM_REF_HZ) * count * (prescale + 1);
 166}
 167
 168/* Returns a bitmask corresponding to the timer under test. */
 169static uint32_t tim_timer_bit(const TestData *td)
 170{
 171    return BIT(timer_index(td->timer));
 172}
 173
 174/* Resets all timers to power-on defaults. */
 175static void tim_reset(const TestData *td)
 176{
 177    int i, j;
 178
 179    /* Reset all the timers, in case a previous test left a timer running. */
 180    for (i = 0; i < ARRAY_SIZE(timer_block); i++) {
 181        for (j = 0; j < ARRAY_SIZE(timer); j++) {
 182            writel(timer_block[i].base_addr + timer[j].tcsr_offset,
 183                   CRST | TCSR_DEFAULT);
 184        }
 185        writel(timer_block[i].base_addr + TISR, -1);
 186    }
 187}
 188
 189/* Verifies the reset state of a timer. */
 190static void test_reset(gconstpointer test_data)
 191{
 192    const TestData *td = test_data;
 193
 194    tim_reset(td);
 195
 196    g_assert_cmphex(tim_read_tcsr(td), ==, TCSR_DEFAULT);
 197    g_assert_cmphex(tim_read_ticr(td), ==, 0);
 198    g_assert_cmphex(tim_read_tdr(td), ==, 0);
 199    g_assert_cmphex(tim_read(td, TISR), ==, 0);
 200    g_assert_cmphex(tim_read(td, WTCR), ==, WTCLK(1));
 201}
 202
 203/* Verifies that CRST wins if both CEN and CRST are set. */
 204static void test_reset_overrides_enable(gconstpointer test_data)
 205{
 206    const TestData *td = test_data;
 207
 208    tim_reset(td);
 209
 210    /* CRST should force CEN to 0 */
 211    tim_write_tcsr(td, CEN | CRST | TCSR_DEFAULT);
 212
 213    g_assert_cmphex(tim_read_tcsr(td), ==, TCSR_DEFAULT);
 214    g_assert_cmphex(tim_read_tdr(td), ==, 0);
 215    g_assert_cmphex(tim_read(td, TISR), ==, 0);
 216}
 217
 218/* Verifies the behavior when CEN is set and then cleared. */
 219static void test_oneshot_enable_then_disable(gconstpointer test_data)
 220{
 221    const TestData *td = test_data;
 222
 223    tim_reset(td);
 224
 225    /* Enable the timer with zero initial count, then disable it again. */
 226    tim_write_tcsr(td, CEN | TCSR_DEFAULT);
 227    tim_write_tcsr(td, TCSR_DEFAULT);
 228
 229    g_assert_cmphex(tim_read_tcsr(td), ==, TCSR_DEFAULT);
 230    g_assert_cmphex(tim_read_tdr(td), ==, 0);
 231    /* Timer interrupt flag should be set, but interrupts are not enabled. */
 232    g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
 233    g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 234}
 235
 236/* Verifies that a one-shot timer fires when expected with prescaler 5. */
 237static void test_oneshot_ps5(gconstpointer test_data)
 238{
 239    const TestData *td = test_data;
 240    unsigned int count = 256;
 241    unsigned int ps = 5;
 242
 243    tim_reset(td);
 244
 245    tim_write_ticr(td, count);
 246    tim_write_tcsr(td, CEN | PRESCALE(ps));
 247    g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
 248    g_assert_cmpuint(tim_read_tdr(td), ==, count);
 249
 250    clock_step(tim_calculate_step(count, ps) - 1);
 251
 252    g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
 253    g_assert_cmpuint(tim_read_tdr(td), <, count);
 254    g_assert_cmphex(tim_read(td, TISR), ==, 0);
 255
 256    clock_step(1);
 257
 258    g_assert_cmphex(tim_read_tcsr(td), ==, PRESCALE(ps));
 259    g_assert_cmpuint(tim_read_tdr(td), ==, count);
 260    g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
 261    g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 262
 263    /* Clear the interrupt flag. */
 264    tim_write(td, TISR, tim_timer_bit(td));
 265    g_assert_cmphex(tim_read(td, TISR), ==, 0);
 266    g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 267
 268    /* Verify that this isn't a periodic timer. */
 269    clock_step(2 * tim_calculate_step(count, ps));
 270    g_assert_cmphex(tim_read(td, TISR), ==, 0);
 271    g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 272}
 273
 274/* Verifies that a one-shot timer fires when expected with prescaler 0. */
 275static void test_oneshot_ps0(gconstpointer test_data)
 276{
 277    const TestData *td = test_data;
 278    unsigned int count = 1;
 279    unsigned int ps = 0;
 280
 281    tim_reset(td);
 282
 283    tim_write_ticr(td, count);
 284    tim_write_tcsr(td, CEN | PRESCALE(ps));
 285    g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
 286    g_assert_cmpuint(tim_read_tdr(td), ==, count);
 287
 288    clock_step(tim_calculate_step(count, ps) - 1);
 289
 290    g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
 291    g_assert_cmpuint(tim_read_tdr(td), <, count);
 292    g_assert_cmphex(tim_read(td, TISR), ==, 0);
 293
 294    clock_step(1);
 295
 296    g_assert_cmphex(tim_read_tcsr(td), ==, PRESCALE(ps));
 297    g_assert_cmpuint(tim_read_tdr(td), ==, count);
 298    g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
 299    g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 300}
 301
 302/* Verifies that a one-shot timer fires when expected with highest prescaler. */
 303static void test_oneshot_ps255(gconstpointer test_data)
 304{
 305    const TestData *td = test_data;
 306    unsigned int count = (1U << 24) - 1;
 307    unsigned int ps = 255;
 308
 309    tim_reset(td);
 310
 311    tim_write_ticr(td, count);
 312    tim_write_tcsr(td, CEN | PRESCALE(ps));
 313    g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
 314    g_assert_cmpuint(tim_read_tdr(td), ==, count);
 315
 316    clock_step(tim_calculate_step(count, ps) - 1);
 317
 318    g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
 319    g_assert_cmpuint(tim_read_tdr(td), <, count);
 320    g_assert_cmphex(tim_read(td, TISR), ==, 0);
 321
 322    clock_step(1);
 323
 324    g_assert_cmphex(tim_read_tcsr(td), ==, PRESCALE(ps));
 325    g_assert_cmpuint(tim_read_tdr(td), ==, count);
 326    g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
 327    g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 328}
 329
 330/* Verifies that a oneshot timer fires an interrupt when expected. */
 331static void test_oneshot_interrupt(gconstpointer test_data)
 332{
 333    const TestData *td = test_data;
 334    unsigned int count = 256;
 335    unsigned int ps = 7;
 336
 337    tim_reset(td);
 338
 339    tim_write_ticr(td, count);
 340    tim_write_tcsr(td, IE | CEN | MODE_ONESHOT | PRESCALE(ps));
 341
 342    clock_step_next();
 343
 344    g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
 345    g_assert_true(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 346}
 347
 348/*
 349 * Verifies that the timer can be paused and later resumed, and it still fires
 350 * at the right moment.
 351 */
 352static void test_pause_resume(gconstpointer test_data)
 353{
 354    const TestData *td = test_data;
 355    unsigned int count = 256;
 356    unsigned int ps = 1;
 357
 358    tim_reset(td);
 359
 360    tim_write_ticr(td, count);
 361    tim_write_tcsr(td, IE | CEN | MODE_ONESHOT | PRESCALE(ps));
 362
 363    /* Pause the timer halfway to expiration. */
 364    clock_step(tim_calculate_step(count / 2, ps));
 365    tim_write_tcsr(td, IE | MODE_ONESHOT | PRESCALE(ps));
 366    g_assert_cmpuint(tim_read_tdr(td), ==, count / 2);
 367
 368    /* Counter should not advance during the following step. */
 369    clock_step(2 * tim_calculate_step(count, ps));
 370    g_assert_cmpuint(tim_read_tdr(td), ==, count / 2);
 371    g_assert_cmphex(tim_read(td, TISR), ==, 0);
 372    g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 373
 374    /* Resume the timer and run _almost_ to expiration. */
 375    tim_write_tcsr(td, IE | CEN | MODE_ONESHOT | PRESCALE(ps));
 376    clock_step(tim_calculate_step(count / 2, ps) - 1);
 377    g_assert_cmpuint(tim_read_tdr(td), <, count);
 378    g_assert_cmphex(tim_read(td, TISR), ==, 0);
 379    g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 380
 381    /* Now, run the rest of the way and verify that the interrupt fires. */
 382    clock_step(1);
 383    g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
 384    g_assert_true(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 385}
 386
 387/* Verifies that the prescaler can be changed while the timer is runnin. */
 388static void test_prescaler_change(gconstpointer test_data)
 389{
 390    const TestData *td = test_data;
 391    unsigned int count = 256;
 392    unsigned int ps = 5;
 393
 394    tim_reset(td);
 395
 396    tim_write_ticr(td, count);
 397    tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
 398
 399    /* Run a quarter of the way, and change the prescaler. */
 400    clock_step(tim_calculate_step(count / 4, ps));
 401    g_assert_cmpuint(tim_read_tdr(td), ==, 3 * count / 4);
 402    ps = 2;
 403    tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
 404    /* The counter must not change. */
 405    g_assert_cmpuint(tim_read_tdr(td), ==, 3 * count / 4);
 406
 407    /* Run another quarter of the way, and change the prescaler again. */
 408    clock_step(tim_calculate_step(count / 4, ps));
 409    g_assert_cmpuint(tim_read_tdr(td), ==, count / 2);
 410    ps = 8;
 411    tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
 412    /* The counter must not change. */
 413    g_assert_cmpuint(tim_read_tdr(td), ==, count / 2);
 414
 415    /* Run another quarter of the way, and change the prescaler again. */
 416    clock_step(tim_calculate_step(count / 4, ps));
 417    g_assert_cmpuint(tim_read_tdr(td), ==, count / 4);
 418    ps = 0;
 419    tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
 420    /* The counter must not change. */
 421    g_assert_cmpuint(tim_read_tdr(td), ==, count / 4);
 422
 423    /* Run almost to expiration, and verify the timer didn't fire yet. */
 424    clock_step(tim_calculate_step(count / 4, ps) - 1);
 425    g_assert_cmpuint(tim_read_tdr(td), <, count);
 426    g_assert_cmphex(tim_read(td, TISR), ==, 0);
 427
 428    /* Now, run the rest of the way and verify that the timer fires. */
 429    clock_step(1);
 430    g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
 431}
 432
 433/* Verifies that a periodic timer automatically restarts after expiration. */
 434static void test_periodic_no_interrupt(gconstpointer test_data)
 435{
 436    const TestData *td = test_data;
 437    unsigned int count = 2;
 438    unsigned int ps = 3;
 439    int i;
 440
 441    tim_reset(td);
 442
 443    tim_write_ticr(td, count);
 444    tim_write_tcsr(td, CEN | MODE_PERIODIC | PRESCALE(ps));
 445
 446    for (i = 0; i < 4; i++) {
 447        clock_step_next();
 448
 449        g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
 450        g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 451
 452        tim_write(td, TISR, tim_timer_bit(td));
 453
 454        g_assert_cmphex(tim_read(td, TISR), ==, 0);
 455        g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 456    }
 457}
 458
 459/* Verifies that a periodict timer fires an interrupt every time it expires. */
 460static void test_periodic_interrupt(gconstpointer test_data)
 461{
 462    const TestData *td = test_data;
 463    unsigned int count = 65535;
 464    unsigned int ps = 2;
 465    int i;
 466
 467    tim_reset(td);
 468
 469    tim_write_ticr(td, count);
 470    tim_write_tcsr(td, CEN | IE | MODE_PERIODIC | PRESCALE(ps));
 471
 472    for (i = 0; i < 4; i++) {
 473        clock_step_next();
 474
 475        g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
 476        g_assert_true(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 477
 478        tim_write(td, TISR, tim_timer_bit(td));
 479
 480        g_assert_cmphex(tim_read(td, TISR), ==, 0);
 481        g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
 482    }
 483}
 484
 485/*
 486 * Verifies that the timer behaves correctly when disabled right before and
 487 * exactly when it's supposed to expire.
 488 */
 489static void test_disable_on_expiration(gconstpointer test_data)
 490{
 491    const TestData *td = test_data;
 492    unsigned int count = 8;
 493    unsigned int ps = 255;
 494
 495    tim_reset(td);
 496
 497    tim_write_ticr(td, count);
 498    tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
 499
 500    clock_step(tim_calculate_step(count, ps) - 1);
 501
 502    tim_write_tcsr(td, MODE_ONESHOT | PRESCALE(ps));
 503    tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
 504    clock_step(1);
 505    tim_write_tcsr(td, MODE_ONESHOT | PRESCALE(ps));
 506    g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
 507}
 508
 509/*
 510 * Constructs a name that includes the timer block, timer and testcase name,
 511 * and adds the test to the test suite.
 512 */
 513static void tim_add_test(const char *name, const TestData *td, GTestDataFunc fn)
 514{
 515    g_autofree char *full_name = g_strdup_printf(
 516        "npcm7xx_timer/tim[%d]/timer[%d]/%s", tim_index(td->tim),
 517        timer_index(td->timer), name);
 518    qtest_add_data_func(full_name, td, fn);
 519}
 520
 521/* Convenience macro for adding a test with a predictable function name. */
 522#define add_test(name, td) tim_add_test(#name, td, test_##name)
 523
 524int main(int argc, char **argv)
 525{
 526    TestData testdata[ARRAY_SIZE(timer_block) * ARRAY_SIZE(timer)];
 527    int ret;
 528    int i, j;
 529
 530    g_test_init(&argc, &argv, NULL);
 531    g_test_set_nonfatal_assertions();
 532
 533    for (i = 0; i < ARRAY_SIZE(timer_block); i++) {
 534        for (j = 0; j < ARRAY_SIZE(timer); j++) {
 535            TestData *td = &testdata[i * ARRAY_SIZE(timer) + j];
 536            td->tim = &timer_block[i];
 537            td->timer = &timer[j];
 538
 539            add_test(reset, td);
 540            add_test(reset_overrides_enable, td);
 541            add_test(oneshot_enable_then_disable, td);
 542            add_test(oneshot_ps5, td);
 543            add_test(oneshot_ps0, td);
 544            add_test(oneshot_ps255, td);
 545            add_test(oneshot_interrupt, td);
 546            add_test(pause_resume, td);
 547            add_test(prescaler_change, td);
 548            add_test(periodic_no_interrupt, td);
 549            add_test(periodic_interrupt, td);
 550            add_test(disable_on_expiration, td);
 551        }
 552    }
 553
 554    qtest_start("-machine npcm750-evb");
 555    qtest_irq_intercept_in(global_qtest, "/machine/soc/a9mpcore/gic");
 556    ret = g_test_run();
 557    qtest_end();
 558
 559    return ret;
 560}
 561