1a171fe39Sbalrog /* 2a171fe39Sbalrog * Intel XScale PXA255/270 OS Timers. 3a171fe39Sbalrog * 4a171fe39Sbalrog * Copyright (c) 2006 Openedhand Ltd. 5a171fe39Sbalrog * Copyright (c) 2006 Thorsten Zitterell 6a171fe39Sbalrog * 78e31bf38SMatthew Fernandez * This code is licensed under the GPL. 8a171fe39Sbalrog */ 9a171fe39Sbalrog 1083c9f4caSPaolo Bonzini #include "hw/hw.h" 111de7afc9SPaolo Bonzini #include "qemu/timer.h" 129c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 130d09e41aSPaolo Bonzini #include "hw/arm/pxa.h" 1483c9f4caSPaolo Bonzini #include "hw/sysbus.h" 15a171fe39Sbalrog 16a171fe39Sbalrog #define OSMR0 0x00 17a171fe39Sbalrog #define OSMR1 0x04 18a171fe39Sbalrog #define OSMR2 0x08 19a171fe39Sbalrog #define OSMR3 0x0c 20a171fe39Sbalrog #define OSMR4 0x80 21a171fe39Sbalrog #define OSMR5 0x84 22a171fe39Sbalrog #define OSMR6 0x88 23a171fe39Sbalrog #define OSMR7 0x8c 24a171fe39Sbalrog #define OSMR8 0x90 25a171fe39Sbalrog #define OSMR9 0x94 26a171fe39Sbalrog #define OSMR10 0x98 27a171fe39Sbalrog #define OSMR11 0x9c 28a171fe39Sbalrog #define OSCR 0x10 /* OS Timer Count */ 29a171fe39Sbalrog #define OSCR4 0x40 30a171fe39Sbalrog #define OSCR5 0x44 31a171fe39Sbalrog #define OSCR6 0x48 32a171fe39Sbalrog #define OSCR7 0x4c 33a171fe39Sbalrog #define OSCR8 0x50 34a171fe39Sbalrog #define OSCR9 0x54 35a171fe39Sbalrog #define OSCR10 0x58 36a171fe39Sbalrog #define OSCR11 0x5c 37a171fe39Sbalrog #define OSSR 0x14 /* Timer status register */ 38a171fe39Sbalrog #define OWER 0x18 39a171fe39Sbalrog #define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */ 40a171fe39Sbalrog #define OMCR4 0xc0 /* OS Match Control registers */ 41a171fe39Sbalrog #define OMCR5 0xc4 42a171fe39Sbalrog #define OMCR6 0xc8 43a171fe39Sbalrog #define OMCR7 0xcc 44a171fe39Sbalrog #define OMCR8 0xd0 45a171fe39Sbalrog #define OMCR9 0xd4 46a171fe39Sbalrog #define OMCR10 0xd8 47a171fe39Sbalrog #define OMCR11 0xdc 48a171fe39Sbalrog #define OSNR 0x20 49a171fe39Sbalrog 50a171fe39Sbalrog #define PXA25X_FREQ 3686400 /* 3.6864 MHz */ 51a171fe39Sbalrog #define PXA27X_FREQ 3250000 /* 3.25 MHz */ 52a171fe39Sbalrog 53a171fe39Sbalrog static int pxa2xx_timer4_freq[8] = { 54a171fe39Sbalrog [0] = 0, 55a171fe39Sbalrog [1] = 32768, 56a171fe39Sbalrog [2] = 1000, 57a171fe39Sbalrog [3] = 1, 58a171fe39Sbalrog [4] = 1000000, 59a171fe39Sbalrog /* [5] is the "Externally supplied clock". Assign if necessary. */ 60a171fe39Sbalrog [5 ... 7] = 0, 61a171fe39Sbalrog }; 62a171fe39Sbalrog 63797e9542SDmitry Eremin-Solenikov typedef struct PXA2xxTimerInfo PXA2xxTimerInfo; 64797e9542SDmitry Eremin-Solenikov 65bc24a225SPaul Brook typedef struct { 66a171fe39Sbalrog uint32_t value; 675251d196SAndrzej Zaborowski qemu_irq irq; 68a171fe39Sbalrog QEMUTimer *qtimer; 69a171fe39Sbalrog int num; 70797e9542SDmitry Eremin-Solenikov PXA2xxTimerInfo *info; 71bc24a225SPaul Brook } PXA2xxTimer0; 72a171fe39Sbalrog 73bc24a225SPaul Brook typedef struct { 74bc24a225SPaul Brook PXA2xxTimer0 tm; 75a171fe39Sbalrog int32_t oldclock; 76a171fe39Sbalrog int32_t clock; 77a171fe39Sbalrog uint64_t lastload; 78a171fe39Sbalrog uint32_t freq; 79a171fe39Sbalrog uint32_t control; 80bc24a225SPaul Brook } PXA2xxTimer4; 81a171fe39Sbalrog 82797e9542SDmitry Eremin-Solenikov struct PXA2xxTimerInfo { 83797e9542SDmitry Eremin-Solenikov SysBusDevice busdev; 84b755bde3SBenoît Canet MemoryRegion iomem; 85797e9542SDmitry Eremin-Solenikov uint32_t flags; 86797e9542SDmitry Eremin-Solenikov 87a171fe39Sbalrog int32_t clock; 88a171fe39Sbalrog int32_t oldclock; 89a171fe39Sbalrog uint64_t lastload; 90a171fe39Sbalrog uint32_t freq; 91bc24a225SPaul Brook PXA2xxTimer0 timer[4]; 92a171fe39Sbalrog uint32_t events; 93a171fe39Sbalrog uint32_t irq_enabled; 94a171fe39Sbalrog uint32_t reset3; 95a171fe39Sbalrog uint32_t snapshot; 96797e9542SDmitry Eremin-Solenikov 974ff927ccSDmitry Eremin-Solenikov qemu_irq irq4; 98797e9542SDmitry Eremin-Solenikov PXA2xxTimer4 tm4[8]; 99797e9542SDmitry Eremin-Solenikov }; 100797e9542SDmitry Eremin-Solenikov 101797e9542SDmitry Eremin-Solenikov #define PXA2XX_TIMER_HAVE_TM4 0 102797e9542SDmitry Eremin-Solenikov 103797e9542SDmitry Eremin-Solenikov static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s) 104797e9542SDmitry Eremin-Solenikov { 105797e9542SDmitry Eremin-Solenikov return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4); 106797e9542SDmitry Eremin-Solenikov } 107a171fe39Sbalrog 108a171fe39Sbalrog static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu) 109a171fe39Sbalrog { 110d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 111a171fe39Sbalrog int i; 112a171fe39Sbalrog uint32_t now_vm; 113a171fe39Sbalrog uint64_t new_qemu; 114a171fe39Sbalrog 115a171fe39Sbalrog now_vm = s->clock + 1166ee093c9SJuan Quintela muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec()); 117a171fe39Sbalrog 118a171fe39Sbalrog for (i = 0; i < 4; i ++) { 119a171fe39Sbalrog new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm), 1206ee093c9SJuan Quintela get_ticks_per_sec(), s->freq); 121a171fe39Sbalrog qemu_mod_timer(s->timer[i].qtimer, new_qemu); 122a171fe39Sbalrog } 123a171fe39Sbalrog } 124a171fe39Sbalrog 125a171fe39Sbalrog static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) 126a171fe39Sbalrog { 127d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 128a171fe39Sbalrog uint32_t now_vm; 129a171fe39Sbalrog uint64_t new_qemu; 130a171fe39Sbalrog static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 }; 131a171fe39Sbalrog int counter; 132a171fe39Sbalrog 133a171fe39Sbalrog if (s->tm4[n].control & (1 << 7)) 134a171fe39Sbalrog counter = n; 135a171fe39Sbalrog else 136a171fe39Sbalrog counter = counters[n]; 137a171fe39Sbalrog 138a171fe39Sbalrog if (!s->tm4[counter].freq) { 1393f582262Sbalrog qemu_del_timer(s->tm4[n].tm.qtimer); 140a171fe39Sbalrog return; 141a171fe39Sbalrog } 142a171fe39Sbalrog 143a171fe39Sbalrog now_vm = s->tm4[counter].clock + muldiv64(now_qemu - 144a171fe39Sbalrog s->tm4[counter].lastload, 1456ee093c9SJuan Quintela s->tm4[counter].freq, get_ticks_per_sec()); 146a171fe39Sbalrog 1473bdd58a4Sbalrog new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm), 1486ee093c9SJuan Quintela get_ticks_per_sec(), s->tm4[counter].freq); 1493f582262Sbalrog qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu); 150a171fe39Sbalrog } 151a171fe39Sbalrog 152a8170e5eSAvi Kivity static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, 153b755bde3SBenoît Canet unsigned size) 154a171fe39Sbalrog { 155d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 156a171fe39Sbalrog int tm = 0; 157a171fe39Sbalrog 158a171fe39Sbalrog switch (offset) { 159a171fe39Sbalrog case OSMR3: tm ++; 160de16017dSPeter Maydell /* fall through */ 161a171fe39Sbalrog case OSMR2: tm ++; 162de16017dSPeter Maydell /* fall through */ 163a171fe39Sbalrog case OSMR1: tm ++; 164de16017dSPeter Maydell /* fall through */ 165a171fe39Sbalrog case OSMR0: 166a171fe39Sbalrog return s->timer[tm].value; 167a171fe39Sbalrog case OSMR11: tm ++; 168de16017dSPeter Maydell /* fall through */ 169a171fe39Sbalrog case OSMR10: tm ++; 170de16017dSPeter Maydell /* fall through */ 171a171fe39Sbalrog case OSMR9: tm ++; 172de16017dSPeter Maydell /* fall through */ 173a171fe39Sbalrog case OSMR8: tm ++; 174de16017dSPeter Maydell /* fall through */ 175a171fe39Sbalrog case OSMR7: tm ++; 176de16017dSPeter Maydell /* fall through */ 177a171fe39Sbalrog case OSMR6: tm ++; 178de16017dSPeter Maydell /* fall through */ 179a171fe39Sbalrog case OSMR5: tm ++; 180de16017dSPeter Maydell /* fall through */ 181a171fe39Sbalrog case OSMR4: 182797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 183a171fe39Sbalrog goto badreg; 1843bdd58a4Sbalrog return s->tm4[tm].tm.value; 185a171fe39Sbalrog case OSCR: 18674475455SPaolo Bonzini return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) - 1876ee093c9SJuan Quintela s->lastload, s->freq, get_ticks_per_sec()); 188a171fe39Sbalrog case OSCR11: tm ++; 189de16017dSPeter Maydell /* fall through */ 190a171fe39Sbalrog case OSCR10: tm ++; 191de16017dSPeter Maydell /* fall through */ 192a171fe39Sbalrog case OSCR9: tm ++; 193de16017dSPeter Maydell /* fall through */ 194a171fe39Sbalrog case OSCR8: tm ++; 195de16017dSPeter Maydell /* fall through */ 196a171fe39Sbalrog case OSCR7: tm ++; 197de16017dSPeter Maydell /* fall through */ 198a171fe39Sbalrog case OSCR6: tm ++; 199de16017dSPeter Maydell /* fall through */ 200a171fe39Sbalrog case OSCR5: tm ++; 201de16017dSPeter Maydell /* fall through */ 202a171fe39Sbalrog case OSCR4: 203797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 204a171fe39Sbalrog goto badreg; 205a171fe39Sbalrog 206a171fe39Sbalrog if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) { 207a171fe39Sbalrog if (s->tm4[tm - 1].freq) 208a171fe39Sbalrog s->snapshot = s->tm4[tm - 1].clock + muldiv64( 20974475455SPaolo Bonzini qemu_get_clock_ns(vm_clock) - 210a171fe39Sbalrog s->tm4[tm - 1].lastload, 2116ee093c9SJuan Quintela s->tm4[tm - 1].freq, get_ticks_per_sec()); 212a171fe39Sbalrog else 213a171fe39Sbalrog s->snapshot = s->tm4[tm - 1].clock; 214a171fe39Sbalrog } 215a171fe39Sbalrog 216a171fe39Sbalrog if (!s->tm4[tm].freq) 217a171fe39Sbalrog return s->tm4[tm].clock; 21874475455SPaolo Bonzini return s->tm4[tm].clock + muldiv64(qemu_get_clock_ns(vm_clock) - 2196ee093c9SJuan Quintela s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec()); 220a171fe39Sbalrog case OIER: 221a171fe39Sbalrog return s->irq_enabled; 222a171fe39Sbalrog case OSSR: /* Status register */ 223a171fe39Sbalrog return s->events; 224a171fe39Sbalrog case OWER: 225a171fe39Sbalrog return s->reset3; 226a171fe39Sbalrog case OMCR11: tm ++; 227de16017dSPeter Maydell /* fall through */ 228a171fe39Sbalrog case OMCR10: tm ++; 229de16017dSPeter Maydell /* fall through */ 230a171fe39Sbalrog case OMCR9: tm ++; 231de16017dSPeter Maydell /* fall through */ 232a171fe39Sbalrog case OMCR8: tm ++; 233de16017dSPeter Maydell /* fall through */ 234a171fe39Sbalrog case OMCR7: tm ++; 235de16017dSPeter Maydell /* fall through */ 236a171fe39Sbalrog case OMCR6: tm ++; 237de16017dSPeter Maydell /* fall through */ 238a171fe39Sbalrog case OMCR5: tm ++; 239de16017dSPeter Maydell /* fall through */ 240a171fe39Sbalrog case OMCR4: 241797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 242a171fe39Sbalrog goto badreg; 243a171fe39Sbalrog return s->tm4[tm].control; 244a171fe39Sbalrog case OSNR: 245a171fe39Sbalrog return s->snapshot; 246a171fe39Sbalrog default: 247a171fe39Sbalrog badreg: 2482ac71179SPaul Brook hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset); 249a171fe39Sbalrog } 250a171fe39Sbalrog 251a171fe39Sbalrog return 0; 252a171fe39Sbalrog } 253a171fe39Sbalrog 254a8170e5eSAvi Kivity static void pxa2xx_timer_write(void *opaque, hwaddr offset, 255b755bde3SBenoît Canet uint64_t value, unsigned size) 256a171fe39Sbalrog { 257a171fe39Sbalrog int i, tm = 0; 258d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 259a171fe39Sbalrog 260a171fe39Sbalrog switch (offset) { 261a171fe39Sbalrog case OSMR3: tm ++; 262de16017dSPeter Maydell /* fall through */ 263a171fe39Sbalrog case OSMR2: tm ++; 264de16017dSPeter Maydell /* fall through */ 265a171fe39Sbalrog case OSMR1: tm ++; 266de16017dSPeter Maydell /* fall through */ 267a171fe39Sbalrog case OSMR0: 268a171fe39Sbalrog s->timer[tm].value = value; 26974475455SPaolo Bonzini pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock)); 270a171fe39Sbalrog break; 271a171fe39Sbalrog case OSMR11: tm ++; 272de16017dSPeter Maydell /* fall through */ 273a171fe39Sbalrog case OSMR10: tm ++; 274de16017dSPeter Maydell /* fall through */ 275a171fe39Sbalrog case OSMR9: tm ++; 276de16017dSPeter Maydell /* fall through */ 277a171fe39Sbalrog case OSMR8: tm ++; 278de16017dSPeter Maydell /* fall through */ 279a171fe39Sbalrog case OSMR7: tm ++; 280de16017dSPeter Maydell /* fall through */ 281a171fe39Sbalrog case OSMR6: tm ++; 282de16017dSPeter Maydell /* fall through */ 283a171fe39Sbalrog case OSMR5: tm ++; 284de16017dSPeter Maydell /* fall through */ 285a171fe39Sbalrog case OSMR4: 286797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 287a171fe39Sbalrog goto badreg; 2883bdd58a4Sbalrog s->tm4[tm].tm.value = value; 28974475455SPaolo Bonzini pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm); 290a171fe39Sbalrog break; 291a171fe39Sbalrog case OSCR: 292a171fe39Sbalrog s->oldclock = s->clock; 29374475455SPaolo Bonzini s->lastload = qemu_get_clock_ns(vm_clock); 294a171fe39Sbalrog s->clock = value; 295a171fe39Sbalrog pxa2xx_timer_update(s, s->lastload); 296a171fe39Sbalrog break; 297a171fe39Sbalrog case OSCR11: tm ++; 298de16017dSPeter Maydell /* fall through */ 299a171fe39Sbalrog case OSCR10: tm ++; 300de16017dSPeter Maydell /* fall through */ 301a171fe39Sbalrog case OSCR9: tm ++; 302de16017dSPeter Maydell /* fall through */ 303a171fe39Sbalrog case OSCR8: tm ++; 304de16017dSPeter Maydell /* fall through */ 305a171fe39Sbalrog case OSCR7: tm ++; 306de16017dSPeter Maydell /* fall through */ 307a171fe39Sbalrog case OSCR6: tm ++; 308de16017dSPeter Maydell /* fall through */ 309a171fe39Sbalrog case OSCR5: tm ++; 310de16017dSPeter Maydell /* fall through */ 311a171fe39Sbalrog case OSCR4: 312797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 313a171fe39Sbalrog goto badreg; 314a171fe39Sbalrog s->tm4[tm].oldclock = s->tm4[tm].clock; 31574475455SPaolo Bonzini s->tm4[tm].lastload = qemu_get_clock_ns(vm_clock); 316a171fe39Sbalrog s->tm4[tm].clock = value; 317a171fe39Sbalrog pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm); 318a171fe39Sbalrog break; 319a171fe39Sbalrog case OIER: 320a171fe39Sbalrog s->irq_enabled = value & 0xfff; 321a171fe39Sbalrog break; 322a171fe39Sbalrog case OSSR: /* Status register */ 3238034ce7dSAndrzej Zaborowski value &= s->events; 324a171fe39Sbalrog s->events &= ~value; 3258034ce7dSAndrzej Zaborowski for (i = 0; i < 4; i ++, value >>= 1) 3268034ce7dSAndrzej Zaborowski if (value & 1) 3275251d196SAndrzej Zaborowski qemu_irq_lower(s->timer[i].irq); 3288034ce7dSAndrzej Zaborowski if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value) 3294ff927ccSDmitry Eremin-Solenikov qemu_irq_lower(s->irq4); 330a171fe39Sbalrog break; 331a171fe39Sbalrog case OWER: /* XXX: Reset on OSMR3 match? */ 332a171fe39Sbalrog s->reset3 = value; 333a171fe39Sbalrog break; 334a171fe39Sbalrog case OMCR7: tm ++; 335de16017dSPeter Maydell /* fall through */ 336a171fe39Sbalrog case OMCR6: tm ++; 337de16017dSPeter Maydell /* fall through */ 338a171fe39Sbalrog case OMCR5: tm ++; 339de16017dSPeter Maydell /* fall through */ 340a171fe39Sbalrog case OMCR4: 341797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 342a171fe39Sbalrog goto badreg; 343a171fe39Sbalrog s->tm4[tm].control = value & 0x0ff; 344a171fe39Sbalrog /* XXX Stop if running (shouldn't happen) */ 345a171fe39Sbalrog if ((value & (1 << 7)) || tm == 0) 346a171fe39Sbalrog s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7]; 347a171fe39Sbalrog else { 348a171fe39Sbalrog s->tm4[tm].freq = 0; 34974475455SPaolo Bonzini pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm); 350a171fe39Sbalrog } 351a171fe39Sbalrog break; 352a171fe39Sbalrog case OMCR11: tm ++; 353de16017dSPeter Maydell /* fall through */ 354a171fe39Sbalrog case OMCR10: tm ++; 355de16017dSPeter Maydell /* fall through */ 356a171fe39Sbalrog case OMCR9: tm ++; 357de16017dSPeter Maydell /* fall through */ 358a171fe39Sbalrog case OMCR8: tm += 4; 359797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 360a171fe39Sbalrog goto badreg; 361a171fe39Sbalrog s->tm4[tm].control = value & 0x3ff; 362a171fe39Sbalrog /* XXX Stop if running (shouldn't happen) */ 363a171fe39Sbalrog if ((value & (1 << 7)) || !(tm & 1)) 364a171fe39Sbalrog s->tm4[tm].freq = 365a171fe39Sbalrog pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)]; 366a171fe39Sbalrog else { 367a171fe39Sbalrog s->tm4[tm].freq = 0; 36874475455SPaolo Bonzini pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm); 369a171fe39Sbalrog } 370a171fe39Sbalrog break; 371a171fe39Sbalrog default: 372a171fe39Sbalrog badreg: 3732ac71179SPaul Brook hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset); 374a171fe39Sbalrog } 375a171fe39Sbalrog } 376a171fe39Sbalrog 377b755bde3SBenoît Canet static const MemoryRegionOps pxa2xx_timer_ops = { 378b755bde3SBenoît Canet .read = pxa2xx_timer_read, 379b755bde3SBenoît Canet .write = pxa2xx_timer_write, 380b755bde3SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 381a171fe39Sbalrog }; 382a171fe39Sbalrog 383a171fe39Sbalrog static void pxa2xx_timer_tick(void *opaque) 384a171fe39Sbalrog { 385bc24a225SPaul Brook PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque; 386797e9542SDmitry Eremin-Solenikov PXA2xxTimerInfo *i = t->info; 387a171fe39Sbalrog 388a171fe39Sbalrog if (i->irq_enabled & (1 << t->num)) { 389a171fe39Sbalrog i->events |= 1 << t->num; 3905251d196SAndrzej Zaborowski qemu_irq_raise(t->irq); 391a171fe39Sbalrog } 392a171fe39Sbalrog 393a171fe39Sbalrog if (t->num == 3) 394a171fe39Sbalrog if (i->reset3 & 1) { 395a171fe39Sbalrog i->reset3 = 0; 3963f582262Sbalrog qemu_system_reset_request(); 397a171fe39Sbalrog } 398a171fe39Sbalrog } 399a171fe39Sbalrog 400a171fe39Sbalrog static void pxa2xx_timer_tick4(void *opaque) 401a171fe39Sbalrog { 402bc24a225SPaul Brook PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque; 403d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info; 404a171fe39Sbalrog 4053bdd58a4Sbalrog pxa2xx_timer_tick(&t->tm); 406a171fe39Sbalrog if (t->control & (1 << 3)) 407a171fe39Sbalrog t->clock = 0; 408a171fe39Sbalrog if (t->control & (1 << 6)) 40974475455SPaolo Bonzini pxa2xx_timer_update4(i, qemu_get_clock_ns(vm_clock), t->tm.num - 4); 4104ff927ccSDmitry Eremin-Solenikov if (i->events & 0xff0) 4114ff927ccSDmitry Eremin-Solenikov qemu_irq_raise(i->irq4); 412a171fe39Sbalrog } 413a171fe39Sbalrog 414797e9542SDmitry Eremin-Solenikov static int pxa25x_timer_post_load(void *opaque, int version_id) 415aa941b94Sbalrog { 416d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 417aa941b94Sbalrog int64_t now; 418aa941b94Sbalrog int i; 419aa941b94Sbalrog 42074475455SPaolo Bonzini now = qemu_get_clock_ns(vm_clock); 421aa941b94Sbalrog pxa2xx_timer_update(s, now); 422aa941b94Sbalrog 423797e9542SDmitry Eremin-Solenikov if (pxa2xx_timer_has_tm4(s)) 424797e9542SDmitry Eremin-Solenikov for (i = 0; i < 8; i ++) 425aa941b94Sbalrog pxa2xx_timer_update4(s, now, i); 426aa941b94Sbalrog 427aa941b94Sbalrog return 0; 428aa941b94Sbalrog } 429aa941b94Sbalrog 430797e9542SDmitry Eremin-Solenikov static int pxa2xx_timer_init(SysBusDevice *dev) 431a171fe39Sbalrog { 432a171fe39Sbalrog int i; 433d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s; 434a171fe39Sbalrog 435797e9542SDmitry Eremin-Solenikov s = FROM_SYSBUS(PXA2xxTimerInfo, dev); 436a171fe39Sbalrog s->irq_enabled = 0; 437a171fe39Sbalrog s->oldclock = 0; 438a171fe39Sbalrog s->clock = 0; 43974475455SPaolo Bonzini s->lastload = qemu_get_clock_ns(vm_clock); 440a171fe39Sbalrog s->reset3 = 0; 441a171fe39Sbalrog 442a171fe39Sbalrog for (i = 0; i < 4; i ++) { 443a171fe39Sbalrog s->timer[i].value = 0; 4445251d196SAndrzej Zaborowski sysbus_init_irq(dev, &s->timer[i].irq); 445a171fe39Sbalrog s->timer[i].info = s; 446a171fe39Sbalrog s->timer[i].num = i; 44774475455SPaolo Bonzini s->timer[i].qtimer = qemu_new_timer_ns(vm_clock, 448a171fe39Sbalrog pxa2xx_timer_tick, &s->timer[i]); 449a171fe39Sbalrog } 450797e9542SDmitry Eremin-Solenikov if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) { 4514ff927ccSDmitry Eremin-Solenikov sysbus_init_irq(dev, &s->irq4); 452a171fe39Sbalrog 453a171fe39Sbalrog for (i = 0; i < 8; i ++) { 4543bdd58a4Sbalrog s->tm4[i].tm.value = 0; 4553bdd58a4Sbalrog s->tm4[i].tm.info = s; 4563bdd58a4Sbalrog s->tm4[i].tm.num = i + 4; 457a171fe39Sbalrog s->tm4[i].freq = 0; 458a171fe39Sbalrog s->tm4[i].control = 0x0; 45974475455SPaolo Bonzini s->tm4[i].tm.qtimer = qemu_new_timer_ns(vm_clock, 460a171fe39Sbalrog pxa2xx_timer_tick4, &s->tm4[i]); 461a171fe39Sbalrog } 462a171fe39Sbalrog } 463797e9542SDmitry Eremin-Solenikov 464*853dca12SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_timer_ops, s, 465b755bde3SBenoît Canet "pxa2xx-timer", 0x00001000); 466750ecd44SAvi Kivity sysbus_init_mmio(dev, &s->iomem); 467797e9542SDmitry Eremin-Solenikov 468797e9542SDmitry Eremin-Solenikov return 0; 469797e9542SDmitry Eremin-Solenikov } 470797e9542SDmitry Eremin-Solenikov 471797e9542SDmitry Eremin-Solenikov static const VMStateDescription vmstate_pxa2xx_timer0_regs = { 472797e9542SDmitry Eremin-Solenikov .name = "pxa2xx_timer0", 4738034ce7dSAndrzej Zaborowski .version_id = 2, 4748034ce7dSAndrzej Zaborowski .minimum_version_id = 2, 4758034ce7dSAndrzej Zaborowski .minimum_version_id_old = 2, 476797e9542SDmitry Eremin-Solenikov .fields = (VMStateField[]) { 477797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(value, PXA2xxTimer0), 478797e9542SDmitry Eremin-Solenikov VMSTATE_END_OF_LIST(), 479797e9542SDmitry Eremin-Solenikov }, 480797e9542SDmitry Eremin-Solenikov }; 481797e9542SDmitry Eremin-Solenikov 482797e9542SDmitry Eremin-Solenikov static const VMStateDescription vmstate_pxa2xx_timer4_regs = { 483797e9542SDmitry Eremin-Solenikov .name = "pxa2xx_timer4", 484797e9542SDmitry Eremin-Solenikov .version_id = 1, 485797e9542SDmitry Eremin-Solenikov .minimum_version_id = 1, 486797e9542SDmitry Eremin-Solenikov .minimum_version_id_old = 1, 487797e9542SDmitry Eremin-Solenikov .fields = (VMStateField[]) { 488797e9542SDmitry Eremin-Solenikov VMSTATE_STRUCT(tm, PXA2xxTimer4, 1, 489797e9542SDmitry Eremin-Solenikov vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), 490797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(oldclock, PXA2xxTimer4), 491797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(clock, PXA2xxTimer4), 492797e9542SDmitry Eremin-Solenikov VMSTATE_UINT64(lastload, PXA2xxTimer4), 493797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(freq, PXA2xxTimer4), 494797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(control, PXA2xxTimer4), 495797e9542SDmitry Eremin-Solenikov VMSTATE_END_OF_LIST(), 496797e9542SDmitry Eremin-Solenikov }, 497797e9542SDmitry Eremin-Solenikov }; 498797e9542SDmitry Eremin-Solenikov 499797e9542SDmitry Eremin-Solenikov static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id) 500797e9542SDmitry Eremin-Solenikov { 501797e9542SDmitry Eremin-Solenikov return pxa2xx_timer_has_tm4(opaque); 502797e9542SDmitry Eremin-Solenikov } 503797e9542SDmitry Eremin-Solenikov 504797e9542SDmitry Eremin-Solenikov static const VMStateDescription vmstate_pxa2xx_timer_regs = { 505797e9542SDmitry Eremin-Solenikov .name = "pxa2xx_timer", 506797e9542SDmitry Eremin-Solenikov .version_id = 1, 507797e9542SDmitry Eremin-Solenikov .minimum_version_id = 1, 508797e9542SDmitry Eremin-Solenikov .minimum_version_id_old = 1, 509797e9542SDmitry Eremin-Solenikov .post_load = pxa25x_timer_post_load, 510797e9542SDmitry Eremin-Solenikov .fields = (VMStateField[]) { 511797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(clock, PXA2xxTimerInfo), 512797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(oldclock, PXA2xxTimerInfo), 513797e9542SDmitry Eremin-Solenikov VMSTATE_UINT64(lastload, PXA2xxTimerInfo), 514797e9542SDmitry Eremin-Solenikov VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1, 515797e9542SDmitry Eremin-Solenikov vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), 516797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(events, PXA2xxTimerInfo), 517797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo), 518797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(reset3, PXA2xxTimerInfo), 519797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(snapshot, PXA2xxTimerInfo), 520797e9542SDmitry Eremin-Solenikov VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8, 521797e9542SDmitry Eremin-Solenikov pxa2xx_timer_has_tm4_test, 0, 522797e9542SDmitry Eremin-Solenikov vmstate_pxa2xx_timer4_regs, PXA2xxTimer4), 523797e9542SDmitry Eremin-Solenikov VMSTATE_END_OF_LIST(), 524797e9542SDmitry Eremin-Solenikov } 525797e9542SDmitry Eremin-Solenikov }; 526797e9542SDmitry Eremin-Solenikov 527999e12bbSAnthony Liguori static Property pxa25x_timer_dev_properties[] = { 528797e9542SDmitry Eremin-Solenikov DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ), 529797e9542SDmitry Eremin-Solenikov DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, 530797e9542SDmitry Eremin-Solenikov PXA2XX_TIMER_HAVE_TM4, false), 531797e9542SDmitry Eremin-Solenikov DEFINE_PROP_END_OF_LIST(), 532797e9542SDmitry Eremin-Solenikov }; 533797e9542SDmitry Eremin-Solenikov 534999e12bbSAnthony Liguori static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data) 535999e12bbSAnthony Liguori { 53639bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 537999e12bbSAnthony Liguori SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 538999e12bbSAnthony Liguori 539999e12bbSAnthony Liguori k->init = pxa2xx_timer_init; 54039bffca2SAnthony Liguori dc->desc = "PXA25x timer"; 54139bffca2SAnthony Liguori dc->vmsd = &vmstate_pxa2xx_timer_regs; 54239bffca2SAnthony Liguori dc->props = pxa25x_timer_dev_properties; 543999e12bbSAnthony Liguori } 544999e12bbSAnthony Liguori 5458c43a6f0SAndreas Färber static const TypeInfo pxa25x_timer_dev_info = { 546999e12bbSAnthony Liguori .name = "pxa25x-timer", 54739bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 54839bffca2SAnthony Liguori .instance_size = sizeof(PXA2xxTimerInfo), 549999e12bbSAnthony Liguori .class_init = pxa25x_timer_dev_class_init, 550999e12bbSAnthony Liguori }; 551999e12bbSAnthony Liguori 552999e12bbSAnthony Liguori static Property pxa27x_timer_dev_properties[] = { 553797e9542SDmitry Eremin-Solenikov DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ), 554797e9542SDmitry Eremin-Solenikov DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, 555797e9542SDmitry Eremin-Solenikov PXA2XX_TIMER_HAVE_TM4, true), 556797e9542SDmitry Eremin-Solenikov DEFINE_PROP_END_OF_LIST(), 557999e12bbSAnthony Liguori }; 558999e12bbSAnthony Liguori 559999e12bbSAnthony Liguori static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data) 560999e12bbSAnthony Liguori { 56139bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 562999e12bbSAnthony Liguori SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 563999e12bbSAnthony Liguori 564999e12bbSAnthony Liguori k->init = pxa2xx_timer_init; 56539bffca2SAnthony Liguori dc->desc = "PXA27x timer"; 56639bffca2SAnthony Liguori dc->vmsd = &vmstate_pxa2xx_timer_regs; 56739bffca2SAnthony Liguori dc->props = pxa27x_timer_dev_properties; 568999e12bbSAnthony Liguori } 569999e12bbSAnthony Liguori 5708c43a6f0SAndreas Färber static const TypeInfo pxa27x_timer_dev_info = { 571999e12bbSAnthony Liguori .name = "pxa27x-timer", 57239bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 57339bffca2SAnthony Liguori .instance_size = sizeof(PXA2xxTimerInfo), 574999e12bbSAnthony Liguori .class_init = pxa27x_timer_dev_class_init, 575797e9542SDmitry Eremin-Solenikov }; 576797e9542SDmitry Eremin-Solenikov 57783f7d43aSAndreas Färber static void pxa2xx_timer_register_types(void) 578797e9542SDmitry Eremin-Solenikov { 57939bffca2SAnthony Liguori type_register_static(&pxa25x_timer_dev_info); 58039bffca2SAnthony Liguori type_register_static(&pxa27x_timer_dev_info); 58183f7d43aSAndreas Färber } 58283f7d43aSAndreas Färber 58383f7d43aSAndreas Färber type_init(pxa2xx_timer_register_types) 584