xref: /qemu/tests/qtest/npcm7xx_timer-test.c (revision 19d50149c857e50ccb1ee35dd4277f9d4954877f)
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