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 143*e702fba8SPhilippe Mathieu-Daudé assert(n < ARRAY_SIZE(counters)); 1443bd88451SPaolo Bonzini if (s->tm4[n].control & (1 << 7)) 1453bd88451SPaolo Bonzini counter = n; 1463bd88451SPaolo Bonzini else 1473bd88451SPaolo Bonzini counter = counters[n]; 1483bd88451SPaolo Bonzini 1493bd88451SPaolo Bonzini if (!s->tm4[counter].freq) { 150bc72ad67SAlex Bligh timer_del(s->tm4[n].tm.qtimer); 1513bd88451SPaolo Bonzini return; 1523bd88451SPaolo Bonzini } 1533bd88451SPaolo Bonzini 1543bd88451SPaolo Bonzini now_vm = s->tm4[counter].clock + muldiv64(now_qemu - 1553bd88451SPaolo Bonzini s->tm4[counter].lastload, 15673bcb24dSRutuja Shah s->tm4[counter].freq, NANOSECONDS_PER_SECOND); 1573bd88451SPaolo Bonzini 1583bd88451SPaolo Bonzini new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm), 15973bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, s->tm4[counter].freq); 160bc72ad67SAlex Bligh timer_mod(s->tm4[n].tm.qtimer, new_qemu); 1613bd88451SPaolo Bonzini } 1623bd88451SPaolo Bonzini 1633bd88451SPaolo Bonzini static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, 1643bd88451SPaolo Bonzini unsigned size) 1653bd88451SPaolo Bonzini { 1663bd88451SPaolo Bonzini PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 1673bd88451SPaolo Bonzini int tm = 0; 1683bd88451SPaolo Bonzini 1693bd88451SPaolo Bonzini switch (offset) { 1703bd88451SPaolo Bonzini case OSMR3: tm ++; 1713bd88451SPaolo Bonzini /* fall through */ 1723bd88451SPaolo Bonzini case OSMR2: tm ++; 1733bd88451SPaolo Bonzini /* fall through */ 1743bd88451SPaolo Bonzini case OSMR1: tm ++; 1753bd88451SPaolo Bonzini /* fall through */ 1763bd88451SPaolo Bonzini case OSMR0: 1773bd88451SPaolo Bonzini return s->timer[tm].value; 1783bd88451SPaolo Bonzini case OSMR11: tm ++; 1793bd88451SPaolo Bonzini /* fall through */ 1803bd88451SPaolo Bonzini case OSMR10: tm ++; 1813bd88451SPaolo Bonzini /* fall through */ 1823bd88451SPaolo Bonzini case OSMR9: tm ++; 1833bd88451SPaolo Bonzini /* fall through */ 1843bd88451SPaolo Bonzini case OSMR8: tm ++; 1853bd88451SPaolo Bonzini /* fall through */ 1863bd88451SPaolo Bonzini case OSMR7: tm ++; 1873bd88451SPaolo Bonzini /* fall through */ 1883bd88451SPaolo Bonzini case OSMR6: tm ++; 1893bd88451SPaolo Bonzini /* fall through */ 1903bd88451SPaolo Bonzini case OSMR5: tm ++; 1913bd88451SPaolo Bonzini /* fall through */ 1923bd88451SPaolo Bonzini case OSMR4: 1933bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s)) 1943bd88451SPaolo Bonzini goto badreg; 1953bd88451SPaolo Bonzini return s->tm4[tm].tm.value; 1963bd88451SPaolo Bonzini case OSCR: 197bc72ad67SAlex Bligh return s->clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - 19873bcb24dSRutuja Shah s->lastload, s->freq, NANOSECONDS_PER_SECOND); 1993bd88451SPaolo Bonzini case OSCR11: tm ++; 2003bd88451SPaolo Bonzini /* fall through */ 2013bd88451SPaolo Bonzini case OSCR10: tm ++; 2023bd88451SPaolo Bonzini /* fall through */ 2033bd88451SPaolo Bonzini case OSCR9: tm ++; 2043bd88451SPaolo Bonzini /* fall through */ 2053bd88451SPaolo Bonzini case OSCR8: tm ++; 2063bd88451SPaolo Bonzini /* fall through */ 2073bd88451SPaolo Bonzini case OSCR7: tm ++; 2083bd88451SPaolo Bonzini /* fall through */ 2093bd88451SPaolo Bonzini case OSCR6: tm ++; 2103bd88451SPaolo Bonzini /* fall through */ 2113bd88451SPaolo Bonzini case OSCR5: tm ++; 2123bd88451SPaolo Bonzini /* fall through */ 2133bd88451SPaolo Bonzini case OSCR4: 2143bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s)) 2153bd88451SPaolo Bonzini goto badreg; 2163bd88451SPaolo Bonzini 2173bd88451SPaolo Bonzini if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) { 2183bd88451SPaolo Bonzini if (s->tm4[tm - 1].freq) 2193bd88451SPaolo Bonzini s->snapshot = s->tm4[tm - 1].clock + muldiv64( 220bc72ad67SAlex Bligh qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - 2213bd88451SPaolo Bonzini s->tm4[tm - 1].lastload, 22273bcb24dSRutuja Shah s->tm4[tm - 1].freq, NANOSECONDS_PER_SECOND); 2233bd88451SPaolo Bonzini else 2243bd88451SPaolo Bonzini s->snapshot = s->tm4[tm - 1].clock; 2253bd88451SPaolo Bonzini } 2263bd88451SPaolo Bonzini 2273bd88451SPaolo Bonzini if (!s->tm4[tm].freq) 2283bd88451SPaolo Bonzini return s->tm4[tm].clock; 22973bcb24dSRutuja Shah return s->tm4[tm].clock + 23073bcb24dSRutuja Shah muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - 23173bcb24dSRutuja Shah s->tm4[tm].lastload, s->tm4[tm].freq, 23273bcb24dSRutuja Shah NANOSECONDS_PER_SECOND); 2333bd88451SPaolo Bonzini case OIER: 2343bd88451SPaolo Bonzini return s->irq_enabled; 2353bd88451SPaolo Bonzini case OSSR: /* Status register */ 2363bd88451SPaolo Bonzini return s->events; 2373bd88451SPaolo Bonzini case OWER: 2383bd88451SPaolo Bonzini return s->reset3; 2393bd88451SPaolo Bonzini case OMCR11: tm ++; 2403bd88451SPaolo Bonzini /* fall through */ 2413bd88451SPaolo Bonzini case OMCR10: tm ++; 2423bd88451SPaolo Bonzini /* fall through */ 2433bd88451SPaolo Bonzini case OMCR9: tm ++; 2443bd88451SPaolo Bonzini /* fall through */ 2453bd88451SPaolo Bonzini case OMCR8: tm ++; 2463bd88451SPaolo Bonzini /* fall through */ 2473bd88451SPaolo Bonzini case OMCR7: tm ++; 2483bd88451SPaolo Bonzini /* fall through */ 2493bd88451SPaolo Bonzini case OMCR6: tm ++; 2503bd88451SPaolo Bonzini /* fall through */ 2513bd88451SPaolo Bonzini case OMCR5: tm ++; 2523bd88451SPaolo Bonzini /* fall through */ 2533bd88451SPaolo Bonzini case OMCR4: 2543bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s)) 2553bd88451SPaolo Bonzini goto badreg; 2563bd88451SPaolo Bonzini return s->tm4[tm].control; 2573bd88451SPaolo Bonzini case OSNR: 2583bd88451SPaolo Bonzini return s->snapshot; 2593bd88451SPaolo Bonzini default: 2602ba63e4aSPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP, 2612ba63e4aSPhilippe Mathieu-Daudé "%s: unknown register 0x%02" HWADDR_PRIx "\n", 2622ba63e4aSPhilippe Mathieu-Daudé __func__, offset); 2632ba63e4aSPhilippe Mathieu-Daudé break; 2643bd88451SPaolo Bonzini badreg: 2652ba63e4aSPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR, 2662ba63e4aSPhilippe Mathieu-Daudé "%s: incorrect register 0x%02" HWADDR_PRIx "\n", 2672ba63e4aSPhilippe Mathieu-Daudé __func__, offset); 2683bd88451SPaolo Bonzini } 2693bd88451SPaolo Bonzini 2703bd88451SPaolo Bonzini return 0; 2713bd88451SPaolo Bonzini } 2723bd88451SPaolo Bonzini 2733bd88451SPaolo Bonzini static void pxa2xx_timer_write(void *opaque, hwaddr offset, 2743bd88451SPaolo Bonzini uint64_t value, unsigned size) 2753bd88451SPaolo Bonzini { 2763bd88451SPaolo Bonzini int i, tm = 0; 2773bd88451SPaolo Bonzini PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 2783bd88451SPaolo Bonzini 2793bd88451SPaolo Bonzini switch (offset) { 2803bd88451SPaolo Bonzini case OSMR3: tm ++; 2813bd88451SPaolo Bonzini /* fall through */ 2823bd88451SPaolo Bonzini case OSMR2: tm ++; 2833bd88451SPaolo Bonzini /* fall through */ 2843bd88451SPaolo Bonzini case OSMR1: tm ++; 2853bd88451SPaolo Bonzini /* fall through */ 2863bd88451SPaolo Bonzini case OSMR0: 2873bd88451SPaolo Bonzini s->timer[tm].value = value; 288bc72ad67SAlex Bligh pxa2xx_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 2893bd88451SPaolo Bonzini break; 2903bd88451SPaolo Bonzini case OSMR11: tm ++; 2913bd88451SPaolo Bonzini /* fall through */ 2923bd88451SPaolo Bonzini case OSMR10: tm ++; 2933bd88451SPaolo Bonzini /* fall through */ 2943bd88451SPaolo Bonzini case OSMR9: tm ++; 2953bd88451SPaolo Bonzini /* fall through */ 2963bd88451SPaolo Bonzini case OSMR8: tm ++; 2973bd88451SPaolo Bonzini /* fall through */ 2983bd88451SPaolo Bonzini case OSMR7: tm ++; 2993bd88451SPaolo Bonzini /* fall through */ 3003bd88451SPaolo Bonzini case OSMR6: tm ++; 3013bd88451SPaolo Bonzini /* fall through */ 3023bd88451SPaolo Bonzini case OSMR5: tm ++; 3033bd88451SPaolo Bonzini /* fall through */ 3043bd88451SPaolo Bonzini case OSMR4: 3053bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s)) 3063bd88451SPaolo Bonzini goto badreg; 3073bd88451SPaolo Bonzini s->tm4[tm].tm.value = value; 308bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); 3093bd88451SPaolo Bonzini break; 3103bd88451SPaolo Bonzini case OSCR: 3113bd88451SPaolo Bonzini s->oldclock = s->clock; 312bc72ad67SAlex Bligh s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 3133bd88451SPaolo Bonzini s->clock = value; 3143bd88451SPaolo Bonzini pxa2xx_timer_update(s, s->lastload); 3153bd88451SPaolo Bonzini break; 3163bd88451SPaolo Bonzini case OSCR11: tm ++; 3173bd88451SPaolo Bonzini /* fall through */ 3183bd88451SPaolo Bonzini case OSCR10: tm ++; 3193bd88451SPaolo Bonzini /* fall through */ 3203bd88451SPaolo Bonzini case OSCR9: tm ++; 3213bd88451SPaolo Bonzini /* fall through */ 3223bd88451SPaolo Bonzini case OSCR8: tm ++; 3233bd88451SPaolo Bonzini /* fall through */ 3243bd88451SPaolo Bonzini case OSCR7: tm ++; 3253bd88451SPaolo Bonzini /* fall through */ 3263bd88451SPaolo Bonzini case OSCR6: tm ++; 3273bd88451SPaolo Bonzini /* fall through */ 3283bd88451SPaolo Bonzini case OSCR5: tm ++; 3293bd88451SPaolo Bonzini /* fall through */ 3303bd88451SPaolo Bonzini case OSCR4: 3313bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s)) 3323bd88451SPaolo Bonzini goto badreg; 3333bd88451SPaolo Bonzini s->tm4[tm].oldclock = s->tm4[tm].clock; 334bc72ad67SAlex Bligh s->tm4[tm].lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 3353bd88451SPaolo Bonzini s->tm4[tm].clock = value; 3363bd88451SPaolo Bonzini pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm); 3373bd88451SPaolo Bonzini break; 3383bd88451SPaolo Bonzini case OIER: 3393bd88451SPaolo Bonzini s->irq_enabled = value & 0xfff; 3403bd88451SPaolo Bonzini break; 3413bd88451SPaolo Bonzini case OSSR: /* Status register */ 3423bd88451SPaolo Bonzini value &= s->events; 3433bd88451SPaolo Bonzini s->events &= ~value; 3443bd88451SPaolo Bonzini for (i = 0; i < 4; i ++, value >>= 1) 3453bd88451SPaolo Bonzini if (value & 1) 3463bd88451SPaolo Bonzini qemu_irq_lower(s->timer[i].irq); 3473bd88451SPaolo Bonzini if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value) 3483bd88451SPaolo Bonzini qemu_irq_lower(s->irq4); 3493bd88451SPaolo Bonzini break; 3503bd88451SPaolo Bonzini case OWER: /* XXX: Reset on OSMR3 match? */ 3513bd88451SPaolo Bonzini s->reset3 = value; 3523bd88451SPaolo Bonzini break; 3533bd88451SPaolo Bonzini case OMCR7: tm ++; 3543bd88451SPaolo Bonzini /* fall through */ 3553bd88451SPaolo Bonzini case OMCR6: tm ++; 3563bd88451SPaolo Bonzini /* fall through */ 3573bd88451SPaolo Bonzini case OMCR5: tm ++; 3583bd88451SPaolo Bonzini /* fall through */ 3593bd88451SPaolo Bonzini case OMCR4: 3603bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s)) 3613bd88451SPaolo Bonzini goto badreg; 3623bd88451SPaolo Bonzini s->tm4[tm].control = value & 0x0ff; 3633bd88451SPaolo Bonzini /* XXX Stop if running (shouldn't happen) */ 3643bd88451SPaolo Bonzini if ((value & (1 << 7)) || tm == 0) 3653bd88451SPaolo Bonzini s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7]; 3663bd88451SPaolo Bonzini else { 3673bd88451SPaolo Bonzini s->tm4[tm].freq = 0; 368bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); 3693bd88451SPaolo Bonzini } 3703bd88451SPaolo Bonzini break; 3713bd88451SPaolo Bonzini case OMCR11: tm ++; 3723bd88451SPaolo Bonzini /* fall through */ 3733bd88451SPaolo Bonzini case OMCR10: tm ++; 3743bd88451SPaolo Bonzini /* fall through */ 3753bd88451SPaolo Bonzini case OMCR9: tm ++; 3763bd88451SPaolo Bonzini /* fall through */ 3773bd88451SPaolo Bonzini case OMCR8: tm += 4; 3783bd88451SPaolo Bonzini if (!pxa2xx_timer_has_tm4(s)) 3793bd88451SPaolo Bonzini goto badreg; 3803bd88451SPaolo Bonzini s->tm4[tm].control = value & 0x3ff; 3813bd88451SPaolo Bonzini /* XXX Stop if running (shouldn't happen) */ 3823bd88451SPaolo Bonzini if ((value & (1 << 7)) || !(tm & 1)) 3833bd88451SPaolo Bonzini s->tm4[tm].freq = 3843bd88451SPaolo Bonzini pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)]; 3853bd88451SPaolo Bonzini else { 3863bd88451SPaolo Bonzini s->tm4[tm].freq = 0; 387bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); 3883bd88451SPaolo Bonzini } 3893bd88451SPaolo Bonzini break; 3903bd88451SPaolo Bonzini default: 3912ba63e4aSPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP, 3922ba63e4aSPhilippe Mathieu-Daudé "%s: unknown register 0x%02" HWADDR_PRIx " " 3932ba63e4aSPhilippe Mathieu-Daudé "(value 0x%08" PRIx64 ")\n", __func__, offset, value); 3942ba63e4aSPhilippe Mathieu-Daudé break; 3953bd88451SPaolo Bonzini badreg: 3962ba63e4aSPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR, 3972ba63e4aSPhilippe Mathieu-Daudé "%s: incorrect register 0x%02" HWADDR_PRIx " " 3982ba63e4aSPhilippe Mathieu-Daudé "(value 0x%08" PRIx64 ")\n", __func__, offset, value); 3993bd88451SPaolo Bonzini } 4003bd88451SPaolo Bonzini } 4013bd88451SPaolo Bonzini 4023bd88451SPaolo Bonzini static const MemoryRegionOps pxa2xx_timer_ops = { 4033bd88451SPaolo Bonzini .read = pxa2xx_timer_read, 4043bd88451SPaolo Bonzini .write = pxa2xx_timer_write, 4053bd88451SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN, 4063bd88451SPaolo Bonzini }; 4073bd88451SPaolo Bonzini 4083bd88451SPaolo Bonzini static void pxa2xx_timer_tick(void *opaque) 4093bd88451SPaolo Bonzini { 4103bd88451SPaolo Bonzini PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque; 4113bd88451SPaolo Bonzini PXA2xxTimerInfo *i = t->info; 4123bd88451SPaolo Bonzini 4133bd88451SPaolo Bonzini if (i->irq_enabled & (1 << t->num)) { 4143bd88451SPaolo Bonzini i->events |= 1 << t->num; 4153bd88451SPaolo Bonzini qemu_irq_raise(t->irq); 4163bd88451SPaolo Bonzini } 4173bd88451SPaolo Bonzini 4183bd88451SPaolo Bonzini if (t->num == 3) 4193bd88451SPaolo Bonzini if (i->reset3 & 1) { 4203bd88451SPaolo Bonzini i->reset3 = 0; 421cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 4223bd88451SPaolo Bonzini } 4233bd88451SPaolo Bonzini } 4243bd88451SPaolo Bonzini 4253bd88451SPaolo Bonzini static void pxa2xx_timer_tick4(void *opaque) 4263bd88451SPaolo Bonzini { 4273bd88451SPaolo Bonzini PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque; 4283bd88451SPaolo Bonzini PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info; 4293bd88451SPaolo Bonzini 4303bd88451SPaolo Bonzini pxa2xx_timer_tick(&t->tm); 4313bd88451SPaolo Bonzini if (t->control & (1 << 3)) 4323bd88451SPaolo Bonzini t->clock = 0; 4333bd88451SPaolo Bonzini if (t->control & (1 << 6)) 434bc72ad67SAlex Bligh pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4); 4353bd88451SPaolo Bonzini if (i->events & 0xff0) 4363bd88451SPaolo Bonzini qemu_irq_raise(i->irq4); 4373bd88451SPaolo Bonzini } 4383bd88451SPaolo Bonzini 4393bd88451SPaolo Bonzini static int pxa25x_timer_post_load(void *opaque, int version_id) 4403bd88451SPaolo Bonzini { 4413bd88451SPaolo Bonzini PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 4423bd88451SPaolo Bonzini int64_t now; 4433bd88451SPaolo Bonzini int i; 4443bd88451SPaolo Bonzini 445bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 4463bd88451SPaolo Bonzini pxa2xx_timer_update(s, now); 4473bd88451SPaolo Bonzini 4483bd88451SPaolo Bonzini if (pxa2xx_timer_has_tm4(s)) 4493bd88451SPaolo Bonzini for (i = 0; i < 8; i ++) 4503bd88451SPaolo Bonzini pxa2xx_timer_update4(s, now, i); 4513bd88451SPaolo Bonzini 4523bd88451SPaolo Bonzini return 0; 4533bd88451SPaolo Bonzini } 4543bd88451SPaolo Bonzini 4555d83e348Sxiaoqiang.zhao static void pxa2xx_timer_init(Object *obj) 4563bd88451SPaolo Bonzini { 4575d83e348Sxiaoqiang.zhao PXA2xxTimerInfo *s = PXA2XX_TIMER(obj); 4585d83e348Sxiaoqiang.zhao SysBusDevice *dev = SYS_BUS_DEVICE(obj); 4593bd88451SPaolo Bonzini 4603bd88451SPaolo Bonzini s->irq_enabled = 0; 4613bd88451SPaolo Bonzini s->oldclock = 0; 4623bd88451SPaolo Bonzini s->clock = 0; 463bc72ad67SAlex Bligh s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 4643bd88451SPaolo Bonzini s->reset3 = 0; 4653bd88451SPaolo Bonzini 4665d83e348Sxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &pxa2xx_timer_ops, s, 4675d83e348Sxiaoqiang.zhao "pxa2xx-timer", 0x00001000); 4685d83e348Sxiaoqiang.zhao sysbus_init_mmio(dev, &s->iomem); 4695d83e348Sxiaoqiang.zhao } 4705d83e348Sxiaoqiang.zhao 4715d83e348Sxiaoqiang.zhao static void pxa2xx_timer_realize(DeviceState *dev, Error **errp) 4725d83e348Sxiaoqiang.zhao { 4735d83e348Sxiaoqiang.zhao PXA2xxTimerInfo *s = PXA2XX_TIMER(dev); 4745d83e348Sxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 4755d83e348Sxiaoqiang.zhao int i; 4765d83e348Sxiaoqiang.zhao 4773bd88451SPaolo Bonzini for (i = 0; i < 4; i ++) { 4783bd88451SPaolo Bonzini s->timer[i].value = 0; 4795d83e348Sxiaoqiang.zhao sysbus_init_irq(sbd, &s->timer[i].irq); 4803bd88451SPaolo Bonzini s->timer[i].info = s; 4813bd88451SPaolo Bonzini s->timer[i].num = i; 482bc72ad67SAlex Bligh s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 4833bd88451SPaolo Bonzini pxa2xx_timer_tick, &s->timer[i]); 4843bd88451SPaolo Bonzini } 4855d83e348Sxiaoqiang.zhao 4863bd88451SPaolo Bonzini if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) { 4875d83e348Sxiaoqiang.zhao sysbus_init_irq(sbd, &s->irq4); 4883bd88451SPaolo Bonzini 4893bd88451SPaolo Bonzini for (i = 0; i < 8; i ++) { 4903bd88451SPaolo Bonzini s->tm4[i].tm.value = 0; 4913bd88451SPaolo Bonzini s->tm4[i].tm.info = s; 4923bd88451SPaolo Bonzini s->tm4[i].tm.num = i + 4; 4933bd88451SPaolo Bonzini s->tm4[i].freq = 0; 4943bd88451SPaolo Bonzini s->tm4[i].control = 0x0; 495bc72ad67SAlex Bligh s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 4963bd88451SPaolo Bonzini pxa2xx_timer_tick4, &s->tm4[i]); 4973bd88451SPaolo Bonzini } 4983bd88451SPaolo Bonzini } 4993bd88451SPaolo Bonzini } 5003bd88451SPaolo Bonzini 5013bd88451SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_timer0_regs = { 5023bd88451SPaolo Bonzini .name = "pxa2xx_timer0", 5033bd88451SPaolo Bonzini .version_id = 2, 5043bd88451SPaolo Bonzini .minimum_version_id = 2, 5053bd88451SPaolo Bonzini .fields = (VMStateField[]) { 5063bd88451SPaolo Bonzini VMSTATE_UINT32(value, PXA2xxTimer0), 5073bd88451SPaolo Bonzini VMSTATE_END_OF_LIST(), 5083bd88451SPaolo Bonzini }, 5093bd88451SPaolo Bonzini }; 5103bd88451SPaolo Bonzini 5113bd88451SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_timer4_regs = { 5123bd88451SPaolo Bonzini .name = "pxa2xx_timer4", 5133bd88451SPaolo Bonzini .version_id = 1, 5143bd88451SPaolo Bonzini .minimum_version_id = 1, 5153bd88451SPaolo Bonzini .fields = (VMStateField[]) { 5163bd88451SPaolo Bonzini VMSTATE_STRUCT(tm, PXA2xxTimer4, 1, 5173bd88451SPaolo Bonzini vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), 5183bd88451SPaolo Bonzini VMSTATE_INT32(oldclock, PXA2xxTimer4), 5193bd88451SPaolo Bonzini VMSTATE_INT32(clock, PXA2xxTimer4), 5203bd88451SPaolo Bonzini VMSTATE_UINT64(lastload, PXA2xxTimer4), 5213bd88451SPaolo Bonzini VMSTATE_UINT32(freq, PXA2xxTimer4), 5223bd88451SPaolo Bonzini VMSTATE_UINT32(control, PXA2xxTimer4), 5233bd88451SPaolo Bonzini VMSTATE_END_OF_LIST(), 5243bd88451SPaolo Bonzini }, 5253bd88451SPaolo Bonzini }; 5263bd88451SPaolo Bonzini 5273bd88451SPaolo Bonzini static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id) 5283bd88451SPaolo Bonzini { 5293bd88451SPaolo Bonzini return pxa2xx_timer_has_tm4(opaque); 5303bd88451SPaolo Bonzini } 5313bd88451SPaolo Bonzini 5323bd88451SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_timer_regs = { 5333bd88451SPaolo Bonzini .name = "pxa2xx_timer", 5343bd88451SPaolo Bonzini .version_id = 1, 5353bd88451SPaolo Bonzini .minimum_version_id = 1, 5363bd88451SPaolo Bonzini .post_load = pxa25x_timer_post_load, 5373bd88451SPaolo Bonzini .fields = (VMStateField[]) { 5383bd88451SPaolo Bonzini VMSTATE_INT32(clock, PXA2xxTimerInfo), 5393bd88451SPaolo Bonzini VMSTATE_INT32(oldclock, PXA2xxTimerInfo), 5403bd88451SPaolo Bonzini VMSTATE_UINT64(lastload, PXA2xxTimerInfo), 5413bd88451SPaolo Bonzini VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1, 5423bd88451SPaolo Bonzini vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), 5433bd88451SPaolo Bonzini VMSTATE_UINT32(events, PXA2xxTimerInfo), 5443bd88451SPaolo Bonzini VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo), 5453bd88451SPaolo Bonzini VMSTATE_UINT32(reset3, PXA2xxTimerInfo), 5463bd88451SPaolo Bonzini VMSTATE_UINT32(snapshot, PXA2xxTimerInfo), 5473bd88451SPaolo Bonzini VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8, 5483bd88451SPaolo Bonzini pxa2xx_timer_has_tm4_test, 0, 5493bd88451SPaolo Bonzini vmstate_pxa2xx_timer4_regs, PXA2xxTimer4), 5503bd88451SPaolo Bonzini VMSTATE_END_OF_LIST(), 5513bd88451SPaolo Bonzini } 5523bd88451SPaolo Bonzini }; 5533bd88451SPaolo Bonzini 5543bd88451SPaolo Bonzini static Property pxa25x_timer_dev_properties[] = { 5553bd88451SPaolo Bonzini DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ), 5563bd88451SPaolo Bonzini DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, 5573bd88451SPaolo Bonzini PXA2XX_TIMER_HAVE_TM4, false), 5583bd88451SPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 5593bd88451SPaolo Bonzini }; 5603bd88451SPaolo Bonzini 5613bd88451SPaolo Bonzini static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data) 5623bd88451SPaolo Bonzini { 5633bd88451SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 5643bd88451SPaolo Bonzini 5653bd88451SPaolo Bonzini dc->desc = "PXA25x timer"; 5664f67d30bSMarc-André Lureau device_class_set_props(dc, pxa25x_timer_dev_properties); 5673bd88451SPaolo Bonzini } 5683bd88451SPaolo Bonzini 5693bd88451SPaolo Bonzini static const TypeInfo pxa25x_timer_dev_info = { 5703bd88451SPaolo Bonzini .name = "pxa25x-timer", 571feea4361SAndreas Färber .parent = TYPE_PXA2XX_TIMER, 5723bd88451SPaolo Bonzini .instance_size = sizeof(PXA2xxTimerInfo), 5733bd88451SPaolo Bonzini .class_init = pxa25x_timer_dev_class_init, 5743bd88451SPaolo Bonzini }; 5753bd88451SPaolo Bonzini 5763bd88451SPaolo Bonzini static Property pxa27x_timer_dev_properties[] = { 5773bd88451SPaolo Bonzini DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ), 5783bd88451SPaolo Bonzini DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, 5793bd88451SPaolo Bonzini PXA2XX_TIMER_HAVE_TM4, true), 5803bd88451SPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 5813bd88451SPaolo Bonzini }; 5823bd88451SPaolo Bonzini 5833bd88451SPaolo Bonzini static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data) 5843bd88451SPaolo Bonzini { 5853bd88451SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 5863bd88451SPaolo Bonzini 5873bd88451SPaolo Bonzini dc->desc = "PXA27x timer"; 5884f67d30bSMarc-André Lureau device_class_set_props(dc, pxa27x_timer_dev_properties); 5893bd88451SPaolo Bonzini } 5903bd88451SPaolo Bonzini 5913bd88451SPaolo Bonzini static const TypeInfo pxa27x_timer_dev_info = { 5923bd88451SPaolo Bonzini .name = "pxa27x-timer", 593feea4361SAndreas Färber .parent = TYPE_PXA2XX_TIMER, 5943bd88451SPaolo Bonzini .instance_size = sizeof(PXA2xxTimerInfo), 5953bd88451SPaolo Bonzini .class_init = pxa27x_timer_dev_class_init, 5963bd88451SPaolo Bonzini }; 5973bd88451SPaolo Bonzini 598feea4361SAndreas Färber static void pxa2xx_timer_class_init(ObjectClass *oc, void *data) 599feea4361SAndreas Färber { 600feea4361SAndreas Färber DeviceClass *dc = DEVICE_CLASS(oc); 601feea4361SAndreas Färber 6025d83e348Sxiaoqiang.zhao dc->realize = pxa2xx_timer_realize; 603feea4361SAndreas Färber dc->vmsd = &vmstate_pxa2xx_timer_regs; 604feea4361SAndreas Färber } 605feea4361SAndreas Färber 606feea4361SAndreas Färber static const TypeInfo pxa2xx_timer_type_info = { 607feea4361SAndreas Färber .name = TYPE_PXA2XX_TIMER, 608feea4361SAndreas Färber .parent = TYPE_SYS_BUS_DEVICE, 609feea4361SAndreas Färber .instance_size = sizeof(PXA2xxTimerInfo), 6105d83e348Sxiaoqiang.zhao .instance_init = pxa2xx_timer_init, 611feea4361SAndreas Färber .abstract = true, 612feea4361SAndreas Färber .class_init = pxa2xx_timer_class_init, 613feea4361SAndreas Färber }; 614feea4361SAndreas Färber 6153bd88451SPaolo Bonzini static void pxa2xx_timer_register_types(void) 6163bd88451SPaolo Bonzini { 617feea4361SAndreas Färber type_register_static(&pxa2xx_timer_type_info); 6183bd88451SPaolo Bonzini type_register_static(&pxa25x_timer_dev_info); 6193bd88451SPaolo Bonzini type_register_static(&pxa27x_timer_dev_info); 6203bd88451SPaolo Bonzini } 6213bd88451SPaolo Bonzini 6223bd88451SPaolo Bonzini type_init(pxa2xx_timer_register_types) 623