xref: /openbmc/qemu/hw/timer/npcm7xx_timer.c (revision 5de5b99b)
1 /*
2  * Nuvoton NPCM7xx Timer Controller
3  *
4  * Copyright 2020 Google LLC
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14  * for more details.
15  */
16 
17 #include "qemu/osdep.h"
18 
19 #include "hw/irq.h"
20 #include "hw/misc/npcm7xx_clk.h"
21 #include "hw/timer/npcm7xx_timer.h"
22 #include "migration/vmstate.h"
23 #include "qemu/bitops.h"
24 #include "qemu/error-report.h"
25 #include "qemu/log.h"
26 #include "qemu/module.h"
27 #include "qemu/timer.h"
28 #include "qemu/units.h"
29 #include "trace.h"
30 
31 /* 32-bit register indices. */
32 enum NPCM7xxTimerRegisters {
33     NPCM7XX_TIMER_TCSR0,
34     NPCM7XX_TIMER_TCSR1,
35     NPCM7XX_TIMER_TICR0,
36     NPCM7XX_TIMER_TICR1,
37     NPCM7XX_TIMER_TDR0,
38     NPCM7XX_TIMER_TDR1,
39     NPCM7XX_TIMER_TISR,
40     NPCM7XX_TIMER_WTCR,
41     NPCM7XX_TIMER_TCSR2,
42     NPCM7XX_TIMER_TCSR3,
43     NPCM7XX_TIMER_TICR2,
44     NPCM7XX_TIMER_TICR3,
45     NPCM7XX_TIMER_TDR2,
46     NPCM7XX_TIMER_TDR3,
47     NPCM7XX_TIMER_TCSR4         = 0x0040 / sizeof(uint32_t),
48     NPCM7XX_TIMER_TICR4         = 0x0048 / sizeof(uint32_t),
49     NPCM7XX_TIMER_TDR4          = 0x0050 / sizeof(uint32_t),
50     NPCM7XX_TIMER_REGS_END,
51 };
52 
53 /* Register field definitions. */
54 #define NPCM7XX_TCSR_CEN                BIT(30)
55 #define NPCM7XX_TCSR_IE                 BIT(29)
56 #define NPCM7XX_TCSR_PERIODIC           BIT(27)
57 #define NPCM7XX_TCSR_CRST               BIT(26)
58 #define NPCM7XX_TCSR_CACT               BIT(25)
59 #define NPCM7XX_TCSR_RSVD               0x01ffff00
60 #define NPCM7XX_TCSR_PRESCALE_START     0
61 #define NPCM7XX_TCSR_PRESCALE_LEN       8
62 
63 /*
64  * Returns the index of timer in the tc->timer array. This can be used to
65  * locate the registers that belong to this timer.
66  */
67 static int npcm7xx_timer_index(NPCM7xxTimerCtrlState *tc, NPCM7xxTimer *timer)
68 {
69     int index = timer - tc->timer;
70 
71     g_assert(index >= 0 && index < NPCM7XX_TIMERS_PER_CTRL);
72 
73     return index;
74 }
75 
76 /* Return the value by which to divide the reference clock rate. */
77 static uint32_t npcm7xx_tcsr_prescaler(uint32_t tcsr)
78 {
79     return extract32(tcsr, NPCM7XX_TCSR_PRESCALE_START,
80                      NPCM7XX_TCSR_PRESCALE_LEN) + 1;
81 }
82 
83 /* Convert a timer cycle count to a time interval in nanoseconds. */
84 static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count)
85 {
86     int64_t ns = count;
87 
88     ns *= NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ;
89     ns *= npcm7xx_tcsr_prescaler(t->tcsr);
90 
91     return ns;
92 }
93 
94 /* Convert a time interval in nanoseconds to a timer cycle count. */
95 static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
96 {
97     int64_t count;
98 
99     count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ);
100     count /= npcm7xx_tcsr_prescaler(t->tcsr);
101 
102     return count;
103 }
104 
105 /*
106  * Raise the interrupt line if there's a pending interrupt and interrupts are
107  * enabled for this timer. If not, lower it.
108  */
109 static void npcm7xx_timer_check_interrupt(NPCM7xxTimer *t)
110 {
111     NPCM7xxTimerCtrlState *tc = t->ctrl;
112     int index = npcm7xx_timer_index(tc, t);
113     bool pending = (t->tcsr & NPCM7XX_TCSR_IE) && (tc->tisr & BIT(index));
114 
115     qemu_set_irq(t->irq, pending);
116     trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, pending);
117 }
118 
119 /* Start or resume the timer. */
120 static void npcm7xx_timer_start(NPCM7xxTimer *t)
121 {
122     int64_t now;
123 
124     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
125     t->expires_ns = now + t->remaining_ns;
126     timer_mod(&t->qtimer, t->expires_ns);
127 }
128 
129 /*
130  * Called when the counter reaches zero. Sets the interrupt flag, and either
131  * restarts or disables the timer.
132  */
133 static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
134 {
135     NPCM7xxTimerCtrlState *tc = t->ctrl;
136     int index = npcm7xx_timer_index(tc, t);
137 
138     tc->tisr |= BIT(index);
139 
140     if (t->tcsr & NPCM7XX_TCSR_PERIODIC) {
141         t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
142         if (t->tcsr & NPCM7XX_TCSR_CEN) {
143             npcm7xx_timer_start(t);
144         }
145     } else {
146         t->tcsr &= ~(NPCM7XX_TCSR_CEN | NPCM7XX_TCSR_CACT);
147     }
148 
149     npcm7xx_timer_check_interrupt(t);
150 }
151 
152 /* Stop counting. Record the time remaining so we can continue later. */
153 static void npcm7xx_timer_pause(NPCM7xxTimer *t)
154 {
155     int64_t now;
156 
157     timer_del(&t->qtimer);
158     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
159     t->remaining_ns = t->expires_ns - now;
160     if (t->remaining_ns <= 0) {
161         npcm7xx_timer_reached_zero(t);
162     }
163 }
164 
165 /*
166  * Restart the timer from its initial value. If the timer was enabled and stays
167  * enabled, adjust the QEMU timer according to the new count. If the timer is
168  * transitioning from disabled to enabled, the caller is expected to start the
169  * timer later.
170  */
171 static void npcm7xx_timer_restart(NPCM7xxTimer *t, uint32_t old_tcsr)
172 {
173     t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
174 
175     if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
176         npcm7xx_timer_start(t);
177     }
178 }
179 
180 /* Register read and write handlers */
181 
182 static uint32_t npcm7xx_timer_read_tdr(NPCM7xxTimer *t)
183 {
184     if (t->tcsr & NPCM7XX_TCSR_CEN) {
185         int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
186 
187         return npcm7xx_timer_ns_to_count(t, t->expires_ns - now);
188     }
189 
190     return npcm7xx_timer_ns_to_count(t, t->remaining_ns);
191 }
192 
193 static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
194 {
195     uint32_t old_tcsr = t->tcsr;
196     uint32_t tdr;
197 
198     if (new_tcsr & NPCM7XX_TCSR_RSVD) {
199         qemu_log_mask(LOG_GUEST_ERROR, "%s: reserved bits in 0x%08x ignored\n",
200                       __func__, new_tcsr);
201         new_tcsr &= ~NPCM7XX_TCSR_RSVD;
202     }
203     if (new_tcsr & NPCM7XX_TCSR_CACT) {
204         qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only bits in 0x%08x ignored\n",
205                       __func__, new_tcsr);
206         new_tcsr &= ~NPCM7XX_TCSR_CACT;
207     }
208     if ((new_tcsr & NPCM7XX_TCSR_CRST) && (new_tcsr & NPCM7XX_TCSR_CEN)) {
209         qemu_log_mask(LOG_GUEST_ERROR,
210                       "%s: both CRST and CEN set; ignoring CEN.\n",
211                       __func__);
212         new_tcsr &= ~NPCM7XX_TCSR_CEN;
213     }
214 
215     /* Calculate the value of TDR before potentially changing the prescaler. */
216     tdr = npcm7xx_timer_read_tdr(t);
217 
218     t->tcsr = (t->tcsr & NPCM7XX_TCSR_CACT) | new_tcsr;
219 
220     if (npcm7xx_tcsr_prescaler(old_tcsr) != npcm7xx_tcsr_prescaler(new_tcsr)) {
221         /* Recalculate time remaining based on the current TDR value. */
222         t->remaining_ns = npcm7xx_timer_count_to_ns(t, tdr);
223         if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
224             npcm7xx_timer_start(t);
225         }
226     }
227 
228     if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_IE) {
229         npcm7xx_timer_check_interrupt(t);
230     }
231     if (new_tcsr & NPCM7XX_TCSR_CRST) {
232         npcm7xx_timer_restart(t, old_tcsr);
233         t->tcsr &= ~NPCM7XX_TCSR_CRST;
234     }
235     if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_CEN) {
236         if (new_tcsr & NPCM7XX_TCSR_CEN) {
237             t->tcsr |= NPCM7XX_TCSR_CACT;
238             npcm7xx_timer_start(t);
239         } else {
240             t->tcsr &= ~NPCM7XX_TCSR_CACT;
241             npcm7xx_timer_pause(t);
242         }
243     }
244 }
245 
246 static void npcm7xx_timer_write_ticr(NPCM7xxTimer *t, uint32_t new_ticr)
247 {
248     t->ticr = new_ticr;
249 
250     npcm7xx_timer_restart(t, t->tcsr);
251 }
252 
253 static void npcm7xx_timer_write_tisr(NPCM7xxTimerCtrlState *s, uint32_t value)
254 {
255     int i;
256 
257     s->tisr &= ~value;
258     for (i = 0; i < ARRAY_SIZE(s->timer); i++) {
259         if (value & (1U << i)) {
260             npcm7xx_timer_check_interrupt(&s->timer[i]);
261         }
262     }
263 }
264 
265 static hwaddr npcm7xx_tcsr_index(hwaddr reg)
266 {
267     switch (reg) {
268     case NPCM7XX_TIMER_TCSR0:
269         return 0;
270     case NPCM7XX_TIMER_TCSR1:
271         return 1;
272     case NPCM7XX_TIMER_TCSR2:
273         return 2;
274     case NPCM7XX_TIMER_TCSR3:
275         return 3;
276     case NPCM7XX_TIMER_TCSR4:
277         return 4;
278     default:
279         g_assert_not_reached();
280     }
281 }
282 
283 static hwaddr npcm7xx_ticr_index(hwaddr reg)
284 {
285     switch (reg) {
286     case NPCM7XX_TIMER_TICR0:
287         return 0;
288     case NPCM7XX_TIMER_TICR1:
289         return 1;
290     case NPCM7XX_TIMER_TICR2:
291         return 2;
292     case NPCM7XX_TIMER_TICR3:
293         return 3;
294     case NPCM7XX_TIMER_TICR4:
295         return 4;
296     default:
297         g_assert_not_reached();
298     }
299 }
300 
301 static hwaddr npcm7xx_tdr_index(hwaddr reg)
302 {
303     switch (reg) {
304     case NPCM7XX_TIMER_TDR0:
305         return 0;
306     case NPCM7XX_TIMER_TDR1:
307         return 1;
308     case NPCM7XX_TIMER_TDR2:
309         return 2;
310     case NPCM7XX_TIMER_TDR3:
311         return 3;
312     case NPCM7XX_TIMER_TDR4:
313         return 4;
314     default:
315         g_assert_not_reached();
316     }
317 }
318 
319 static uint64_t npcm7xx_timer_read(void *opaque, hwaddr offset, unsigned size)
320 {
321     NPCM7xxTimerCtrlState *s = opaque;
322     uint64_t value = 0;
323     hwaddr reg;
324 
325     reg = offset / sizeof(uint32_t);
326     switch (reg) {
327     case NPCM7XX_TIMER_TCSR0:
328     case NPCM7XX_TIMER_TCSR1:
329     case NPCM7XX_TIMER_TCSR2:
330     case NPCM7XX_TIMER_TCSR3:
331     case NPCM7XX_TIMER_TCSR4:
332         value = s->timer[npcm7xx_tcsr_index(reg)].tcsr;
333         break;
334 
335     case NPCM7XX_TIMER_TICR0:
336     case NPCM7XX_TIMER_TICR1:
337     case NPCM7XX_TIMER_TICR2:
338     case NPCM7XX_TIMER_TICR3:
339     case NPCM7XX_TIMER_TICR4:
340         value = s->timer[npcm7xx_ticr_index(reg)].ticr;
341         break;
342 
343     case NPCM7XX_TIMER_TDR0:
344     case NPCM7XX_TIMER_TDR1:
345     case NPCM7XX_TIMER_TDR2:
346     case NPCM7XX_TIMER_TDR3:
347     case NPCM7XX_TIMER_TDR4:
348         value = npcm7xx_timer_read_tdr(&s->timer[npcm7xx_tdr_index(reg)]);
349         break;
350 
351     case NPCM7XX_TIMER_TISR:
352         value = s->tisr;
353         break;
354 
355     case NPCM7XX_TIMER_WTCR:
356         value = s->wtcr;
357         break;
358 
359     default:
360         qemu_log_mask(LOG_GUEST_ERROR,
361                       "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
362                       __func__, offset);
363         break;
364     }
365 
366     trace_npcm7xx_timer_read(DEVICE(s)->canonical_path, offset, value);
367 
368     return value;
369 }
370 
371 static void npcm7xx_timer_write(void *opaque, hwaddr offset,
372                                 uint64_t v, unsigned size)
373 {
374     uint32_t reg = offset / sizeof(uint32_t);
375     NPCM7xxTimerCtrlState *s = opaque;
376     uint32_t value = v;
377 
378     trace_npcm7xx_timer_write(DEVICE(s)->canonical_path, offset, value);
379 
380     switch (reg) {
381     case NPCM7XX_TIMER_TCSR0:
382     case NPCM7XX_TIMER_TCSR1:
383     case NPCM7XX_TIMER_TCSR2:
384     case NPCM7XX_TIMER_TCSR3:
385     case NPCM7XX_TIMER_TCSR4:
386         npcm7xx_timer_write_tcsr(&s->timer[npcm7xx_tcsr_index(reg)], value);
387         return;
388 
389     case NPCM7XX_TIMER_TICR0:
390     case NPCM7XX_TIMER_TICR1:
391     case NPCM7XX_TIMER_TICR2:
392     case NPCM7XX_TIMER_TICR3:
393     case NPCM7XX_TIMER_TICR4:
394         npcm7xx_timer_write_ticr(&s->timer[npcm7xx_ticr_index(reg)], value);
395         return;
396 
397     case NPCM7XX_TIMER_TDR0:
398     case NPCM7XX_TIMER_TDR1:
399     case NPCM7XX_TIMER_TDR2:
400     case NPCM7XX_TIMER_TDR3:
401     case NPCM7XX_TIMER_TDR4:
402         qemu_log_mask(LOG_GUEST_ERROR,
403                       "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
404                       __func__, offset);
405         return;
406 
407     case NPCM7XX_TIMER_TISR:
408         npcm7xx_timer_write_tisr(s, value);
409         return;
410 
411     case NPCM7XX_TIMER_WTCR:
412         qemu_log_mask(LOG_UNIMP, "%s: WTCR write not implemented: 0x%08x\n",
413                       __func__, value);
414         return;
415     }
416 
417     qemu_log_mask(LOG_GUEST_ERROR,
418                   "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
419                   __func__, offset);
420 }
421 
422 static const struct MemoryRegionOps npcm7xx_timer_ops = {
423     .read       = npcm7xx_timer_read,
424     .write      = npcm7xx_timer_write,
425     .endianness = DEVICE_LITTLE_ENDIAN,
426     .valid      = {
427         .min_access_size        = 4,
428         .max_access_size        = 4,
429         .unaligned              = false,
430     },
431 };
432 
433 /* Called when the QEMU timer expires. */
434 static void npcm7xx_timer_expired(void *opaque)
435 {
436     NPCM7xxTimer *t = opaque;
437 
438     if (t->tcsr & NPCM7XX_TCSR_CEN) {
439         npcm7xx_timer_reached_zero(t);
440     }
441 }
442 
443 static void npcm7xx_timer_enter_reset(Object *obj, ResetType type)
444 {
445     NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
446     int i;
447 
448     for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
449         NPCM7xxTimer *t = &s->timer[i];
450 
451         timer_del(&t->qtimer);
452         t->expires_ns = 0;
453         t->remaining_ns = 0;
454         t->tcsr = 0x00000005;
455         t->ticr = 0x00000000;
456     }
457 
458     s->tisr = 0x00000000;
459     s->wtcr = 0x00000400;
460 }
461 
462 static void npcm7xx_timer_hold_reset(Object *obj)
463 {
464     NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
465     int i;
466 
467     for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
468         qemu_irq_lower(s->timer[i].irq);
469     }
470 }
471 
472 static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
473 {
474     NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
475     SysBusDevice *sbd = &s->parent;
476     int i;
477 
478     for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
479         NPCM7xxTimer *t = &s->timer[i];
480         t->ctrl = s;
481         timer_init_ns(&t->qtimer, QEMU_CLOCK_VIRTUAL, npcm7xx_timer_expired, t);
482         sysbus_init_irq(sbd, &t->irq);
483     }
484 
485     memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s,
486                           TYPE_NPCM7XX_TIMER, 4 * KiB);
487     sysbus_init_mmio(sbd, &s->iomem);
488 }
489 
490 static const VMStateDescription vmstate_npcm7xx_timer = {
491     .name = "npcm7xx-timer",
492     .version_id = 0,
493     .minimum_version_id = 0,
494     .fields = (VMStateField[]) {
495         VMSTATE_TIMER(qtimer, NPCM7xxTimer),
496         VMSTATE_INT64(expires_ns, NPCM7xxTimer),
497         VMSTATE_INT64(remaining_ns, NPCM7xxTimer),
498         VMSTATE_UINT32(tcsr, NPCM7xxTimer),
499         VMSTATE_UINT32(ticr, NPCM7xxTimer),
500         VMSTATE_END_OF_LIST(),
501     },
502 };
503 
504 static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
505     .name = "npcm7xx-timer-ctrl",
506     .version_id = 0,
507     .minimum_version_id = 0,
508     .fields = (VMStateField[]) {
509         VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
510         VMSTATE_UINT32(wtcr, NPCM7xxTimerCtrlState),
511         VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
512                              NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
513                              NPCM7xxTimer),
514         VMSTATE_END_OF_LIST(),
515     },
516 };
517 
518 static void npcm7xx_timer_class_init(ObjectClass *klass, void *data)
519 {
520     ResettableClass *rc = RESETTABLE_CLASS(klass);
521     DeviceClass *dc = DEVICE_CLASS(klass);
522 
523     QEMU_BUILD_BUG_ON(NPCM7XX_TIMER_REGS_END > NPCM7XX_TIMER_NR_REGS);
524 
525     dc->desc = "NPCM7xx Timer Controller";
526     dc->realize = npcm7xx_timer_realize;
527     dc->vmsd = &vmstate_npcm7xx_timer_ctrl;
528     rc->phases.enter = npcm7xx_timer_enter_reset;
529     rc->phases.hold = npcm7xx_timer_hold_reset;
530 }
531 
532 static const TypeInfo npcm7xx_timer_info = {
533     .name               = TYPE_NPCM7XX_TIMER,
534     .parent             = TYPE_SYS_BUS_DEVICE,
535     .instance_size      = sizeof(NPCM7xxTimerCtrlState),
536     .class_init         = npcm7xx_timer_class_init,
537 };
538 
539 static void npcm7xx_timer_register_type(void)
540 {
541     type_register_static(&npcm7xx_timer_info);
542 }
543 type_init(npcm7xx_timer_register_type);
544