119d50149SHavard Skinnemoen /* 219d50149SHavard Skinnemoen * QTest testcase for the Nuvoton NPCM7xx Timer 319d50149SHavard Skinnemoen * 419d50149SHavard Skinnemoen * Copyright 2020 Google LLC 519d50149SHavard Skinnemoen * 619d50149SHavard Skinnemoen * This program is free software; you can redistribute it and/or modify it 719d50149SHavard Skinnemoen * under the terms of the GNU General Public License as published by the 819d50149SHavard Skinnemoen * Free Software Foundation; either version 2 of the License, or 919d50149SHavard Skinnemoen * (at your option) any later version. 1019d50149SHavard Skinnemoen * 1119d50149SHavard Skinnemoen * This program is distributed in the hope that it will be useful, but WITHOUT 1219d50149SHavard Skinnemoen * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1319d50149SHavard Skinnemoen * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1419d50149SHavard Skinnemoen * for more details. 1519d50149SHavard Skinnemoen */ 1619d50149SHavard Skinnemoen 1719d50149SHavard Skinnemoen #include "qemu/osdep.h" 1819d50149SHavard Skinnemoen #include "qemu/timer.h" 1919d50149SHavard Skinnemoen #include "libqtest-single.h" 2019d50149SHavard Skinnemoen 2119d50149SHavard Skinnemoen #define TIM_REF_HZ (25000000) 2219d50149SHavard Skinnemoen 2319d50149SHavard Skinnemoen /* Bits in TCSRx */ 2419d50149SHavard Skinnemoen #define CEN BIT(30) 2519d50149SHavard Skinnemoen #define IE BIT(29) 2619d50149SHavard Skinnemoen #define MODE_ONESHOT (0 << 27) 2719d50149SHavard Skinnemoen #define MODE_PERIODIC (1 << 27) 2819d50149SHavard Skinnemoen #define CRST BIT(26) 2919d50149SHavard Skinnemoen #define CACT BIT(25) 3019d50149SHavard Skinnemoen #define PRESCALE(x) (x) 3119d50149SHavard Skinnemoen 3219d50149SHavard Skinnemoen /* Registers shared between all timers in a module. */ 3319d50149SHavard Skinnemoen #define TISR 0x18 3419d50149SHavard Skinnemoen #define WTCR 0x1c 3519d50149SHavard Skinnemoen # define WTCLK(x) ((x) << 10) 3619d50149SHavard Skinnemoen 3719d50149SHavard Skinnemoen /* Power-on default; used to re-initialize timers before each test. */ 3819d50149SHavard Skinnemoen #define TCSR_DEFAULT PRESCALE(5) 3919d50149SHavard Skinnemoen 4019d50149SHavard Skinnemoen /* Register offsets for a timer within a timer block. */ 4119d50149SHavard Skinnemoen typedef struct Timer { 4219d50149SHavard Skinnemoen unsigned int tcsr_offset; 4319d50149SHavard Skinnemoen unsigned int ticr_offset; 4419d50149SHavard Skinnemoen unsigned int tdr_offset; 4519d50149SHavard Skinnemoen } Timer; 4619d50149SHavard Skinnemoen 4719d50149SHavard Skinnemoen /* A timer block containing 5 timers. */ 4819d50149SHavard Skinnemoen typedef struct TimerBlock { 4919d50149SHavard Skinnemoen int irq_base; 5019d50149SHavard Skinnemoen uint64_t base_addr; 5119d50149SHavard Skinnemoen } TimerBlock; 5219d50149SHavard Skinnemoen 5319d50149SHavard Skinnemoen /* Testdata for testing a particular timer within a timer block. */ 5419d50149SHavard Skinnemoen typedef struct TestData { 5519d50149SHavard Skinnemoen const TimerBlock *tim; 5619d50149SHavard Skinnemoen const Timer *timer; 5719d50149SHavard Skinnemoen } TestData; 5819d50149SHavard Skinnemoen 5919d50149SHavard Skinnemoen const TimerBlock timer_block[] = { 6019d50149SHavard Skinnemoen { 6119d50149SHavard Skinnemoen .irq_base = 32, 6219d50149SHavard Skinnemoen .base_addr = 0xf0008000, 6319d50149SHavard Skinnemoen }, 6419d50149SHavard Skinnemoen { 6519d50149SHavard Skinnemoen .irq_base = 37, 6619d50149SHavard Skinnemoen .base_addr = 0xf0009000, 6719d50149SHavard Skinnemoen }, 6819d50149SHavard Skinnemoen { 6919d50149SHavard Skinnemoen .irq_base = 42, 7019d50149SHavard Skinnemoen .base_addr = 0xf000a000, 7119d50149SHavard Skinnemoen }, 7219d50149SHavard Skinnemoen }; 7319d50149SHavard Skinnemoen 7419d50149SHavard Skinnemoen const Timer timer[] = { 7519d50149SHavard Skinnemoen { 7619d50149SHavard Skinnemoen .tcsr_offset = 0x00, 7719d50149SHavard Skinnemoen .ticr_offset = 0x08, 7819d50149SHavard Skinnemoen .tdr_offset = 0x10, 7919d50149SHavard Skinnemoen }, { 8019d50149SHavard Skinnemoen .tcsr_offset = 0x04, 8119d50149SHavard Skinnemoen .ticr_offset = 0x0c, 8219d50149SHavard Skinnemoen .tdr_offset = 0x14, 8319d50149SHavard Skinnemoen }, { 8419d50149SHavard Skinnemoen .tcsr_offset = 0x20, 8519d50149SHavard Skinnemoen .ticr_offset = 0x28, 8619d50149SHavard Skinnemoen .tdr_offset = 0x30, 8719d50149SHavard Skinnemoen }, { 8819d50149SHavard Skinnemoen .tcsr_offset = 0x24, 8919d50149SHavard Skinnemoen .ticr_offset = 0x2c, 9019d50149SHavard Skinnemoen .tdr_offset = 0x34, 9119d50149SHavard Skinnemoen }, { 9219d50149SHavard Skinnemoen .tcsr_offset = 0x40, 9319d50149SHavard Skinnemoen .ticr_offset = 0x48, 9419d50149SHavard Skinnemoen .tdr_offset = 0x50, 9519d50149SHavard Skinnemoen }, 9619d50149SHavard Skinnemoen }; 9719d50149SHavard Skinnemoen 9819d50149SHavard Skinnemoen /* Returns the index of the timer block. */ 9919d50149SHavard Skinnemoen static int tim_index(const TimerBlock *tim) 10019d50149SHavard Skinnemoen { 10119d50149SHavard Skinnemoen ptrdiff_t diff = tim - timer_block; 10219d50149SHavard Skinnemoen 10319d50149SHavard Skinnemoen g_assert(diff >= 0 && diff < ARRAY_SIZE(timer_block)); 10419d50149SHavard Skinnemoen 10519d50149SHavard Skinnemoen return diff; 10619d50149SHavard Skinnemoen } 10719d50149SHavard Skinnemoen 10819d50149SHavard Skinnemoen /* Returns the index of a timer within a timer block. */ 10919d50149SHavard Skinnemoen static int timer_index(const Timer *t) 11019d50149SHavard Skinnemoen { 11119d50149SHavard Skinnemoen ptrdiff_t diff = t - timer; 11219d50149SHavard Skinnemoen 11319d50149SHavard Skinnemoen g_assert(diff >= 0 && diff < ARRAY_SIZE(timer)); 11419d50149SHavard Skinnemoen 11519d50149SHavard Skinnemoen return diff; 11619d50149SHavard Skinnemoen } 11719d50149SHavard Skinnemoen 11819d50149SHavard Skinnemoen /* Returns the irq line for a given timer. */ 11919d50149SHavard Skinnemoen static int tim_timer_irq(const TestData *td) 12019d50149SHavard Skinnemoen { 12119d50149SHavard Skinnemoen return td->tim->irq_base + timer_index(td->timer); 12219d50149SHavard Skinnemoen } 12319d50149SHavard Skinnemoen 12419d50149SHavard Skinnemoen /* Register read/write accessors. */ 12519d50149SHavard Skinnemoen 12619d50149SHavard Skinnemoen static void tim_write(const TestData *td, 12719d50149SHavard Skinnemoen unsigned int offset, uint32_t value) 12819d50149SHavard Skinnemoen { 12919d50149SHavard Skinnemoen writel(td->tim->base_addr + offset, value); 13019d50149SHavard Skinnemoen } 13119d50149SHavard Skinnemoen 13219d50149SHavard Skinnemoen static uint32_t tim_read(const TestData *td, unsigned int offset) 13319d50149SHavard Skinnemoen { 13419d50149SHavard Skinnemoen return readl(td->tim->base_addr + offset); 13519d50149SHavard Skinnemoen } 13619d50149SHavard Skinnemoen 13719d50149SHavard Skinnemoen static void tim_write_tcsr(const TestData *td, uint32_t value) 13819d50149SHavard Skinnemoen { 13919d50149SHavard Skinnemoen tim_write(td, td->timer->tcsr_offset, value); 14019d50149SHavard Skinnemoen } 14119d50149SHavard Skinnemoen 14219d50149SHavard Skinnemoen static uint32_t tim_read_tcsr(const TestData *td) 14319d50149SHavard Skinnemoen { 14419d50149SHavard Skinnemoen return tim_read(td, td->timer->tcsr_offset); 14519d50149SHavard Skinnemoen } 14619d50149SHavard Skinnemoen 14719d50149SHavard Skinnemoen static void tim_write_ticr(const TestData *td, uint32_t value) 14819d50149SHavard Skinnemoen { 14919d50149SHavard Skinnemoen tim_write(td, td->timer->ticr_offset, value); 15019d50149SHavard Skinnemoen } 15119d50149SHavard Skinnemoen 15219d50149SHavard Skinnemoen static uint32_t tim_read_ticr(const TestData *td) 15319d50149SHavard Skinnemoen { 15419d50149SHavard Skinnemoen return tim_read(td, td->timer->ticr_offset); 15519d50149SHavard Skinnemoen } 15619d50149SHavard Skinnemoen 15719d50149SHavard Skinnemoen static uint32_t tim_read_tdr(const TestData *td) 15819d50149SHavard Skinnemoen { 15919d50149SHavard Skinnemoen return tim_read(td, td->timer->tdr_offset); 16019d50149SHavard Skinnemoen } 16119d50149SHavard Skinnemoen 16219d50149SHavard Skinnemoen /* Returns the number of nanoseconds to count the given number of cycles. */ 16319d50149SHavard Skinnemoen static int64_t tim_calculate_step(uint32_t count, uint32_t prescale) 16419d50149SHavard Skinnemoen { 16519d50149SHavard Skinnemoen return (1000000000LL / TIM_REF_HZ) * count * (prescale + 1); 16619d50149SHavard Skinnemoen } 16719d50149SHavard Skinnemoen 16819d50149SHavard Skinnemoen /* Returns a bitmask corresponding to the timer under test. */ 16919d50149SHavard Skinnemoen static uint32_t tim_timer_bit(const TestData *td) 17019d50149SHavard Skinnemoen { 17119d50149SHavard Skinnemoen return BIT(timer_index(td->timer)); 17219d50149SHavard Skinnemoen } 17319d50149SHavard Skinnemoen 17419d50149SHavard Skinnemoen /* Resets all timers to power-on defaults. */ 17519d50149SHavard Skinnemoen static void tim_reset(const TestData *td) 17619d50149SHavard Skinnemoen { 17719d50149SHavard Skinnemoen int i, j; 17819d50149SHavard Skinnemoen 17919d50149SHavard Skinnemoen /* Reset all the timers, in case a previous test left a timer running. */ 18019d50149SHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(timer_block); i++) { 18119d50149SHavard Skinnemoen for (j = 0; j < ARRAY_SIZE(timer); j++) { 18219d50149SHavard Skinnemoen writel(timer_block[i].base_addr + timer[j].tcsr_offset, 18319d50149SHavard Skinnemoen CRST | TCSR_DEFAULT); 18419d50149SHavard Skinnemoen } 18519d50149SHavard Skinnemoen writel(timer_block[i].base_addr + TISR, -1); 18619d50149SHavard Skinnemoen } 18719d50149SHavard Skinnemoen } 18819d50149SHavard Skinnemoen 18919d50149SHavard Skinnemoen /* Verifies the reset state of a timer. */ 19019d50149SHavard Skinnemoen static void test_reset(gconstpointer test_data) 19119d50149SHavard Skinnemoen { 19219d50149SHavard Skinnemoen const TestData *td = test_data; 19319d50149SHavard Skinnemoen 19419d50149SHavard Skinnemoen tim_reset(td); 19519d50149SHavard Skinnemoen 19619d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, TCSR_DEFAULT); 19719d50149SHavard Skinnemoen g_assert_cmphex(tim_read_ticr(td), ==, 0); 19819d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tdr(td), ==, 0); 19919d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 20019d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, WTCR), ==, WTCLK(1)); 20119d50149SHavard Skinnemoen } 20219d50149SHavard Skinnemoen 20319d50149SHavard Skinnemoen /* Verifies that CRST wins if both CEN and CRST are set. */ 20419d50149SHavard Skinnemoen static void test_reset_overrides_enable(gconstpointer test_data) 20519d50149SHavard Skinnemoen { 20619d50149SHavard Skinnemoen const TestData *td = test_data; 20719d50149SHavard Skinnemoen 20819d50149SHavard Skinnemoen tim_reset(td); 20919d50149SHavard Skinnemoen 21019d50149SHavard Skinnemoen /* CRST should force CEN to 0 */ 21119d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | CRST | TCSR_DEFAULT); 21219d50149SHavard Skinnemoen 21319d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, TCSR_DEFAULT); 21419d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tdr(td), ==, 0); 21519d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 21619d50149SHavard Skinnemoen } 21719d50149SHavard Skinnemoen 21819d50149SHavard Skinnemoen /* Verifies the behavior when CEN is set and then cleared. */ 21919d50149SHavard Skinnemoen static void test_oneshot_enable_then_disable(gconstpointer test_data) 22019d50149SHavard Skinnemoen { 22119d50149SHavard Skinnemoen const TestData *td = test_data; 22219d50149SHavard Skinnemoen 22319d50149SHavard Skinnemoen tim_reset(td); 22419d50149SHavard Skinnemoen 22519d50149SHavard Skinnemoen /* Enable the timer with zero initial count, then disable it again. */ 22619d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | TCSR_DEFAULT); 22719d50149SHavard Skinnemoen tim_write_tcsr(td, TCSR_DEFAULT); 22819d50149SHavard Skinnemoen 22919d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, TCSR_DEFAULT); 23019d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tdr(td), ==, 0); 23119d50149SHavard Skinnemoen /* Timer interrupt flag should be set, but interrupts are not enabled. */ 23219d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td)); 23319d50149SHavard Skinnemoen g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td))); 23419d50149SHavard Skinnemoen } 23519d50149SHavard Skinnemoen 23619d50149SHavard Skinnemoen /* Verifies that a one-shot timer fires when expected with prescaler 5. */ 23719d50149SHavard Skinnemoen static void test_oneshot_ps5(gconstpointer test_data) 23819d50149SHavard Skinnemoen { 23919d50149SHavard Skinnemoen const TestData *td = test_data; 24019d50149SHavard Skinnemoen unsigned int count = 256; 24119d50149SHavard Skinnemoen unsigned int ps = 5; 24219d50149SHavard Skinnemoen 24319d50149SHavard Skinnemoen tim_reset(td); 24419d50149SHavard Skinnemoen 24519d50149SHavard Skinnemoen tim_write_ticr(td, count); 24619d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | PRESCALE(ps)); 24719d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps)); 24819d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count); 24919d50149SHavard Skinnemoen 25019d50149SHavard Skinnemoen clock_step(tim_calculate_step(count, ps) - 1); 25119d50149SHavard Skinnemoen 25219d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps)); 25319d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), <, count); 25419d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 25519d50149SHavard Skinnemoen 25619d50149SHavard Skinnemoen clock_step(1); 25719d50149SHavard Skinnemoen 25819d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, PRESCALE(ps)); 25919d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count); 26019d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td)); 26119d50149SHavard Skinnemoen g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td))); 26219d50149SHavard Skinnemoen 26319d50149SHavard Skinnemoen /* Clear the interrupt flag. */ 26419d50149SHavard Skinnemoen tim_write(td, TISR, tim_timer_bit(td)); 26519d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 26619d50149SHavard Skinnemoen g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td))); 26719d50149SHavard Skinnemoen 26819d50149SHavard Skinnemoen /* Verify that this isn't a periodic timer. */ 26919d50149SHavard Skinnemoen clock_step(2 * tim_calculate_step(count, ps)); 27019d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 27119d50149SHavard Skinnemoen g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td))); 27219d50149SHavard Skinnemoen } 27319d50149SHavard Skinnemoen 27419d50149SHavard Skinnemoen /* Verifies that a one-shot timer fires when expected with prescaler 0. */ 27519d50149SHavard Skinnemoen static void test_oneshot_ps0(gconstpointer test_data) 27619d50149SHavard Skinnemoen { 27719d50149SHavard Skinnemoen const TestData *td = test_data; 27819d50149SHavard Skinnemoen unsigned int count = 1; 27919d50149SHavard Skinnemoen unsigned int ps = 0; 28019d50149SHavard Skinnemoen 28119d50149SHavard Skinnemoen tim_reset(td); 28219d50149SHavard Skinnemoen 28319d50149SHavard Skinnemoen tim_write_ticr(td, count); 28419d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | PRESCALE(ps)); 28519d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps)); 28619d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count); 28719d50149SHavard Skinnemoen 28819d50149SHavard Skinnemoen clock_step(tim_calculate_step(count, ps) - 1); 28919d50149SHavard Skinnemoen 29019d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps)); 29119d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), <, count); 29219d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 29319d50149SHavard Skinnemoen 29419d50149SHavard Skinnemoen clock_step(1); 29519d50149SHavard Skinnemoen 29619d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, PRESCALE(ps)); 29719d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count); 29819d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td)); 29919d50149SHavard Skinnemoen g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td))); 30019d50149SHavard Skinnemoen } 30119d50149SHavard Skinnemoen 30219d50149SHavard Skinnemoen /* Verifies that a one-shot timer fires when expected with highest prescaler. */ 30319d50149SHavard Skinnemoen static void test_oneshot_ps255(gconstpointer test_data) 30419d50149SHavard Skinnemoen { 30519d50149SHavard Skinnemoen const TestData *td = test_data; 30619d50149SHavard Skinnemoen unsigned int count = (1U << 24) - 1; 30719d50149SHavard Skinnemoen unsigned int ps = 255; 30819d50149SHavard Skinnemoen 30919d50149SHavard Skinnemoen tim_reset(td); 31019d50149SHavard Skinnemoen 31119d50149SHavard Skinnemoen tim_write_ticr(td, count); 31219d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | PRESCALE(ps)); 31319d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps)); 31419d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count); 31519d50149SHavard Skinnemoen 31619d50149SHavard Skinnemoen clock_step(tim_calculate_step(count, ps) - 1); 31719d50149SHavard Skinnemoen 31819d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps)); 31919d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), <, count); 32019d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 32119d50149SHavard Skinnemoen 32219d50149SHavard Skinnemoen clock_step(1); 32319d50149SHavard Skinnemoen 32419d50149SHavard Skinnemoen g_assert_cmphex(tim_read_tcsr(td), ==, PRESCALE(ps)); 32519d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count); 32619d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td)); 32719d50149SHavard Skinnemoen g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td))); 32819d50149SHavard Skinnemoen } 32919d50149SHavard Skinnemoen 33019d50149SHavard Skinnemoen /* Verifies that a oneshot timer fires an interrupt when expected. */ 33119d50149SHavard Skinnemoen static void test_oneshot_interrupt(gconstpointer test_data) 33219d50149SHavard Skinnemoen { 33319d50149SHavard Skinnemoen const TestData *td = test_data; 33419d50149SHavard Skinnemoen unsigned int count = 256; 33519d50149SHavard Skinnemoen unsigned int ps = 7; 33619d50149SHavard Skinnemoen 33719d50149SHavard Skinnemoen tim_reset(td); 33819d50149SHavard Skinnemoen 33919d50149SHavard Skinnemoen tim_write_ticr(td, count); 34019d50149SHavard Skinnemoen tim_write_tcsr(td, IE | CEN | MODE_ONESHOT | PRESCALE(ps)); 34119d50149SHavard Skinnemoen 34219d50149SHavard Skinnemoen clock_step_next(); 34319d50149SHavard Skinnemoen 34419d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td)); 34519d50149SHavard Skinnemoen g_assert_true(qtest_get_irq(global_qtest, tim_timer_irq(td))); 34619d50149SHavard Skinnemoen } 34719d50149SHavard Skinnemoen 34819d50149SHavard Skinnemoen /* 34919d50149SHavard Skinnemoen * Verifies that the timer can be paused and later resumed, and it still fires 35019d50149SHavard Skinnemoen * at the right moment. 35119d50149SHavard Skinnemoen */ 35219d50149SHavard Skinnemoen static void test_pause_resume(gconstpointer test_data) 35319d50149SHavard Skinnemoen { 35419d50149SHavard Skinnemoen const TestData *td = test_data; 35519d50149SHavard Skinnemoen unsigned int count = 256; 35619d50149SHavard Skinnemoen unsigned int ps = 1; 35719d50149SHavard Skinnemoen 35819d50149SHavard Skinnemoen tim_reset(td); 35919d50149SHavard Skinnemoen 36019d50149SHavard Skinnemoen tim_write_ticr(td, count); 36119d50149SHavard Skinnemoen tim_write_tcsr(td, IE | CEN | MODE_ONESHOT | PRESCALE(ps)); 36219d50149SHavard Skinnemoen 36319d50149SHavard Skinnemoen /* Pause the timer halfway to expiration. */ 36419d50149SHavard Skinnemoen clock_step(tim_calculate_step(count / 2, ps)); 36519d50149SHavard Skinnemoen tim_write_tcsr(td, IE | MODE_ONESHOT | PRESCALE(ps)); 36619d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count / 2); 36719d50149SHavard Skinnemoen 36819d50149SHavard Skinnemoen /* Counter should not advance during the following step. */ 36919d50149SHavard Skinnemoen clock_step(2 * tim_calculate_step(count, ps)); 37019d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count / 2); 37119d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 37219d50149SHavard Skinnemoen g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td))); 37319d50149SHavard Skinnemoen 37419d50149SHavard Skinnemoen /* Resume the timer and run _almost_ to expiration. */ 37519d50149SHavard Skinnemoen tim_write_tcsr(td, IE | CEN | MODE_ONESHOT | PRESCALE(ps)); 37619d50149SHavard Skinnemoen clock_step(tim_calculate_step(count / 2, ps) - 1); 37719d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), <, count); 37819d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 37919d50149SHavard Skinnemoen g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td))); 38019d50149SHavard Skinnemoen 38119d50149SHavard Skinnemoen /* Now, run the rest of the way and verify that the interrupt fires. */ 38219d50149SHavard Skinnemoen clock_step(1); 38319d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td)); 38419d50149SHavard Skinnemoen g_assert_true(qtest_get_irq(global_qtest, tim_timer_irq(td))); 38519d50149SHavard Skinnemoen } 38619d50149SHavard Skinnemoen 387*96420a30SMichael Tokarev /* Verifies that the prescaler can be changed while the timer is running. */ 38819d50149SHavard Skinnemoen static void test_prescaler_change(gconstpointer test_data) 38919d50149SHavard Skinnemoen { 39019d50149SHavard Skinnemoen const TestData *td = test_data; 39119d50149SHavard Skinnemoen unsigned int count = 256; 39219d50149SHavard Skinnemoen unsigned int ps = 5; 39319d50149SHavard Skinnemoen 39419d50149SHavard Skinnemoen tim_reset(td); 39519d50149SHavard Skinnemoen 39619d50149SHavard Skinnemoen tim_write_ticr(td, count); 39719d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps)); 39819d50149SHavard Skinnemoen 39919d50149SHavard Skinnemoen /* Run a quarter of the way, and change the prescaler. */ 40019d50149SHavard Skinnemoen clock_step(tim_calculate_step(count / 4, ps)); 40119d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, 3 * count / 4); 40219d50149SHavard Skinnemoen ps = 2; 40319d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps)); 40419d50149SHavard Skinnemoen /* The counter must not change. */ 40519d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, 3 * count / 4); 40619d50149SHavard Skinnemoen 40719d50149SHavard Skinnemoen /* Run another quarter of the way, and change the prescaler again. */ 40819d50149SHavard Skinnemoen clock_step(tim_calculate_step(count / 4, ps)); 40919d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count / 2); 41019d50149SHavard Skinnemoen ps = 8; 41119d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps)); 41219d50149SHavard Skinnemoen /* The counter must not change. */ 41319d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count / 2); 41419d50149SHavard Skinnemoen 41519d50149SHavard Skinnemoen /* Run another quarter of the way, and change the prescaler again. */ 41619d50149SHavard Skinnemoen clock_step(tim_calculate_step(count / 4, ps)); 41719d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count / 4); 41819d50149SHavard Skinnemoen ps = 0; 41919d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps)); 42019d50149SHavard Skinnemoen /* The counter must not change. */ 42119d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), ==, count / 4); 42219d50149SHavard Skinnemoen 42319d50149SHavard Skinnemoen /* Run almost to expiration, and verify the timer didn't fire yet. */ 42419d50149SHavard Skinnemoen clock_step(tim_calculate_step(count / 4, ps) - 1); 42519d50149SHavard Skinnemoen g_assert_cmpuint(tim_read_tdr(td), <, count); 42619d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 42719d50149SHavard Skinnemoen 42819d50149SHavard Skinnemoen /* Now, run the rest of the way and verify that the timer fires. */ 42919d50149SHavard Skinnemoen clock_step(1); 43019d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td)); 43119d50149SHavard Skinnemoen } 43219d50149SHavard Skinnemoen 43319d50149SHavard Skinnemoen /* Verifies that a periodic timer automatically restarts after expiration. */ 43419d50149SHavard Skinnemoen static void test_periodic_no_interrupt(gconstpointer test_data) 43519d50149SHavard Skinnemoen { 43619d50149SHavard Skinnemoen const TestData *td = test_data; 43719d50149SHavard Skinnemoen unsigned int count = 2; 43819d50149SHavard Skinnemoen unsigned int ps = 3; 43919d50149SHavard Skinnemoen int i; 44019d50149SHavard Skinnemoen 44119d50149SHavard Skinnemoen tim_reset(td); 44219d50149SHavard Skinnemoen 44319d50149SHavard Skinnemoen tim_write_ticr(td, count); 44419d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | MODE_PERIODIC | PRESCALE(ps)); 44519d50149SHavard Skinnemoen 44619d50149SHavard Skinnemoen for (i = 0; i < 4; i++) { 44719d50149SHavard Skinnemoen clock_step_next(); 44819d50149SHavard Skinnemoen 44919d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td)); 45019d50149SHavard Skinnemoen g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td))); 45119d50149SHavard Skinnemoen 45219d50149SHavard Skinnemoen tim_write(td, TISR, tim_timer_bit(td)); 45319d50149SHavard Skinnemoen 45419d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 45519d50149SHavard Skinnemoen g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td))); 45619d50149SHavard Skinnemoen } 45719d50149SHavard Skinnemoen } 45819d50149SHavard Skinnemoen 45919d50149SHavard Skinnemoen /* Verifies that a periodict timer fires an interrupt every time it expires. */ 46019d50149SHavard Skinnemoen static void test_periodic_interrupt(gconstpointer test_data) 46119d50149SHavard Skinnemoen { 46219d50149SHavard Skinnemoen const TestData *td = test_data; 46319d50149SHavard Skinnemoen unsigned int count = 65535; 46419d50149SHavard Skinnemoen unsigned int ps = 2; 46519d50149SHavard Skinnemoen int i; 46619d50149SHavard Skinnemoen 46719d50149SHavard Skinnemoen tim_reset(td); 46819d50149SHavard Skinnemoen 46919d50149SHavard Skinnemoen tim_write_ticr(td, count); 47019d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | IE | MODE_PERIODIC | PRESCALE(ps)); 47119d50149SHavard Skinnemoen 47219d50149SHavard Skinnemoen for (i = 0; i < 4; i++) { 47319d50149SHavard Skinnemoen clock_step_next(); 47419d50149SHavard Skinnemoen 47519d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td)); 47619d50149SHavard Skinnemoen g_assert_true(qtest_get_irq(global_qtest, tim_timer_irq(td))); 47719d50149SHavard Skinnemoen 47819d50149SHavard Skinnemoen tim_write(td, TISR, tim_timer_bit(td)); 47919d50149SHavard Skinnemoen 48019d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, 0); 48119d50149SHavard Skinnemoen g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td))); 48219d50149SHavard Skinnemoen } 48319d50149SHavard Skinnemoen } 48419d50149SHavard Skinnemoen 48519d50149SHavard Skinnemoen /* 48619d50149SHavard Skinnemoen * Verifies that the timer behaves correctly when disabled right before and 48719d50149SHavard Skinnemoen * exactly when it's supposed to expire. 48819d50149SHavard Skinnemoen */ 48919d50149SHavard Skinnemoen static void test_disable_on_expiration(gconstpointer test_data) 49019d50149SHavard Skinnemoen { 49119d50149SHavard Skinnemoen const TestData *td = test_data; 49219d50149SHavard Skinnemoen unsigned int count = 8; 49319d50149SHavard Skinnemoen unsigned int ps = 255; 49419d50149SHavard Skinnemoen 49519d50149SHavard Skinnemoen tim_reset(td); 49619d50149SHavard Skinnemoen 49719d50149SHavard Skinnemoen tim_write_ticr(td, count); 49819d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps)); 49919d50149SHavard Skinnemoen 50019d50149SHavard Skinnemoen clock_step(tim_calculate_step(count, ps) - 1); 50119d50149SHavard Skinnemoen 50219d50149SHavard Skinnemoen tim_write_tcsr(td, MODE_ONESHOT | PRESCALE(ps)); 50319d50149SHavard Skinnemoen tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps)); 50419d50149SHavard Skinnemoen clock_step(1); 50519d50149SHavard Skinnemoen tim_write_tcsr(td, MODE_ONESHOT | PRESCALE(ps)); 50619d50149SHavard Skinnemoen g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td)); 50719d50149SHavard Skinnemoen } 50819d50149SHavard Skinnemoen 50919d50149SHavard Skinnemoen /* 51019d50149SHavard Skinnemoen * Constructs a name that includes the timer block, timer and testcase name, 51119d50149SHavard Skinnemoen * and adds the test to the test suite. 51219d50149SHavard Skinnemoen */ 51319d50149SHavard Skinnemoen static void tim_add_test(const char *name, const TestData *td, GTestDataFunc fn) 51419d50149SHavard Skinnemoen { 515f3697976SChen Qun g_autofree char *full_name = g_strdup_printf( 516f3697976SChen Qun "npcm7xx_timer/tim[%d]/timer[%d]/%s", tim_index(td->tim), 517f3697976SChen Qun timer_index(td->timer), name); 51819d50149SHavard Skinnemoen qtest_add_data_func(full_name, td, fn); 51919d50149SHavard Skinnemoen } 52019d50149SHavard Skinnemoen 52119d50149SHavard Skinnemoen /* Convenience macro for adding a test with a predictable function name. */ 52219d50149SHavard Skinnemoen #define add_test(name, td) tim_add_test(#name, td, test_##name) 52319d50149SHavard Skinnemoen 52419d50149SHavard Skinnemoen int main(int argc, char **argv) 52519d50149SHavard Skinnemoen { 52619d50149SHavard Skinnemoen TestData testdata[ARRAY_SIZE(timer_block) * ARRAY_SIZE(timer)]; 52719d50149SHavard Skinnemoen int ret; 52819d50149SHavard Skinnemoen int i, j; 52919d50149SHavard Skinnemoen 53019d50149SHavard Skinnemoen g_test_init(&argc, &argv, NULL); 53119d50149SHavard Skinnemoen g_test_set_nonfatal_assertions(); 53219d50149SHavard Skinnemoen 53319d50149SHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(timer_block); i++) { 53419d50149SHavard Skinnemoen for (j = 0; j < ARRAY_SIZE(timer); j++) { 53519d50149SHavard Skinnemoen TestData *td = &testdata[i * ARRAY_SIZE(timer) + j]; 53619d50149SHavard Skinnemoen td->tim = &timer_block[i]; 53719d50149SHavard Skinnemoen td->timer = &timer[j]; 53819d50149SHavard Skinnemoen 53919d50149SHavard Skinnemoen add_test(reset, td); 54019d50149SHavard Skinnemoen add_test(reset_overrides_enable, td); 54119d50149SHavard Skinnemoen add_test(oneshot_enable_then_disable, td); 54219d50149SHavard Skinnemoen add_test(oneshot_ps5, td); 54319d50149SHavard Skinnemoen add_test(oneshot_ps0, td); 54419d50149SHavard Skinnemoen add_test(oneshot_ps255, td); 54519d50149SHavard Skinnemoen add_test(oneshot_interrupt, td); 54619d50149SHavard Skinnemoen add_test(pause_resume, td); 54719d50149SHavard Skinnemoen add_test(prescaler_change, td); 54819d50149SHavard Skinnemoen add_test(periodic_no_interrupt, td); 54919d50149SHavard Skinnemoen add_test(periodic_interrupt, td); 55019d50149SHavard Skinnemoen add_test(disable_on_expiration, td); 55119d50149SHavard Skinnemoen } 55219d50149SHavard Skinnemoen } 55319d50149SHavard Skinnemoen 55419d50149SHavard Skinnemoen qtest_start("-machine npcm750-evb"); 55519d50149SHavard Skinnemoen qtest_irq_intercept_in(global_qtest, "/machine/soc/a9mpcore/gic"); 55619d50149SHavard Skinnemoen ret = g_test_run(); 55719d50149SHavard Skinnemoen qtest_end(); 55819d50149SHavard Skinnemoen 55919d50149SHavard Skinnemoen return ret; 56019d50149SHavard Skinnemoen } 561