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