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/sysbus.h"
16d6454270SMarkus Armbruster #include "migration/vmstate.h"
172ba63e4aSPhilippe Mathieu-Daudé #include "qemu/log.h"
180b8fa32fSMarkus Armbruster #include "qemu/module.h"
19db1015e9SEduardo Habkost #include "qom/object.h"
20*efabbc07SAbhiram Tilak #include "sysemu/watchdog.h"
213bd88451SPaolo Bonzini
223bd88451SPaolo Bonzini #define OSMR0 0x00
233bd88451SPaolo Bonzini #define OSMR1 0x04
243bd88451SPaolo Bonzini #define OSMR2 0x08
253bd88451SPaolo Bonzini #define OSMR3 0x0c
263bd88451SPaolo Bonzini #define OSMR4 0x80
273bd88451SPaolo Bonzini #define OSMR5 0x84
283bd88451SPaolo Bonzini #define OSMR6 0x88
293bd88451SPaolo Bonzini #define OSMR7 0x8c
303bd88451SPaolo Bonzini #define OSMR8 0x90
313bd88451SPaolo Bonzini #define OSMR9 0x94
323bd88451SPaolo Bonzini #define OSMR10 0x98
333bd88451SPaolo Bonzini #define OSMR11 0x9c
343bd88451SPaolo Bonzini #define OSCR 0x10 /* OS Timer Count */
353bd88451SPaolo Bonzini #define OSCR4 0x40
363bd88451SPaolo Bonzini #define OSCR5 0x44
373bd88451SPaolo Bonzini #define OSCR6 0x48
383bd88451SPaolo Bonzini #define OSCR7 0x4c
393bd88451SPaolo Bonzini #define OSCR8 0x50
403bd88451SPaolo Bonzini #define OSCR9 0x54
413bd88451SPaolo Bonzini #define OSCR10 0x58
423bd88451SPaolo Bonzini #define OSCR11 0x5c
433bd88451SPaolo Bonzini #define OSSR 0x14 /* Timer status register */
443bd88451SPaolo Bonzini #define OWER 0x18
453bd88451SPaolo Bonzini #define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */
463bd88451SPaolo Bonzini #define OMCR4 0xc0 /* OS Match Control registers */
473bd88451SPaolo Bonzini #define OMCR5 0xc4
483bd88451SPaolo Bonzini #define OMCR6 0xc8
493bd88451SPaolo Bonzini #define OMCR7 0xcc
503bd88451SPaolo Bonzini #define OMCR8 0xd0
513bd88451SPaolo Bonzini #define OMCR9 0xd4
523bd88451SPaolo Bonzini #define OMCR10 0xd8
533bd88451SPaolo Bonzini #define OMCR11 0xdc
543bd88451SPaolo Bonzini #define OSNR 0x20
553bd88451SPaolo Bonzini
563bd88451SPaolo Bonzini #define PXA25X_FREQ 3686400 /* 3.6864 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"
698063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxTimerInfo, PXA2XX_TIMER)
70feea4361SAndreas Färber
713bd88451SPaolo Bonzini
723bd88451SPaolo Bonzini typedef struct {
733bd88451SPaolo Bonzini uint32_t value;
743bd88451SPaolo Bonzini qemu_irq irq;
753bd88451SPaolo Bonzini QEMUTimer *qtimer;
763bd88451SPaolo Bonzini int num;
773bd88451SPaolo Bonzini PXA2xxTimerInfo *info;
783bd88451SPaolo Bonzini } PXA2xxTimer0;
793bd88451SPaolo Bonzini
803bd88451SPaolo Bonzini typedef struct {
813bd88451SPaolo Bonzini PXA2xxTimer0 tm;
823bd88451SPaolo Bonzini int32_t oldclock;
833bd88451SPaolo Bonzini int32_t clock;
843bd88451SPaolo Bonzini uint64_t lastload;
853bd88451SPaolo Bonzini uint32_t freq;
863bd88451SPaolo Bonzini uint32_t control;
873bd88451SPaolo Bonzini } PXA2xxTimer4;
883bd88451SPaolo Bonzini
893bd88451SPaolo Bonzini struct PXA2xxTimerInfo {
90feea4361SAndreas Färber SysBusDevice parent_obj;
91feea4361SAndreas Färber
923bd88451SPaolo Bonzini MemoryRegion iomem;
933bd88451SPaolo Bonzini uint32_t flags;
943bd88451SPaolo Bonzini
953bd88451SPaolo Bonzini int32_t clock;
963bd88451SPaolo Bonzini int32_t oldclock;
973bd88451SPaolo Bonzini uint64_t lastload;
983bd88451SPaolo Bonzini uint32_t freq;
993bd88451SPaolo Bonzini PXA2xxTimer0 timer[4];
1003bd88451SPaolo Bonzini uint32_t events;
1013bd88451SPaolo Bonzini uint32_t irq_enabled;
1023bd88451SPaolo Bonzini uint32_t reset3;
1033bd88451SPaolo Bonzini uint32_t snapshot;
1043bd88451SPaolo Bonzini
1053bd88451SPaolo Bonzini qemu_irq irq4;
1063bd88451SPaolo Bonzini PXA2xxTimer4 tm4[8];
1073bd88451SPaolo Bonzini };
1083bd88451SPaolo Bonzini
1093bd88451SPaolo Bonzini #define PXA2XX_TIMER_HAVE_TM4 0
1103bd88451SPaolo Bonzini
pxa2xx_timer_has_tm4(PXA2xxTimerInfo * s)1113bd88451SPaolo Bonzini static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
1123bd88451SPaolo Bonzini {
1133bd88451SPaolo Bonzini return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
1143bd88451SPaolo Bonzini }
1153bd88451SPaolo Bonzini
pxa2xx_timer_update(void * opaque,uint64_t now_qemu)1163bd88451SPaolo Bonzini static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
1173bd88451SPaolo Bonzini {
1183bd88451SPaolo Bonzini PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
1193bd88451SPaolo Bonzini int i;
1203bd88451SPaolo Bonzini uint32_t now_vm;
1213bd88451SPaolo Bonzini uint64_t new_qemu;
1223bd88451SPaolo Bonzini
1233bd88451SPaolo Bonzini now_vm = s->clock +
12473bcb24dSRutuja Shah muldiv64(now_qemu - s->lastload, s->freq, NANOSECONDS_PER_SECOND);
1253bd88451SPaolo Bonzini
1263bd88451SPaolo Bonzini for (i = 0; i < 4; i ++) {
1273bd88451SPaolo Bonzini new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
12873bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, s->freq);
129bc72ad67SAlex Bligh timer_mod(s->timer[i].qtimer, new_qemu);
1303bd88451SPaolo Bonzini }
1313bd88451SPaolo Bonzini }
1323bd88451SPaolo Bonzini
pxa2xx_timer_update4(void * opaque,uint64_t now_qemu,int n)1333bd88451SPaolo Bonzini static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
1343bd88451SPaolo Bonzini {
1353bd88451SPaolo Bonzini PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
1363bd88451SPaolo Bonzini uint32_t now_vm;
1373bd88451SPaolo Bonzini uint64_t new_qemu;
1383bd88451SPaolo Bonzini static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
1393bd88451SPaolo Bonzini int counter;
1403bd88451SPaolo Bonzini
141e702fba8SPhilippe Mathieu-Daudé assert(n < ARRAY_SIZE(counters));
1423bd88451SPaolo Bonzini if (s->tm4[n].control & (1 << 7))
1433bd88451SPaolo Bonzini counter = n;
1443bd88451SPaolo Bonzini else
1453bd88451SPaolo Bonzini counter = counters[n];
1463bd88451SPaolo Bonzini
1473bd88451SPaolo Bonzini if (!s->tm4[counter].freq) {
148bc72ad67SAlex Bligh timer_del(s->tm4[n].tm.qtimer);
1493bd88451SPaolo Bonzini return;
1503bd88451SPaolo Bonzini }
1513bd88451SPaolo Bonzini
1523bd88451SPaolo Bonzini now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
1533bd88451SPaolo Bonzini s->tm4[counter].lastload,
15473bcb24dSRutuja Shah s->tm4[counter].freq, NANOSECONDS_PER_SECOND);
1553bd88451SPaolo Bonzini
1563bd88451SPaolo Bonzini new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
15773bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, s->tm4[counter].freq);
158bc72ad67SAlex Bligh timer_mod(s->tm4[n].tm.qtimer, new_qemu);
1593bd88451SPaolo Bonzini }
1603bd88451SPaolo Bonzini
pxa2xx_timer_read(void * opaque,hwaddr offset,unsigned size)1613bd88451SPaolo Bonzini static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset,
1623bd88451SPaolo Bonzini unsigned size)
1633bd88451SPaolo Bonzini {
1643bd88451SPaolo Bonzini PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
1653bd88451SPaolo Bonzini int tm = 0;
1663bd88451SPaolo Bonzini
1673bd88451SPaolo Bonzini switch (offset) {
1683bd88451SPaolo Bonzini case OSMR3: tm ++;
1693bd88451SPaolo Bonzini /* fall through */
1703bd88451SPaolo Bonzini case OSMR2: tm ++;
1713bd88451SPaolo Bonzini /* fall through */
1723bd88451SPaolo Bonzini case OSMR1: tm ++;
1733bd88451SPaolo Bonzini /* fall through */
1743bd88451SPaolo Bonzini case OSMR0:
1753bd88451SPaolo Bonzini return s->timer[tm].value;
1763bd88451SPaolo Bonzini case OSMR11: tm ++;
1773bd88451SPaolo Bonzini /* fall through */
1783bd88451SPaolo Bonzini case OSMR10: tm ++;
1793bd88451SPaolo Bonzini /* fall through */
1803bd88451SPaolo Bonzini case OSMR9: tm ++;
1813bd88451SPaolo Bonzini /* fall through */
1823bd88451SPaolo Bonzini case OSMR8: tm ++;
1833bd88451SPaolo Bonzini /* fall through */
1843bd88451SPaolo Bonzini case OSMR7: tm ++;
1853bd88451SPaolo Bonzini /* fall through */
1863bd88451SPaolo Bonzini case OSMR6: tm ++;
1873bd88451SPaolo Bonzini /* fall through */
1883bd88451SPaolo Bonzini case OSMR5: tm ++;
1893bd88451SPaolo Bonzini /* fall through */
1903bd88451SPaolo Bonzini case OSMR4:
1913bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s))
1923bd88451SPaolo Bonzini goto badreg;
1933bd88451SPaolo Bonzini return s->tm4[tm].tm.value;
1943bd88451SPaolo Bonzini case OSCR:
195bc72ad67SAlex Bligh return s->clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
19673bcb24dSRutuja Shah s->lastload, s->freq, NANOSECONDS_PER_SECOND);
1973bd88451SPaolo Bonzini case OSCR11: tm ++;
1983bd88451SPaolo Bonzini /* fall through */
1993bd88451SPaolo Bonzini case OSCR10: tm ++;
2003bd88451SPaolo Bonzini /* fall through */
2013bd88451SPaolo Bonzini case OSCR9: tm ++;
2023bd88451SPaolo Bonzini /* fall through */
2033bd88451SPaolo Bonzini case OSCR8: tm ++;
2043bd88451SPaolo Bonzini /* fall through */
2053bd88451SPaolo Bonzini case OSCR7: tm ++;
2063bd88451SPaolo Bonzini /* fall through */
2073bd88451SPaolo Bonzini case OSCR6: tm ++;
2083bd88451SPaolo Bonzini /* fall through */
2093bd88451SPaolo Bonzini case OSCR5: tm ++;
2103bd88451SPaolo Bonzini /* fall through */
2113bd88451SPaolo Bonzini case OSCR4:
2123bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s))
2133bd88451SPaolo Bonzini goto badreg;
2143bd88451SPaolo Bonzini
2153bd88451SPaolo Bonzini if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
2163bd88451SPaolo Bonzini if (s->tm4[tm - 1].freq)
2173bd88451SPaolo Bonzini s->snapshot = s->tm4[tm - 1].clock + muldiv64(
218bc72ad67SAlex Bligh qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
2193bd88451SPaolo Bonzini s->tm4[tm - 1].lastload,
22073bcb24dSRutuja Shah s->tm4[tm - 1].freq, NANOSECONDS_PER_SECOND);
2213bd88451SPaolo Bonzini else
2223bd88451SPaolo Bonzini s->snapshot = s->tm4[tm - 1].clock;
2233bd88451SPaolo Bonzini }
2243bd88451SPaolo Bonzini
2253bd88451SPaolo Bonzini if (!s->tm4[tm].freq)
2263bd88451SPaolo Bonzini return s->tm4[tm].clock;
22773bcb24dSRutuja Shah return s->tm4[tm].clock +
22873bcb24dSRutuja Shah muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
22973bcb24dSRutuja Shah s->tm4[tm].lastload, s->tm4[tm].freq,
23073bcb24dSRutuja Shah NANOSECONDS_PER_SECOND);
2313bd88451SPaolo Bonzini case OIER:
2323bd88451SPaolo Bonzini return s->irq_enabled;
2333bd88451SPaolo Bonzini case OSSR: /* Status register */
2343bd88451SPaolo Bonzini return s->events;
2353bd88451SPaolo Bonzini case OWER:
2363bd88451SPaolo Bonzini return s->reset3;
2373bd88451SPaolo Bonzini case OMCR11: tm ++;
2383bd88451SPaolo Bonzini /* fall through */
2393bd88451SPaolo Bonzini case OMCR10: tm ++;
2403bd88451SPaolo Bonzini /* fall through */
2413bd88451SPaolo Bonzini case OMCR9: tm ++;
2423bd88451SPaolo Bonzini /* fall through */
2433bd88451SPaolo Bonzini case OMCR8: tm ++;
2443bd88451SPaolo Bonzini /* fall through */
2453bd88451SPaolo Bonzini case OMCR7: tm ++;
2463bd88451SPaolo Bonzini /* fall through */
2473bd88451SPaolo Bonzini case OMCR6: tm ++;
2483bd88451SPaolo Bonzini /* fall through */
2493bd88451SPaolo Bonzini case OMCR5: tm ++;
2503bd88451SPaolo Bonzini /* fall through */
2513bd88451SPaolo Bonzini case OMCR4:
2523bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s))
2533bd88451SPaolo Bonzini goto badreg;
2543bd88451SPaolo Bonzini return s->tm4[tm].control;
2553bd88451SPaolo Bonzini case OSNR:
2563bd88451SPaolo Bonzini return s->snapshot;
2573bd88451SPaolo Bonzini default:
2582ba63e4aSPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP,
2592ba63e4aSPhilippe Mathieu-Daudé "%s: unknown register 0x%02" HWADDR_PRIx "\n",
2602ba63e4aSPhilippe Mathieu-Daudé __func__, offset);
2612ba63e4aSPhilippe Mathieu-Daudé break;
2623bd88451SPaolo Bonzini badreg:
2632ba63e4aSPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR,
2642ba63e4aSPhilippe Mathieu-Daudé "%s: incorrect register 0x%02" HWADDR_PRIx "\n",
2652ba63e4aSPhilippe Mathieu-Daudé __func__, offset);
2663bd88451SPaolo Bonzini }
2673bd88451SPaolo Bonzini
2683bd88451SPaolo Bonzini return 0;
2693bd88451SPaolo Bonzini }
2703bd88451SPaolo Bonzini
pxa2xx_timer_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)2713bd88451SPaolo Bonzini static void pxa2xx_timer_write(void *opaque, hwaddr offset,
2723bd88451SPaolo Bonzini uint64_t value, unsigned size)
2733bd88451SPaolo Bonzini {
2743bd88451SPaolo Bonzini int i, tm = 0;
2753bd88451SPaolo Bonzini PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
2763bd88451SPaolo Bonzini
2773bd88451SPaolo Bonzini switch (offset) {
2783bd88451SPaolo Bonzini case OSMR3: tm ++;
2793bd88451SPaolo Bonzini /* fall through */
2803bd88451SPaolo Bonzini case OSMR2: tm ++;
2813bd88451SPaolo Bonzini /* fall through */
2823bd88451SPaolo Bonzini case OSMR1: tm ++;
2833bd88451SPaolo Bonzini /* fall through */
2843bd88451SPaolo Bonzini case OSMR0:
2853bd88451SPaolo Bonzini s->timer[tm].value = value;
286bc72ad67SAlex Bligh pxa2xx_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
2873bd88451SPaolo Bonzini break;
2883bd88451SPaolo Bonzini case OSMR11: tm ++;
2893bd88451SPaolo Bonzini /* fall through */
2903bd88451SPaolo Bonzini case OSMR10: tm ++;
2913bd88451SPaolo Bonzini /* fall through */
2923bd88451SPaolo Bonzini case OSMR9: tm ++;
2933bd88451SPaolo Bonzini /* fall through */
2943bd88451SPaolo Bonzini case OSMR8: tm ++;
2953bd88451SPaolo Bonzini /* fall through */
2963bd88451SPaolo Bonzini case OSMR7: tm ++;
2973bd88451SPaolo Bonzini /* fall through */
2983bd88451SPaolo Bonzini case OSMR6: tm ++;
2993bd88451SPaolo Bonzini /* fall through */
3003bd88451SPaolo Bonzini case OSMR5: tm ++;
3013bd88451SPaolo Bonzini /* fall through */
3023bd88451SPaolo Bonzini case OSMR4:
3033bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s))
3043bd88451SPaolo Bonzini goto badreg;
3053bd88451SPaolo Bonzini s->tm4[tm].tm.value = value;
306bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
3073bd88451SPaolo Bonzini break;
3083bd88451SPaolo Bonzini case OSCR:
3093bd88451SPaolo Bonzini s->oldclock = s->clock;
310bc72ad67SAlex Bligh s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3113bd88451SPaolo Bonzini s->clock = value;
3123bd88451SPaolo Bonzini pxa2xx_timer_update(s, s->lastload);
3133bd88451SPaolo Bonzini break;
3143bd88451SPaolo Bonzini case OSCR11: tm ++;
3153bd88451SPaolo Bonzini /* fall through */
3163bd88451SPaolo Bonzini case OSCR10: tm ++;
3173bd88451SPaolo Bonzini /* fall through */
3183bd88451SPaolo Bonzini case OSCR9: tm ++;
3193bd88451SPaolo Bonzini /* fall through */
3203bd88451SPaolo Bonzini case OSCR8: tm ++;
3213bd88451SPaolo Bonzini /* fall through */
3223bd88451SPaolo Bonzini case OSCR7: tm ++;
3233bd88451SPaolo Bonzini /* fall through */
3243bd88451SPaolo Bonzini case OSCR6: tm ++;
3253bd88451SPaolo Bonzini /* fall through */
3263bd88451SPaolo Bonzini case OSCR5: tm ++;
3273bd88451SPaolo Bonzini /* fall through */
3283bd88451SPaolo Bonzini case OSCR4:
3293bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s))
3303bd88451SPaolo Bonzini goto badreg;
3313bd88451SPaolo Bonzini s->tm4[tm].oldclock = s->tm4[tm].clock;
332bc72ad67SAlex Bligh s->tm4[tm].lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3333bd88451SPaolo Bonzini s->tm4[tm].clock = value;
3343bd88451SPaolo Bonzini pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
3353bd88451SPaolo Bonzini break;
3363bd88451SPaolo Bonzini case OIER:
3373bd88451SPaolo Bonzini s->irq_enabled = value & 0xfff;
3383bd88451SPaolo Bonzini break;
3393bd88451SPaolo Bonzini case OSSR: /* Status register */
3403bd88451SPaolo Bonzini value &= s->events;
3413bd88451SPaolo Bonzini s->events &= ~value;
3423bd88451SPaolo Bonzini for (i = 0; i < 4; i ++, value >>= 1)
3433bd88451SPaolo Bonzini if (value & 1)
3443bd88451SPaolo Bonzini qemu_irq_lower(s->timer[i].irq);
3453bd88451SPaolo Bonzini if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
3463bd88451SPaolo Bonzini qemu_irq_lower(s->irq4);
3473bd88451SPaolo Bonzini break;
3483bd88451SPaolo Bonzini case OWER: /* XXX: Reset on OSMR3 match? */
3493bd88451SPaolo Bonzini s->reset3 = value;
3503bd88451SPaolo Bonzini break;
3513bd88451SPaolo Bonzini case OMCR7: tm ++;
3523bd88451SPaolo Bonzini /* fall through */
3533bd88451SPaolo Bonzini case OMCR6: tm ++;
3543bd88451SPaolo Bonzini /* fall through */
3553bd88451SPaolo Bonzini case OMCR5: tm ++;
3563bd88451SPaolo Bonzini /* fall through */
3573bd88451SPaolo Bonzini case OMCR4:
3583bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s))
3593bd88451SPaolo Bonzini goto badreg;
3603bd88451SPaolo Bonzini s->tm4[tm].control = value & 0x0ff;
3613bd88451SPaolo Bonzini /* XXX Stop if running (shouldn't happen) */
3623bd88451SPaolo Bonzini if ((value & (1 << 7)) || tm == 0)
3633bd88451SPaolo Bonzini s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
3643bd88451SPaolo Bonzini else {
3653bd88451SPaolo Bonzini s->tm4[tm].freq = 0;
366bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
3673bd88451SPaolo Bonzini }
3683bd88451SPaolo Bonzini break;
3693bd88451SPaolo Bonzini case OMCR11: tm ++;
3703bd88451SPaolo Bonzini /* fall through */
3713bd88451SPaolo Bonzini case OMCR10: tm ++;
3723bd88451SPaolo Bonzini /* fall through */
3733bd88451SPaolo Bonzini case OMCR9: tm ++;
3743bd88451SPaolo Bonzini /* fall through */
3753bd88451SPaolo Bonzini case OMCR8: tm += 4;
3763bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s))
3773bd88451SPaolo Bonzini goto badreg;
3783bd88451SPaolo Bonzini s->tm4[tm].control = value & 0x3ff;
3793bd88451SPaolo Bonzini /* XXX Stop if running (shouldn't happen) */
3803bd88451SPaolo Bonzini if ((value & (1 << 7)) || !(tm & 1))
3813bd88451SPaolo Bonzini s->tm4[tm].freq =
3823bd88451SPaolo Bonzini pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)];
3833bd88451SPaolo Bonzini else {
3843bd88451SPaolo Bonzini s->tm4[tm].freq = 0;
385bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
3863bd88451SPaolo Bonzini }
3873bd88451SPaolo Bonzini break;
3883bd88451SPaolo Bonzini default:
3892ba63e4aSPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP,
3902ba63e4aSPhilippe Mathieu-Daudé "%s: unknown register 0x%02" HWADDR_PRIx " "
3912ba63e4aSPhilippe Mathieu-Daudé "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
3922ba63e4aSPhilippe Mathieu-Daudé break;
3933bd88451SPaolo Bonzini badreg:
3942ba63e4aSPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR,
3952ba63e4aSPhilippe Mathieu-Daudé "%s: incorrect register 0x%02" HWADDR_PRIx " "
3962ba63e4aSPhilippe Mathieu-Daudé "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
3973bd88451SPaolo Bonzini }
3983bd88451SPaolo Bonzini }
3993bd88451SPaolo Bonzini
4003bd88451SPaolo Bonzini static const MemoryRegionOps pxa2xx_timer_ops = {
4013bd88451SPaolo Bonzini .read = pxa2xx_timer_read,
4023bd88451SPaolo Bonzini .write = pxa2xx_timer_write,
4033bd88451SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
4043bd88451SPaolo Bonzini };
4053bd88451SPaolo Bonzini
pxa2xx_timer_tick(void * opaque)4063bd88451SPaolo Bonzini static void pxa2xx_timer_tick(void *opaque)
4073bd88451SPaolo Bonzini {
4083bd88451SPaolo Bonzini PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
4093bd88451SPaolo Bonzini PXA2xxTimerInfo *i = t->info;
4103bd88451SPaolo Bonzini
4113bd88451SPaolo Bonzini if (i->irq_enabled & (1 << t->num)) {
4123bd88451SPaolo Bonzini i->events |= 1 << t->num;
4133bd88451SPaolo Bonzini qemu_irq_raise(t->irq);
4143bd88451SPaolo Bonzini }
4153bd88451SPaolo Bonzini
4163bd88451SPaolo Bonzini if (t->num == 3)
4173bd88451SPaolo Bonzini if (i->reset3 & 1) {
4183bd88451SPaolo Bonzini i->reset3 = 0;
419*efabbc07SAbhiram Tilak watchdog_perform_action();
4203bd88451SPaolo Bonzini }
4213bd88451SPaolo Bonzini }
4223bd88451SPaolo Bonzini
pxa2xx_timer_tick4(void * opaque)4233bd88451SPaolo Bonzini static void pxa2xx_timer_tick4(void *opaque)
4243bd88451SPaolo Bonzini {
4253bd88451SPaolo Bonzini PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
4263bd88451SPaolo Bonzini PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
4273bd88451SPaolo Bonzini
4283bd88451SPaolo Bonzini pxa2xx_timer_tick(&t->tm);
4293bd88451SPaolo Bonzini if (t->control & (1 << 3))
4303bd88451SPaolo Bonzini t->clock = 0;
4313bd88451SPaolo Bonzini if (t->control & (1 << 6))
432bc72ad67SAlex Bligh pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4);
4333bd88451SPaolo Bonzini if (i->events & 0xff0)
4343bd88451SPaolo Bonzini qemu_irq_raise(i->irq4);
4353bd88451SPaolo Bonzini }
4363bd88451SPaolo Bonzini
pxa25x_timer_post_load(void * opaque,int version_id)4373bd88451SPaolo Bonzini static int pxa25x_timer_post_load(void *opaque, int version_id)
4383bd88451SPaolo Bonzini {
4393bd88451SPaolo Bonzini PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
4403bd88451SPaolo Bonzini int64_t now;
4413bd88451SPaolo Bonzini int i;
4423bd88451SPaolo Bonzini
443bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
4443bd88451SPaolo Bonzini pxa2xx_timer_update(s, now);
4453bd88451SPaolo Bonzini
4463bd88451SPaolo Bonzini if (pxa2xx_timer_has_tm4(s))
4473bd88451SPaolo Bonzini for (i = 0; i < 8; i ++)
4483bd88451SPaolo Bonzini pxa2xx_timer_update4(s, now, i);
4493bd88451SPaolo Bonzini
4503bd88451SPaolo Bonzini return 0;
4513bd88451SPaolo Bonzini }
4523bd88451SPaolo Bonzini
pxa2xx_timer_init(Object * obj)4535d83e348Sxiaoqiang.zhao static void pxa2xx_timer_init(Object *obj)
4543bd88451SPaolo Bonzini {
4555d83e348Sxiaoqiang.zhao PXA2xxTimerInfo *s = PXA2XX_TIMER(obj);
4565d83e348Sxiaoqiang.zhao SysBusDevice *dev = SYS_BUS_DEVICE(obj);
4573bd88451SPaolo Bonzini
4583bd88451SPaolo Bonzini s->irq_enabled = 0;
4593bd88451SPaolo Bonzini s->oldclock = 0;
4603bd88451SPaolo Bonzini s->clock = 0;
461bc72ad67SAlex Bligh s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
4623bd88451SPaolo Bonzini s->reset3 = 0;
4633bd88451SPaolo Bonzini
4645d83e348Sxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &pxa2xx_timer_ops, s,
4655d83e348Sxiaoqiang.zhao "pxa2xx-timer", 0x00001000);
4665d83e348Sxiaoqiang.zhao sysbus_init_mmio(dev, &s->iomem);
4675d83e348Sxiaoqiang.zhao }
4685d83e348Sxiaoqiang.zhao
pxa2xx_timer_realize(DeviceState * dev,Error ** errp)4695d83e348Sxiaoqiang.zhao static void pxa2xx_timer_realize(DeviceState *dev, Error **errp)
4705d83e348Sxiaoqiang.zhao {
4715d83e348Sxiaoqiang.zhao PXA2xxTimerInfo *s = PXA2XX_TIMER(dev);
4725d83e348Sxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
4735d83e348Sxiaoqiang.zhao int i;
4745d83e348Sxiaoqiang.zhao
4753bd88451SPaolo Bonzini for (i = 0; i < 4; i ++) {
4763bd88451SPaolo Bonzini s->timer[i].value = 0;
4775d83e348Sxiaoqiang.zhao sysbus_init_irq(sbd, &s->timer[i].irq);
4783bd88451SPaolo Bonzini s->timer[i].info = s;
4793bd88451SPaolo Bonzini s->timer[i].num = i;
480bc72ad67SAlex Bligh s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
4813bd88451SPaolo Bonzini pxa2xx_timer_tick, &s->timer[i]);
4823bd88451SPaolo Bonzini }
4835d83e348Sxiaoqiang.zhao
4843bd88451SPaolo Bonzini if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
4855d83e348Sxiaoqiang.zhao sysbus_init_irq(sbd, &s->irq4);
4863bd88451SPaolo Bonzini
4873bd88451SPaolo Bonzini for (i = 0; i < 8; i ++) {
4883bd88451SPaolo Bonzini s->tm4[i].tm.value = 0;
4893bd88451SPaolo Bonzini s->tm4[i].tm.info = s;
4903bd88451SPaolo Bonzini s->tm4[i].tm.num = i + 4;
4913bd88451SPaolo Bonzini s->tm4[i].freq = 0;
4923bd88451SPaolo Bonzini s->tm4[i].control = 0x0;
493bc72ad67SAlex Bligh s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
4943bd88451SPaolo Bonzini pxa2xx_timer_tick4, &s->tm4[i]);
4953bd88451SPaolo Bonzini }
4963bd88451SPaolo Bonzini }
4973bd88451SPaolo Bonzini }
4983bd88451SPaolo Bonzini
4993bd88451SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
5003bd88451SPaolo Bonzini .name = "pxa2xx_timer0",
5013bd88451SPaolo Bonzini .version_id = 2,
5023bd88451SPaolo Bonzini .minimum_version_id = 2,
503ba324b3fSRichard Henderson .fields = (const VMStateField[]) {
5043bd88451SPaolo Bonzini VMSTATE_UINT32(value, PXA2xxTimer0),
5053bd88451SPaolo Bonzini VMSTATE_END_OF_LIST(),
5063bd88451SPaolo Bonzini },
5073bd88451SPaolo Bonzini };
5083bd88451SPaolo Bonzini
5093bd88451SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
5103bd88451SPaolo Bonzini .name = "pxa2xx_timer4",
5113bd88451SPaolo Bonzini .version_id = 1,
5123bd88451SPaolo Bonzini .minimum_version_id = 1,
513ba324b3fSRichard Henderson .fields = (const VMStateField[]) {
5143bd88451SPaolo Bonzini VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
5153bd88451SPaolo Bonzini vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
5163bd88451SPaolo Bonzini VMSTATE_INT32(oldclock, PXA2xxTimer4),
5173bd88451SPaolo Bonzini VMSTATE_INT32(clock, PXA2xxTimer4),
5183bd88451SPaolo Bonzini VMSTATE_UINT64(lastload, PXA2xxTimer4),
5193bd88451SPaolo Bonzini VMSTATE_UINT32(freq, PXA2xxTimer4),
5203bd88451SPaolo Bonzini VMSTATE_UINT32(control, PXA2xxTimer4),
5213bd88451SPaolo Bonzini VMSTATE_END_OF_LIST(),
5223bd88451SPaolo Bonzini },
5233bd88451SPaolo Bonzini };
5243bd88451SPaolo Bonzini
pxa2xx_timer_has_tm4_test(void * opaque,int version_id)5253bd88451SPaolo Bonzini static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
5263bd88451SPaolo Bonzini {
5273bd88451SPaolo Bonzini return pxa2xx_timer_has_tm4(opaque);
5283bd88451SPaolo Bonzini }
5293bd88451SPaolo Bonzini
5303bd88451SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_timer_regs = {
5313bd88451SPaolo Bonzini .name = "pxa2xx_timer",
5323bd88451SPaolo Bonzini .version_id = 1,
5333bd88451SPaolo Bonzini .minimum_version_id = 1,
5343bd88451SPaolo Bonzini .post_load = pxa25x_timer_post_load,
535ba324b3fSRichard Henderson .fields = (const VMStateField[]) {
5363bd88451SPaolo Bonzini VMSTATE_INT32(clock, PXA2xxTimerInfo),
5373bd88451SPaolo Bonzini VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
5383bd88451SPaolo Bonzini VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
5393bd88451SPaolo Bonzini VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
5403bd88451SPaolo Bonzini vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
5413bd88451SPaolo Bonzini VMSTATE_UINT32(events, PXA2xxTimerInfo),
5423bd88451SPaolo Bonzini VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
5433bd88451SPaolo Bonzini VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
5443bd88451SPaolo Bonzini VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
5453bd88451SPaolo Bonzini VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
5463bd88451SPaolo Bonzini pxa2xx_timer_has_tm4_test, 0,
5473bd88451SPaolo Bonzini vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
5483bd88451SPaolo Bonzini VMSTATE_END_OF_LIST(),
5493bd88451SPaolo Bonzini }
5503bd88451SPaolo Bonzini };
5513bd88451SPaolo Bonzini
5523bd88451SPaolo Bonzini static Property pxa25x_timer_dev_properties[] = {
5533bd88451SPaolo Bonzini DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
5543bd88451SPaolo Bonzini DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
5553bd88451SPaolo Bonzini PXA2XX_TIMER_HAVE_TM4, false),
5563bd88451SPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
5573bd88451SPaolo Bonzini };
5583bd88451SPaolo Bonzini
pxa25x_timer_dev_class_init(ObjectClass * klass,void * data)5593bd88451SPaolo Bonzini static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data)
5603bd88451SPaolo Bonzini {
5613bd88451SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
5623bd88451SPaolo Bonzini
5633bd88451SPaolo Bonzini dc->desc = "PXA25x timer";
5644f67d30bSMarc-André Lureau device_class_set_props(dc, pxa25x_timer_dev_properties);
5653bd88451SPaolo Bonzini }
5663bd88451SPaolo Bonzini
5673bd88451SPaolo Bonzini static const TypeInfo pxa25x_timer_dev_info = {
5683bd88451SPaolo Bonzini .name = "pxa25x-timer",
569feea4361SAndreas Färber .parent = TYPE_PXA2XX_TIMER,
5703bd88451SPaolo Bonzini .instance_size = sizeof(PXA2xxTimerInfo),
5713bd88451SPaolo Bonzini .class_init = pxa25x_timer_dev_class_init,
5723bd88451SPaolo Bonzini };
5733bd88451SPaolo Bonzini
pxa2xx_timer_class_init(ObjectClass * oc,void * data)574feea4361SAndreas Färber static void pxa2xx_timer_class_init(ObjectClass *oc, void *data)
575feea4361SAndreas Färber {
576feea4361SAndreas Färber DeviceClass *dc = DEVICE_CLASS(oc);
577feea4361SAndreas Färber
5785d83e348Sxiaoqiang.zhao dc->realize = pxa2xx_timer_realize;
579feea4361SAndreas Färber dc->vmsd = &vmstate_pxa2xx_timer_regs;
580feea4361SAndreas Färber }
581feea4361SAndreas Färber
582feea4361SAndreas Färber static const TypeInfo pxa2xx_timer_type_info = {
583feea4361SAndreas Färber .name = TYPE_PXA2XX_TIMER,
584feea4361SAndreas Färber .parent = TYPE_SYS_BUS_DEVICE,
585feea4361SAndreas Färber .instance_size = sizeof(PXA2xxTimerInfo),
5865d83e348Sxiaoqiang.zhao .instance_init = pxa2xx_timer_init,
587feea4361SAndreas Färber .abstract = true,
588feea4361SAndreas Färber .class_init = pxa2xx_timer_class_init,
589feea4361SAndreas Färber };
590feea4361SAndreas Färber
pxa2xx_timer_register_types(void)5913bd88451SPaolo Bonzini static void pxa2xx_timer_register_types(void)
5923bd88451SPaolo Bonzini {
593feea4361SAndreas Färber type_register_static(&pxa2xx_timer_type_info);
5943bd88451SPaolo Bonzini type_register_static(&pxa25x_timer_dev_info);
5953bd88451SPaolo Bonzini }
5963bd88451SPaolo Bonzini
5973bd88451SPaolo Bonzini type_init(pxa2xx_timer_register_types)
598