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