xref: /openbmc/qemu/hw/timer/pxa2xx_timer.c (revision 4f67d30b5e74e060b8dbe10528829b47345cd6e8)
13bd88451SPaolo Bonzini /*
23bd88451SPaolo Bonzini  * Intel XScale PXA255/270 OS Timers.
33bd88451SPaolo Bonzini  *
43bd88451SPaolo Bonzini  * Copyright (c) 2006 Openedhand Ltd.
53bd88451SPaolo Bonzini  * Copyright (c) 2006 Thorsten Zitterell
63bd88451SPaolo Bonzini  *
73bd88451SPaolo Bonzini  * This code is licensed under the GPL.
83bd88451SPaolo Bonzini  */
93bd88451SPaolo Bonzini 
108ef94f0bSPeter Maydell #include "qemu/osdep.h"
1164552b6bSMarkus Armbruster #include "hw/irq.h"
12a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
133bd88451SPaolo Bonzini #include "qemu/timer.h"
1454d31236SMarkus Armbruster #include "sysemu/runstate.h"
153bd88451SPaolo Bonzini #include "hw/arm/pxa.h"
163bd88451SPaolo Bonzini #include "hw/sysbus.h"
17d6454270SMarkus Armbruster #include "migration/vmstate.h"
182ba63e4aSPhilippe Mathieu-Daudé #include "qemu/log.h"
190b8fa32fSMarkus Armbruster #include "qemu/module.h"
203bd88451SPaolo Bonzini 
213bd88451SPaolo Bonzini #define OSMR0	0x00
223bd88451SPaolo Bonzini #define OSMR1	0x04
233bd88451SPaolo Bonzini #define OSMR2	0x08
243bd88451SPaolo Bonzini #define OSMR3	0x0c
253bd88451SPaolo Bonzini #define OSMR4	0x80
263bd88451SPaolo Bonzini #define OSMR5	0x84
273bd88451SPaolo Bonzini #define OSMR6	0x88
283bd88451SPaolo Bonzini #define OSMR7	0x8c
293bd88451SPaolo Bonzini #define OSMR8	0x90
303bd88451SPaolo Bonzini #define OSMR9	0x94
313bd88451SPaolo Bonzini #define OSMR10	0x98
323bd88451SPaolo Bonzini #define OSMR11	0x9c
333bd88451SPaolo Bonzini #define OSCR	0x10	/* OS Timer Count */
343bd88451SPaolo Bonzini #define OSCR4	0x40
353bd88451SPaolo Bonzini #define OSCR5	0x44
363bd88451SPaolo Bonzini #define OSCR6	0x48
373bd88451SPaolo Bonzini #define OSCR7	0x4c
383bd88451SPaolo Bonzini #define OSCR8	0x50
393bd88451SPaolo Bonzini #define OSCR9	0x54
403bd88451SPaolo Bonzini #define OSCR10	0x58
413bd88451SPaolo Bonzini #define OSCR11	0x5c
423bd88451SPaolo Bonzini #define OSSR	0x14	/* Timer status register */
433bd88451SPaolo Bonzini #define OWER	0x18
443bd88451SPaolo Bonzini #define OIER	0x1c	/* Interrupt enable register  3-0 to E3-E0 */
453bd88451SPaolo Bonzini #define OMCR4	0xc0	/* OS Match Control registers */
463bd88451SPaolo Bonzini #define OMCR5	0xc4
473bd88451SPaolo Bonzini #define OMCR6	0xc8
483bd88451SPaolo Bonzini #define OMCR7	0xcc
493bd88451SPaolo Bonzini #define OMCR8	0xd0
503bd88451SPaolo Bonzini #define OMCR9	0xd4
513bd88451SPaolo Bonzini #define OMCR10	0xd8
523bd88451SPaolo Bonzini #define OMCR11	0xdc
533bd88451SPaolo Bonzini #define OSNR	0x20
543bd88451SPaolo Bonzini 
553bd88451SPaolo Bonzini #define PXA25X_FREQ	3686400	/* 3.6864 MHz */
563bd88451SPaolo Bonzini #define PXA27X_FREQ	3250000	/* 3.25 MHz */
573bd88451SPaolo Bonzini 
583bd88451SPaolo Bonzini static int pxa2xx_timer4_freq[8] = {
593bd88451SPaolo Bonzini     [0] = 0,
603bd88451SPaolo Bonzini     [1] = 32768,
613bd88451SPaolo Bonzini     [2] = 1000,
623bd88451SPaolo Bonzini     [3] = 1,
633bd88451SPaolo Bonzini     [4] = 1000000,
643bd88451SPaolo Bonzini     /* [5] is the "Externally supplied clock".  Assign if necessary.  */
653bd88451SPaolo Bonzini     [5 ... 7] = 0,
663bd88451SPaolo Bonzini };
673bd88451SPaolo Bonzini 
68feea4361SAndreas Färber #define TYPE_PXA2XX_TIMER "pxa2xx-timer"
69feea4361SAndreas Färber #define PXA2XX_TIMER(obj) \
70feea4361SAndreas Färber     OBJECT_CHECK(PXA2xxTimerInfo, (obj), TYPE_PXA2XX_TIMER)
71feea4361SAndreas Färber 
723bd88451SPaolo Bonzini typedef struct PXA2xxTimerInfo PXA2xxTimerInfo;
733bd88451SPaolo Bonzini 
743bd88451SPaolo Bonzini typedef struct {
753bd88451SPaolo Bonzini     uint32_t value;
763bd88451SPaolo Bonzini     qemu_irq irq;
773bd88451SPaolo Bonzini     QEMUTimer *qtimer;
783bd88451SPaolo Bonzini     int num;
793bd88451SPaolo Bonzini     PXA2xxTimerInfo *info;
803bd88451SPaolo Bonzini } PXA2xxTimer0;
813bd88451SPaolo Bonzini 
823bd88451SPaolo Bonzini typedef struct {
833bd88451SPaolo Bonzini     PXA2xxTimer0 tm;
843bd88451SPaolo Bonzini     int32_t oldclock;
853bd88451SPaolo Bonzini     int32_t clock;
863bd88451SPaolo Bonzini     uint64_t lastload;
873bd88451SPaolo Bonzini     uint32_t freq;
883bd88451SPaolo Bonzini     uint32_t control;
893bd88451SPaolo Bonzini } PXA2xxTimer4;
903bd88451SPaolo Bonzini 
913bd88451SPaolo Bonzini struct PXA2xxTimerInfo {
92feea4361SAndreas Färber     SysBusDevice parent_obj;
93feea4361SAndreas Färber 
943bd88451SPaolo Bonzini     MemoryRegion iomem;
953bd88451SPaolo Bonzini     uint32_t flags;
963bd88451SPaolo Bonzini 
973bd88451SPaolo Bonzini     int32_t clock;
983bd88451SPaolo Bonzini     int32_t oldclock;
993bd88451SPaolo Bonzini     uint64_t lastload;
1003bd88451SPaolo Bonzini     uint32_t freq;
1013bd88451SPaolo Bonzini     PXA2xxTimer0 timer[4];
1023bd88451SPaolo Bonzini     uint32_t events;
1033bd88451SPaolo Bonzini     uint32_t irq_enabled;
1043bd88451SPaolo Bonzini     uint32_t reset3;
1053bd88451SPaolo Bonzini     uint32_t snapshot;
1063bd88451SPaolo Bonzini 
1073bd88451SPaolo Bonzini     qemu_irq irq4;
1083bd88451SPaolo Bonzini     PXA2xxTimer4 tm4[8];
1093bd88451SPaolo Bonzini };
1103bd88451SPaolo Bonzini 
1113bd88451SPaolo Bonzini #define PXA2XX_TIMER_HAVE_TM4	0
1123bd88451SPaolo Bonzini 
1133bd88451SPaolo Bonzini static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
1143bd88451SPaolo Bonzini {
1153bd88451SPaolo Bonzini     return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
1163bd88451SPaolo Bonzini }
1173bd88451SPaolo Bonzini 
1183bd88451SPaolo Bonzini static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
1193bd88451SPaolo Bonzini {
1203bd88451SPaolo Bonzini     PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
1213bd88451SPaolo Bonzini     int i;
1223bd88451SPaolo Bonzini     uint32_t now_vm;
1233bd88451SPaolo Bonzini     uint64_t new_qemu;
1243bd88451SPaolo Bonzini 
1253bd88451SPaolo Bonzini     now_vm = s->clock +
12673bcb24dSRutuja Shah             muldiv64(now_qemu - s->lastload, s->freq, NANOSECONDS_PER_SECOND);
1273bd88451SPaolo Bonzini 
1283bd88451SPaolo Bonzini     for (i = 0; i < 4; i ++) {
1293bd88451SPaolo Bonzini         new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
13073bcb24dSRutuja Shah                         NANOSECONDS_PER_SECOND, s->freq);
131bc72ad67SAlex Bligh         timer_mod(s->timer[i].qtimer, new_qemu);
1323bd88451SPaolo Bonzini     }
1333bd88451SPaolo Bonzini }
1343bd88451SPaolo Bonzini 
1353bd88451SPaolo Bonzini static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
1363bd88451SPaolo Bonzini {
1373bd88451SPaolo Bonzini     PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
1383bd88451SPaolo Bonzini     uint32_t now_vm;
1393bd88451SPaolo Bonzini     uint64_t new_qemu;
1403bd88451SPaolo Bonzini     static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
1413bd88451SPaolo Bonzini     int counter;
1423bd88451SPaolo Bonzini 
1433bd88451SPaolo Bonzini     if (s->tm4[n].control & (1 << 7))
1443bd88451SPaolo Bonzini         counter = n;
1453bd88451SPaolo Bonzini     else
1463bd88451SPaolo Bonzini         counter = counters[n];
1473bd88451SPaolo Bonzini 
1483bd88451SPaolo Bonzini     if (!s->tm4[counter].freq) {
149bc72ad67SAlex Bligh         timer_del(s->tm4[n].tm.qtimer);
1503bd88451SPaolo Bonzini         return;
1513bd88451SPaolo Bonzini     }
1523bd88451SPaolo Bonzini 
1533bd88451SPaolo Bonzini     now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
1543bd88451SPaolo Bonzini                     s->tm4[counter].lastload,
15573bcb24dSRutuja Shah                     s->tm4[counter].freq, NANOSECONDS_PER_SECOND);
1563bd88451SPaolo Bonzini 
1573bd88451SPaolo Bonzini     new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
15873bcb24dSRutuja Shah                     NANOSECONDS_PER_SECOND, s->tm4[counter].freq);
159bc72ad67SAlex Bligh     timer_mod(s->tm4[n].tm.qtimer, new_qemu);
1603bd88451SPaolo Bonzini }
1613bd88451SPaolo Bonzini 
1623bd88451SPaolo Bonzini static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset,
1633bd88451SPaolo Bonzini                                   unsigned size)
1643bd88451SPaolo Bonzini {
1653bd88451SPaolo Bonzini     PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
1663bd88451SPaolo Bonzini     int tm = 0;
1673bd88451SPaolo Bonzini 
1683bd88451SPaolo Bonzini     switch (offset) {
1693bd88451SPaolo Bonzini     case OSMR3:  tm ++;
1703bd88451SPaolo Bonzini         /* fall through */
1713bd88451SPaolo Bonzini     case OSMR2:  tm ++;
1723bd88451SPaolo Bonzini         /* fall through */
1733bd88451SPaolo Bonzini     case OSMR1:  tm ++;
1743bd88451SPaolo Bonzini         /* fall through */
1753bd88451SPaolo Bonzini     case OSMR0:
1763bd88451SPaolo Bonzini         return s->timer[tm].value;
1773bd88451SPaolo Bonzini     case OSMR11: tm ++;
1783bd88451SPaolo Bonzini         /* fall through */
1793bd88451SPaolo Bonzini     case OSMR10: tm ++;
1803bd88451SPaolo Bonzini         /* fall through */
1813bd88451SPaolo Bonzini     case OSMR9:  tm ++;
1823bd88451SPaolo Bonzini         /* fall through */
1833bd88451SPaolo Bonzini     case OSMR8:  tm ++;
1843bd88451SPaolo Bonzini         /* fall through */
1853bd88451SPaolo Bonzini     case OSMR7:  tm ++;
1863bd88451SPaolo Bonzini         /* fall through */
1873bd88451SPaolo Bonzini     case OSMR6:  tm ++;
1883bd88451SPaolo Bonzini         /* fall through */
1893bd88451SPaolo Bonzini     case OSMR5:  tm ++;
1903bd88451SPaolo Bonzini         /* fall through */
1913bd88451SPaolo Bonzini     case OSMR4:
1923bd88451SPaolo Bonzini         if (!pxa2xx_timer_has_tm4(s))
1933bd88451SPaolo Bonzini             goto badreg;
1943bd88451SPaolo Bonzini         return s->tm4[tm].tm.value;
1953bd88451SPaolo Bonzini     case OSCR:
196bc72ad67SAlex Bligh         return s->clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
19773bcb24dSRutuja Shah                         s->lastload, s->freq, NANOSECONDS_PER_SECOND);
1983bd88451SPaolo Bonzini     case OSCR11: tm ++;
1993bd88451SPaolo Bonzini         /* fall through */
2003bd88451SPaolo Bonzini     case OSCR10: tm ++;
2013bd88451SPaolo Bonzini         /* fall through */
2023bd88451SPaolo Bonzini     case OSCR9:  tm ++;
2033bd88451SPaolo Bonzini         /* fall through */
2043bd88451SPaolo Bonzini     case OSCR8:  tm ++;
2053bd88451SPaolo Bonzini         /* fall through */
2063bd88451SPaolo Bonzini     case OSCR7:  tm ++;
2073bd88451SPaolo Bonzini         /* fall through */
2083bd88451SPaolo Bonzini     case OSCR6:  tm ++;
2093bd88451SPaolo Bonzini         /* fall through */
2103bd88451SPaolo Bonzini     case OSCR5:  tm ++;
2113bd88451SPaolo Bonzini         /* fall through */
2123bd88451SPaolo Bonzini     case OSCR4:
2133bd88451SPaolo Bonzini         if (!pxa2xx_timer_has_tm4(s))
2143bd88451SPaolo Bonzini             goto badreg;
2153bd88451SPaolo Bonzini 
2163bd88451SPaolo Bonzini         if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
2173bd88451SPaolo Bonzini             if (s->tm4[tm - 1].freq)
2183bd88451SPaolo Bonzini                 s->snapshot = s->tm4[tm - 1].clock + muldiv64(
219bc72ad67SAlex Bligh                                 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
2203bd88451SPaolo Bonzini                                 s->tm4[tm - 1].lastload,
22173bcb24dSRutuja Shah                                 s->tm4[tm - 1].freq, NANOSECONDS_PER_SECOND);
2223bd88451SPaolo Bonzini             else
2233bd88451SPaolo Bonzini                 s->snapshot = s->tm4[tm - 1].clock;
2243bd88451SPaolo Bonzini         }
2253bd88451SPaolo Bonzini 
2263bd88451SPaolo Bonzini         if (!s->tm4[tm].freq)
2273bd88451SPaolo Bonzini             return s->tm4[tm].clock;
22873bcb24dSRutuja Shah         return s->tm4[tm].clock +
22973bcb24dSRutuja Shah             muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
23073bcb24dSRutuja Shah                      s->tm4[tm].lastload, s->tm4[tm].freq,
23173bcb24dSRutuja Shah                      NANOSECONDS_PER_SECOND);
2323bd88451SPaolo Bonzini     case OIER:
2333bd88451SPaolo Bonzini         return s->irq_enabled;
2343bd88451SPaolo Bonzini     case OSSR:	/* Status register */
2353bd88451SPaolo Bonzini         return s->events;
2363bd88451SPaolo Bonzini     case OWER:
2373bd88451SPaolo Bonzini         return s->reset3;
2383bd88451SPaolo Bonzini     case OMCR11: tm ++;
2393bd88451SPaolo Bonzini         /* fall through */
2403bd88451SPaolo Bonzini     case OMCR10: tm ++;
2413bd88451SPaolo Bonzini         /* fall through */
2423bd88451SPaolo Bonzini     case OMCR9:  tm ++;
2433bd88451SPaolo Bonzini         /* fall through */
2443bd88451SPaolo Bonzini     case OMCR8:  tm ++;
2453bd88451SPaolo Bonzini         /* fall through */
2463bd88451SPaolo Bonzini     case OMCR7:  tm ++;
2473bd88451SPaolo Bonzini         /* fall through */
2483bd88451SPaolo Bonzini     case OMCR6:  tm ++;
2493bd88451SPaolo Bonzini         /* fall through */
2503bd88451SPaolo Bonzini     case OMCR5:  tm ++;
2513bd88451SPaolo Bonzini         /* fall through */
2523bd88451SPaolo Bonzini     case OMCR4:
2533bd88451SPaolo Bonzini         if (!pxa2xx_timer_has_tm4(s))
2543bd88451SPaolo Bonzini             goto badreg;
2553bd88451SPaolo Bonzini         return s->tm4[tm].control;
2563bd88451SPaolo Bonzini     case OSNR:
2573bd88451SPaolo Bonzini         return s->snapshot;
2583bd88451SPaolo Bonzini     default:
2592ba63e4aSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_UNIMP,
2602ba63e4aSPhilippe Mathieu-Daudé                       "%s: unknown register 0x%02" HWADDR_PRIx "\n",
2612ba63e4aSPhilippe Mathieu-Daudé                       __func__, offset);
2622ba63e4aSPhilippe Mathieu-Daudé         break;
2633bd88451SPaolo Bonzini     badreg:
2642ba63e4aSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
2652ba63e4aSPhilippe Mathieu-Daudé                       "%s: incorrect register 0x%02" HWADDR_PRIx "\n",
2662ba63e4aSPhilippe Mathieu-Daudé                       __func__, offset);
2673bd88451SPaolo Bonzini     }
2683bd88451SPaolo Bonzini 
2693bd88451SPaolo Bonzini     return 0;
2703bd88451SPaolo Bonzini }
2713bd88451SPaolo Bonzini 
2723bd88451SPaolo Bonzini static void pxa2xx_timer_write(void *opaque, hwaddr offset,
2733bd88451SPaolo Bonzini                                uint64_t value, unsigned size)
2743bd88451SPaolo Bonzini {
2753bd88451SPaolo Bonzini     int i, tm = 0;
2763bd88451SPaolo Bonzini     PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
2773bd88451SPaolo Bonzini 
2783bd88451SPaolo Bonzini     switch (offset) {
2793bd88451SPaolo Bonzini     case OSMR3:  tm ++;
2803bd88451SPaolo Bonzini         /* fall through */
2813bd88451SPaolo Bonzini     case OSMR2:  tm ++;
2823bd88451SPaolo Bonzini         /* fall through */
2833bd88451SPaolo Bonzini     case OSMR1:  tm ++;
2843bd88451SPaolo Bonzini         /* fall through */
2853bd88451SPaolo Bonzini     case OSMR0:
2863bd88451SPaolo Bonzini         s->timer[tm].value = value;
287bc72ad67SAlex Bligh         pxa2xx_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
2883bd88451SPaolo Bonzini         break;
2893bd88451SPaolo Bonzini     case OSMR11: tm ++;
2903bd88451SPaolo Bonzini         /* fall through */
2913bd88451SPaolo Bonzini     case OSMR10: tm ++;
2923bd88451SPaolo Bonzini         /* fall through */
2933bd88451SPaolo Bonzini     case OSMR9:  tm ++;
2943bd88451SPaolo Bonzini         /* fall through */
2953bd88451SPaolo Bonzini     case OSMR8:  tm ++;
2963bd88451SPaolo Bonzini         /* fall through */
2973bd88451SPaolo Bonzini     case OSMR7:  tm ++;
2983bd88451SPaolo Bonzini         /* fall through */
2993bd88451SPaolo Bonzini     case OSMR6:  tm ++;
3003bd88451SPaolo Bonzini         /* fall through */
3013bd88451SPaolo Bonzini     case OSMR5:  tm ++;
3023bd88451SPaolo Bonzini         /* fall through */
3033bd88451SPaolo Bonzini     case OSMR4:
3043bd88451SPaolo Bonzini         if (!pxa2xx_timer_has_tm4(s))
3053bd88451SPaolo Bonzini             goto badreg;
3063bd88451SPaolo Bonzini         s->tm4[tm].tm.value = value;
307bc72ad67SAlex Bligh         pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
3083bd88451SPaolo Bonzini         break;
3093bd88451SPaolo Bonzini     case OSCR:
3103bd88451SPaolo Bonzini         s->oldclock = s->clock;
311bc72ad67SAlex Bligh         s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3123bd88451SPaolo Bonzini         s->clock = value;
3133bd88451SPaolo Bonzini         pxa2xx_timer_update(s, s->lastload);
3143bd88451SPaolo Bonzini         break;
3153bd88451SPaolo Bonzini     case OSCR11: tm ++;
3163bd88451SPaolo Bonzini         /* fall through */
3173bd88451SPaolo Bonzini     case OSCR10: tm ++;
3183bd88451SPaolo Bonzini         /* fall through */
3193bd88451SPaolo Bonzini     case OSCR9:  tm ++;
3203bd88451SPaolo Bonzini         /* fall through */
3213bd88451SPaolo Bonzini     case OSCR8:  tm ++;
3223bd88451SPaolo Bonzini         /* fall through */
3233bd88451SPaolo Bonzini     case OSCR7:  tm ++;
3243bd88451SPaolo Bonzini         /* fall through */
3253bd88451SPaolo Bonzini     case OSCR6:  tm ++;
3263bd88451SPaolo Bonzini         /* fall through */
3273bd88451SPaolo Bonzini     case OSCR5:  tm ++;
3283bd88451SPaolo Bonzini         /* fall through */
3293bd88451SPaolo Bonzini     case OSCR4:
3303bd88451SPaolo Bonzini         if (!pxa2xx_timer_has_tm4(s))
3313bd88451SPaolo Bonzini             goto badreg;
3323bd88451SPaolo Bonzini         s->tm4[tm].oldclock = s->tm4[tm].clock;
333bc72ad67SAlex Bligh         s->tm4[tm].lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3343bd88451SPaolo Bonzini         s->tm4[tm].clock = value;
3353bd88451SPaolo Bonzini         pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
3363bd88451SPaolo Bonzini         break;
3373bd88451SPaolo Bonzini     case OIER:
3383bd88451SPaolo Bonzini         s->irq_enabled = value & 0xfff;
3393bd88451SPaolo Bonzini         break;
3403bd88451SPaolo Bonzini     case OSSR:	/* Status register */
3413bd88451SPaolo Bonzini         value &= s->events;
3423bd88451SPaolo Bonzini         s->events &= ~value;
3433bd88451SPaolo Bonzini         for (i = 0; i < 4; i ++, value >>= 1)
3443bd88451SPaolo Bonzini             if (value & 1)
3453bd88451SPaolo Bonzini                 qemu_irq_lower(s->timer[i].irq);
3463bd88451SPaolo Bonzini         if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
3473bd88451SPaolo Bonzini             qemu_irq_lower(s->irq4);
3483bd88451SPaolo Bonzini         break;
3493bd88451SPaolo Bonzini     case OWER:	/* XXX: Reset on OSMR3 match? */
3503bd88451SPaolo Bonzini         s->reset3 = value;
3513bd88451SPaolo Bonzini         break;
3523bd88451SPaolo Bonzini     case OMCR7:  tm ++;
3533bd88451SPaolo Bonzini         /* fall through */
3543bd88451SPaolo Bonzini     case OMCR6:  tm ++;
3553bd88451SPaolo Bonzini         /* fall through */
3563bd88451SPaolo Bonzini     case OMCR5:  tm ++;
3573bd88451SPaolo Bonzini         /* fall through */
3583bd88451SPaolo Bonzini     case OMCR4:
3593bd88451SPaolo Bonzini         if (!pxa2xx_timer_has_tm4(s))
3603bd88451SPaolo Bonzini             goto badreg;
3613bd88451SPaolo Bonzini         s->tm4[tm].control = value & 0x0ff;
3623bd88451SPaolo Bonzini         /* XXX Stop if running (shouldn't happen) */
3633bd88451SPaolo Bonzini         if ((value & (1 << 7)) || tm == 0)
3643bd88451SPaolo Bonzini             s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
3653bd88451SPaolo Bonzini         else {
3663bd88451SPaolo Bonzini             s->tm4[tm].freq = 0;
367bc72ad67SAlex Bligh             pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
3683bd88451SPaolo Bonzini         }
3693bd88451SPaolo Bonzini         break;
3703bd88451SPaolo Bonzini     case OMCR11: tm ++;
3713bd88451SPaolo Bonzini         /* fall through */
3723bd88451SPaolo Bonzini     case OMCR10: tm ++;
3733bd88451SPaolo Bonzini         /* fall through */
3743bd88451SPaolo Bonzini     case OMCR9:  tm ++;
3753bd88451SPaolo Bonzini         /* fall through */
3763bd88451SPaolo Bonzini     case OMCR8:  tm += 4;
3773bd88451SPaolo Bonzini         if (!pxa2xx_timer_has_tm4(s))
3783bd88451SPaolo Bonzini             goto badreg;
3793bd88451SPaolo Bonzini         s->tm4[tm].control = value & 0x3ff;
3803bd88451SPaolo Bonzini         /* XXX Stop if running (shouldn't happen) */
3813bd88451SPaolo Bonzini         if ((value & (1 << 7)) || !(tm & 1))
3823bd88451SPaolo Bonzini             s->tm4[tm].freq =
3833bd88451SPaolo Bonzini                     pxa2xx_timer4_freq[(value & (1 << 8)) ?  0 : (value & 7)];
3843bd88451SPaolo Bonzini         else {
3853bd88451SPaolo Bonzini             s->tm4[tm].freq = 0;
386bc72ad67SAlex Bligh             pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
3873bd88451SPaolo Bonzini         }
3883bd88451SPaolo Bonzini         break;
3893bd88451SPaolo Bonzini     default:
3902ba63e4aSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_UNIMP,
3912ba63e4aSPhilippe Mathieu-Daudé                       "%s: unknown register 0x%02" HWADDR_PRIx " "
3922ba63e4aSPhilippe Mathieu-Daudé                       "(value 0x%08" PRIx64 ")\n",  __func__, offset, value);
3932ba63e4aSPhilippe Mathieu-Daudé         break;
3943bd88451SPaolo Bonzini     badreg:
3952ba63e4aSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
3962ba63e4aSPhilippe Mathieu-Daudé                       "%s: incorrect register 0x%02" HWADDR_PRIx " "
3972ba63e4aSPhilippe Mathieu-Daudé                       "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
3983bd88451SPaolo Bonzini     }
3993bd88451SPaolo Bonzini }
4003bd88451SPaolo Bonzini 
4013bd88451SPaolo Bonzini static const MemoryRegionOps pxa2xx_timer_ops = {
4023bd88451SPaolo Bonzini     .read = pxa2xx_timer_read,
4033bd88451SPaolo Bonzini     .write = pxa2xx_timer_write,
4043bd88451SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
4053bd88451SPaolo Bonzini };
4063bd88451SPaolo Bonzini 
4073bd88451SPaolo Bonzini static void pxa2xx_timer_tick(void *opaque)
4083bd88451SPaolo Bonzini {
4093bd88451SPaolo Bonzini     PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
4103bd88451SPaolo Bonzini     PXA2xxTimerInfo *i = t->info;
4113bd88451SPaolo Bonzini 
4123bd88451SPaolo Bonzini     if (i->irq_enabled & (1 << t->num)) {
4133bd88451SPaolo Bonzini         i->events |= 1 << t->num;
4143bd88451SPaolo Bonzini         qemu_irq_raise(t->irq);
4153bd88451SPaolo Bonzini     }
4163bd88451SPaolo Bonzini 
4173bd88451SPaolo Bonzini     if (t->num == 3)
4183bd88451SPaolo Bonzini         if (i->reset3 & 1) {
4193bd88451SPaolo Bonzini             i->reset3 = 0;
420cf83f140SEric Blake             qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
4213bd88451SPaolo Bonzini         }
4223bd88451SPaolo Bonzini }
4233bd88451SPaolo Bonzini 
4243bd88451SPaolo Bonzini static void pxa2xx_timer_tick4(void *opaque)
4253bd88451SPaolo Bonzini {
4263bd88451SPaolo Bonzini     PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
4273bd88451SPaolo Bonzini     PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
4283bd88451SPaolo Bonzini 
4293bd88451SPaolo Bonzini     pxa2xx_timer_tick(&t->tm);
4303bd88451SPaolo Bonzini     if (t->control & (1 << 3))
4313bd88451SPaolo Bonzini         t->clock = 0;
4323bd88451SPaolo Bonzini     if (t->control & (1 << 6))
433bc72ad67SAlex Bligh         pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4);
4343bd88451SPaolo Bonzini     if (i->events & 0xff0)
4353bd88451SPaolo Bonzini         qemu_irq_raise(i->irq4);
4363bd88451SPaolo Bonzini }
4373bd88451SPaolo Bonzini 
4383bd88451SPaolo Bonzini static int pxa25x_timer_post_load(void *opaque, int version_id)
4393bd88451SPaolo Bonzini {
4403bd88451SPaolo Bonzini     PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
4413bd88451SPaolo Bonzini     int64_t now;
4423bd88451SPaolo Bonzini     int i;
4433bd88451SPaolo Bonzini 
444bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
4453bd88451SPaolo Bonzini     pxa2xx_timer_update(s, now);
4463bd88451SPaolo Bonzini 
4473bd88451SPaolo Bonzini     if (pxa2xx_timer_has_tm4(s))
4483bd88451SPaolo Bonzini         for (i = 0; i < 8; i ++)
4493bd88451SPaolo Bonzini             pxa2xx_timer_update4(s, now, i);
4503bd88451SPaolo Bonzini 
4513bd88451SPaolo Bonzini     return 0;
4523bd88451SPaolo Bonzini }
4533bd88451SPaolo Bonzini 
4545d83e348Sxiaoqiang.zhao static void pxa2xx_timer_init(Object *obj)
4553bd88451SPaolo Bonzini {
4565d83e348Sxiaoqiang.zhao     PXA2xxTimerInfo *s = PXA2XX_TIMER(obj);
4575d83e348Sxiaoqiang.zhao     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
4583bd88451SPaolo Bonzini 
4593bd88451SPaolo Bonzini     s->irq_enabled = 0;
4603bd88451SPaolo Bonzini     s->oldclock = 0;
4613bd88451SPaolo Bonzini     s->clock = 0;
462bc72ad67SAlex Bligh     s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
4633bd88451SPaolo Bonzini     s->reset3 = 0;
4643bd88451SPaolo Bonzini 
4655d83e348Sxiaoqiang.zhao     memory_region_init_io(&s->iomem, obj, &pxa2xx_timer_ops, s,
4665d83e348Sxiaoqiang.zhao                           "pxa2xx-timer", 0x00001000);
4675d83e348Sxiaoqiang.zhao     sysbus_init_mmio(dev, &s->iomem);
4685d83e348Sxiaoqiang.zhao }
4695d83e348Sxiaoqiang.zhao 
4705d83e348Sxiaoqiang.zhao static void pxa2xx_timer_realize(DeviceState *dev, Error **errp)
4715d83e348Sxiaoqiang.zhao {
4725d83e348Sxiaoqiang.zhao     PXA2xxTimerInfo *s = PXA2XX_TIMER(dev);
4735d83e348Sxiaoqiang.zhao     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
4745d83e348Sxiaoqiang.zhao     int i;
4755d83e348Sxiaoqiang.zhao 
4763bd88451SPaolo Bonzini     for (i = 0; i < 4; i ++) {
4773bd88451SPaolo Bonzini         s->timer[i].value = 0;
4785d83e348Sxiaoqiang.zhao         sysbus_init_irq(sbd, &s->timer[i].irq);
4793bd88451SPaolo Bonzini         s->timer[i].info = s;
4803bd88451SPaolo Bonzini         s->timer[i].num = i;
481bc72ad67SAlex Bligh         s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
4823bd88451SPaolo Bonzini                                           pxa2xx_timer_tick, &s->timer[i]);
4833bd88451SPaolo Bonzini     }
4845d83e348Sxiaoqiang.zhao 
4853bd88451SPaolo Bonzini     if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
4865d83e348Sxiaoqiang.zhao         sysbus_init_irq(sbd, &s->irq4);
4873bd88451SPaolo Bonzini 
4883bd88451SPaolo Bonzini         for (i = 0; i < 8; i ++) {
4893bd88451SPaolo Bonzini             s->tm4[i].tm.value = 0;
4903bd88451SPaolo Bonzini             s->tm4[i].tm.info = s;
4913bd88451SPaolo Bonzini             s->tm4[i].tm.num = i + 4;
4923bd88451SPaolo Bonzini             s->tm4[i].freq = 0;
4933bd88451SPaolo Bonzini             s->tm4[i].control = 0x0;
494bc72ad67SAlex Bligh             s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
4953bd88451SPaolo Bonzini                                                pxa2xx_timer_tick4, &s->tm4[i]);
4963bd88451SPaolo Bonzini         }
4973bd88451SPaolo Bonzini     }
4983bd88451SPaolo Bonzini }
4993bd88451SPaolo Bonzini 
5003bd88451SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
5013bd88451SPaolo Bonzini     .name = "pxa2xx_timer0",
5023bd88451SPaolo Bonzini     .version_id = 2,
5033bd88451SPaolo Bonzini     .minimum_version_id = 2,
5043bd88451SPaolo Bonzini     .fields = (VMStateField[]) {
5053bd88451SPaolo Bonzini         VMSTATE_UINT32(value, PXA2xxTimer0),
5063bd88451SPaolo Bonzini         VMSTATE_END_OF_LIST(),
5073bd88451SPaolo Bonzini     },
5083bd88451SPaolo Bonzini };
5093bd88451SPaolo Bonzini 
5103bd88451SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
5113bd88451SPaolo Bonzini     .name = "pxa2xx_timer4",
5123bd88451SPaolo Bonzini     .version_id = 1,
5133bd88451SPaolo Bonzini     .minimum_version_id = 1,
5143bd88451SPaolo Bonzini     .fields = (VMStateField[]) {
5153bd88451SPaolo Bonzini         VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
5163bd88451SPaolo Bonzini                         vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
5173bd88451SPaolo Bonzini         VMSTATE_INT32(oldclock, PXA2xxTimer4),
5183bd88451SPaolo Bonzini         VMSTATE_INT32(clock, PXA2xxTimer4),
5193bd88451SPaolo Bonzini         VMSTATE_UINT64(lastload, PXA2xxTimer4),
5203bd88451SPaolo Bonzini         VMSTATE_UINT32(freq, PXA2xxTimer4),
5213bd88451SPaolo Bonzini         VMSTATE_UINT32(control, PXA2xxTimer4),
5223bd88451SPaolo Bonzini         VMSTATE_END_OF_LIST(),
5233bd88451SPaolo Bonzini     },
5243bd88451SPaolo Bonzini };
5253bd88451SPaolo Bonzini 
5263bd88451SPaolo Bonzini static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
5273bd88451SPaolo Bonzini {
5283bd88451SPaolo Bonzini     return pxa2xx_timer_has_tm4(opaque);
5293bd88451SPaolo Bonzini }
5303bd88451SPaolo Bonzini 
5313bd88451SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_timer_regs = {
5323bd88451SPaolo Bonzini     .name = "pxa2xx_timer",
5333bd88451SPaolo Bonzini     .version_id = 1,
5343bd88451SPaolo Bonzini     .minimum_version_id = 1,
5353bd88451SPaolo Bonzini     .post_load = pxa25x_timer_post_load,
5363bd88451SPaolo Bonzini     .fields = (VMStateField[]) {
5373bd88451SPaolo Bonzini         VMSTATE_INT32(clock, PXA2xxTimerInfo),
5383bd88451SPaolo Bonzini         VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
5393bd88451SPaolo Bonzini         VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
5403bd88451SPaolo Bonzini         VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
5413bd88451SPaolo Bonzini                         vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
5423bd88451SPaolo Bonzini         VMSTATE_UINT32(events, PXA2xxTimerInfo),
5433bd88451SPaolo Bonzini         VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
5443bd88451SPaolo Bonzini         VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
5453bd88451SPaolo Bonzini         VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
5463bd88451SPaolo Bonzini         VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
5473bd88451SPaolo Bonzini                         pxa2xx_timer_has_tm4_test, 0,
5483bd88451SPaolo Bonzini                         vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
5493bd88451SPaolo Bonzini         VMSTATE_END_OF_LIST(),
5503bd88451SPaolo Bonzini     }
5513bd88451SPaolo Bonzini };
5523bd88451SPaolo Bonzini 
5533bd88451SPaolo Bonzini static Property pxa25x_timer_dev_properties[] = {
5543bd88451SPaolo Bonzini     DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
5553bd88451SPaolo Bonzini     DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
5563bd88451SPaolo Bonzini                     PXA2XX_TIMER_HAVE_TM4, false),
5573bd88451SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
5583bd88451SPaolo Bonzini };
5593bd88451SPaolo Bonzini 
5603bd88451SPaolo Bonzini static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data)
5613bd88451SPaolo Bonzini {
5623bd88451SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
5633bd88451SPaolo Bonzini 
5643bd88451SPaolo Bonzini     dc->desc = "PXA25x timer";
565*4f67d30bSMarc-André Lureau     device_class_set_props(dc, pxa25x_timer_dev_properties);
5663bd88451SPaolo Bonzini }
5673bd88451SPaolo Bonzini 
5683bd88451SPaolo Bonzini static const TypeInfo pxa25x_timer_dev_info = {
5693bd88451SPaolo Bonzini     .name          = "pxa25x-timer",
570feea4361SAndreas Färber     .parent        = TYPE_PXA2XX_TIMER,
5713bd88451SPaolo Bonzini     .instance_size = sizeof(PXA2xxTimerInfo),
5723bd88451SPaolo Bonzini     .class_init    = pxa25x_timer_dev_class_init,
5733bd88451SPaolo Bonzini };
5743bd88451SPaolo Bonzini 
5753bd88451SPaolo Bonzini static Property pxa27x_timer_dev_properties[] = {
5763bd88451SPaolo Bonzini     DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
5773bd88451SPaolo Bonzini     DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
5783bd88451SPaolo Bonzini                     PXA2XX_TIMER_HAVE_TM4, true),
5793bd88451SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
5803bd88451SPaolo Bonzini };
5813bd88451SPaolo Bonzini 
5823bd88451SPaolo Bonzini static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
5833bd88451SPaolo Bonzini {
5843bd88451SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
5853bd88451SPaolo Bonzini 
5863bd88451SPaolo Bonzini     dc->desc = "PXA27x timer";
587*4f67d30bSMarc-André Lureau     device_class_set_props(dc, pxa27x_timer_dev_properties);
5883bd88451SPaolo Bonzini }
5893bd88451SPaolo Bonzini 
5903bd88451SPaolo Bonzini static const TypeInfo pxa27x_timer_dev_info = {
5913bd88451SPaolo Bonzini     .name          = "pxa27x-timer",
592feea4361SAndreas Färber     .parent        = TYPE_PXA2XX_TIMER,
5933bd88451SPaolo Bonzini     .instance_size = sizeof(PXA2xxTimerInfo),
5943bd88451SPaolo Bonzini     .class_init    = pxa27x_timer_dev_class_init,
5953bd88451SPaolo Bonzini };
5963bd88451SPaolo Bonzini 
597feea4361SAndreas Färber static void pxa2xx_timer_class_init(ObjectClass *oc, void *data)
598feea4361SAndreas Färber {
599feea4361SAndreas Färber     DeviceClass *dc = DEVICE_CLASS(oc);
600feea4361SAndreas Färber 
6015d83e348Sxiaoqiang.zhao     dc->realize  = pxa2xx_timer_realize;
602feea4361SAndreas Färber     dc->vmsd = &vmstate_pxa2xx_timer_regs;
603feea4361SAndreas Färber }
604feea4361SAndreas Färber 
605feea4361SAndreas Färber static const TypeInfo pxa2xx_timer_type_info = {
606feea4361SAndreas Färber     .name          = TYPE_PXA2XX_TIMER,
607feea4361SAndreas Färber     .parent        = TYPE_SYS_BUS_DEVICE,
608feea4361SAndreas Färber     .instance_size = sizeof(PXA2xxTimerInfo),
6095d83e348Sxiaoqiang.zhao     .instance_init = pxa2xx_timer_init,
610feea4361SAndreas Färber     .abstract      = true,
611feea4361SAndreas Färber     .class_init    = pxa2xx_timer_class_init,
612feea4361SAndreas Färber };
613feea4361SAndreas Färber 
6143bd88451SPaolo Bonzini static void pxa2xx_timer_register_types(void)
6153bd88451SPaolo Bonzini {
616feea4361SAndreas Färber     type_register_static(&pxa2xx_timer_type_info);
6173bd88451SPaolo Bonzini     type_register_static(&pxa25x_timer_dev_info);
6183bd88451SPaolo Bonzini     type_register_static(&pxa27x_timer_dev_info);
6193bd88451SPaolo Bonzini }
6203bd88451SPaolo Bonzini 
6213bd88451SPaolo Bonzini type_init(pxa2xx_timer_register_types)
622