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 10*8ef94f0bSPeter Maydell #include "qemu/osdep.h" 1183c9f4caSPaolo Bonzini #include "hw/hw.h" 121de7afc9SPaolo Bonzini #include "qemu/timer.h" 139c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 140d09e41aSPaolo Bonzini #include "hw/arm/pxa.h" 1583c9f4caSPaolo Bonzini #include "hw/sysbus.h" 16a171fe39Sbalrog 17a171fe39Sbalrog #define OSMR0 0x00 18a171fe39Sbalrog #define OSMR1 0x04 19a171fe39Sbalrog #define OSMR2 0x08 20a171fe39Sbalrog #define OSMR3 0x0c 21a171fe39Sbalrog #define OSMR4 0x80 22a171fe39Sbalrog #define OSMR5 0x84 23a171fe39Sbalrog #define OSMR6 0x88 24a171fe39Sbalrog #define OSMR7 0x8c 25a171fe39Sbalrog #define OSMR8 0x90 26a171fe39Sbalrog #define OSMR9 0x94 27a171fe39Sbalrog #define OSMR10 0x98 28a171fe39Sbalrog #define OSMR11 0x9c 29a171fe39Sbalrog #define OSCR 0x10 /* OS Timer Count */ 30a171fe39Sbalrog #define OSCR4 0x40 31a171fe39Sbalrog #define OSCR5 0x44 32a171fe39Sbalrog #define OSCR6 0x48 33a171fe39Sbalrog #define OSCR7 0x4c 34a171fe39Sbalrog #define OSCR8 0x50 35a171fe39Sbalrog #define OSCR9 0x54 36a171fe39Sbalrog #define OSCR10 0x58 37a171fe39Sbalrog #define OSCR11 0x5c 38a171fe39Sbalrog #define OSSR 0x14 /* Timer status register */ 39a171fe39Sbalrog #define OWER 0x18 40a171fe39Sbalrog #define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */ 41a171fe39Sbalrog #define OMCR4 0xc0 /* OS Match Control registers */ 42a171fe39Sbalrog #define OMCR5 0xc4 43a171fe39Sbalrog #define OMCR6 0xc8 44a171fe39Sbalrog #define OMCR7 0xcc 45a171fe39Sbalrog #define OMCR8 0xd0 46a171fe39Sbalrog #define OMCR9 0xd4 47a171fe39Sbalrog #define OMCR10 0xd8 48a171fe39Sbalrog #define OMCR11 0xdc 49a171fe39Sbalrog #define OSNR 0x20 50a171fe39Sbalrog 51a171fe39Sbalrog #define PXA25X_FREQ 3686400 /* 3.6864 MHz */ 52a171fe39Sbalrog #define PXA27X_FREQ 3250000 /* 3.25 MHz */ 53a171fe39Sbalrog 54a171fe39Sbalrog static int pxa2xx_timer4_freq[8] = { 55a171fe39Sbalrog [0] = 0, 56a171fe39Sbalrog [1] = 32768, 57a171fe39Sbalrog [2] = 1000, 58a171fe39Sbalrog [3] = 1, 59a171fe39Sbalrog [4] = 1000000, 60a171fe39Sbalrog /* [5] is the "Externally supplied clock". Assign if necessary. */ 61a171fe39Sbalrog [5 ... 7] = 0, 62a171fe39Sbalrog }; 63a171fe39Sbalrog 64feea4361SAndreas Färber #define TYPE_PXA2XX_TIMER "pxa2xx-timer" 65feea4361SAndreas Färber #define PXA2XX_TIMER(obj) \ 66feea4361SAndreas Färber OBJECT_CHECK(PXA2xxTimerInfo, (obj), TYPE_PXA2XX_TIMER) 67feea4361SAndreas Färber 68797e9542SDmitry Eremin-Solenikov typedef struct PXA2xxTimerInfo PXA2xxTimerInfo; 69797e9542SDmitry Eremin-Solenikov 70bc24a225SPaul Brook typedef struct { 71a171fe39Sbalrog uint32_t value; 725251d196SAndrzej Zaborowski qemu_irq irq; 73a171fe39Sbalrog QEMUTimer *qtimer; 74a171fe39Sbalrog int num; 75797e9542SDmitry Eremin-Solenikov PXA2xxTimerInfo *info; 76bc24a225SPaul Brook } PXA2xxTimer0; 77a171fe39Sbalrog 78bc24a225SPaul Brook typedef struct { 79bc24a225SPaul Brook PXA2xxTimer0 tm; 80a171fe39Sbalrog int32_t oldclock; 81a171fe39Sbalrog int32_t clock; 82a171fe39Sbalrog uint64_t lastload; 83a171fe39Sbalrog uint32_t freq; 84a171fe39Sbalrog uint32_t control; 85bc24a225SPaul Brook } PXA2xxTimer4; 86a171fe39Sbalrog 87797e9542SDmitry Eremin-Solenikov struct PXA2xxTimerInfo { 88feea4361SAndreas Färber SysBusDevice parent_obj; 89feea4361SAndreas Färber 90b755bde3SBenoît Canet MemoryRegion iomem; 91797e9542SDmitry Eremin-Solenikov uint32_t flags; 92797e9542SDmitry Eremin-Solenikov 93a171fe39Sbalrog int32_t clock; 94a171fe39Sbalrog int32_t oldclock; 95a171fe39Sbalrog uint64_t lastload; 96a171fe39Sbalrog uint32_t freq; 97bc24a225SPaul Brook PXA2xxTimer0 timer[4]; 98a171fe39Sbalrog uint32_t events; 99a171fe39Sbalrog uint32_t irq_enabled; 100a171fe39Sbalrog uint32_t reset3; 101a171fe39Sbalrog uint32_t snapshot; 102797e9542SDmitry Eremin-Solenikov 1034ff927ccSDmitry Eremin-Solenikov qemu_irq irq4; 104797e9542SDmitry Eremin-Solenikov PXA2xxTimer4 tm4[8]; 105797e9542SDmitry Eremin-Solenikov }; 106797e9542SDmitry Eremin-Solenikov 107797e9542SDmitry Eremin-Solenikov #define PXA2XX_TIMER_HAVE_TM4 0 108797e9542SDmitry Eremin-Solenikov 109797e9542SDmitry Eremin-Solenikov static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s) 110797e9542SDmitry Eremin-Solenikov { 111797e9542SDmitry Eremin-Solenikov return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4); 112797e9542SDmitry Eremin-Solenikov } 113a171fe39Sbalrog 114a171fe39Sbalrog static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu) 115a171fe39Sbalrog { 116d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 117a171fe39Sbalrog int i; 118a171fe39Sbalrog uint32_t now_vm; 119a171fe39Sbalrog uint64_t new_qemu; 120a171fe39Sbalrog 121a171fe39Sbalrog now_vm = s->clock + 1226ee093c9SJuan Quintela muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec()); 123a171fe39Sbalrog 124a171fe39Sbalrog for (i = 0; i < 4; i ++) { 125a171fe39Sbalrog new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm), 1266ee093c9SJuan Quintela get_ticks_per_sec(), s->freq); 127bc72ad67SAlex Bligh timer_mod(s->timer[i].qtimer, new_qemu); 128a171fe39Sbalrog } 129a171fe39Sbalrog } 130a171fe39Sbalrog 131a171fe39Sbalrog static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) 132a171fe39Sbalrog { 133d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 134a171fe39Sbalrog uint32_t now_vm; 135a171fe39Sbalrog uint64_t new_qemu; 136a171fe39Sbalrog static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 }; 137a171fe39Sbalrog int counter; 138a171fe39Sbalrog 139a171fe39Sbalrog if (s->tm4[n].control & (1 << 7)) 140a171fe39Sbalrog counter = n; 141a171fe39Sbalrog else 142a171fe39Sbalrog counter = counters[n]; 143a171fe39Sbalrog 144a171fe39Sbalrog if (!s->tm4[counter].freq) { 145bc72ad67SAlex Bligh timer_del(s->tm4[n].tm.qtimer); 146a171fe39Sbalrog return; 147a171fe39Sbalrog } 148a171fe39Sbalrog 149a171fe39Sbalrog now_vm = s->tm4[counter].clock + muldiv64(now_qemu - 150a171fe39Sbalrog s->tm4[counter].lastload, 1516ee093c9SJuan Quintela s->tm4[counter].freq, get_ticks_per_sec()); 152a171fe39Sbalrog 1533bdd58a4Sbalrog new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm), 1546ee093c9SJuan Quintela get_ticks_per_sec(), s->tm4[counter].freq); 155bc72ad67SAlex Bligh timer_mod(s->tm4[n].tm.qtimer, new_qemu); 156a171fe39Sbalrog } 157a171fe39Sbalrog 158a8170e5eSAvi Kivity static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, 159b755bde3SBenoît Canet unsigned size) 160a171fe39Sbalrog { 161d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 162a171fe39Sbalrog int tm = 0; 163a171fe39Sbalrog 164a171fe39Sbalrog switch (offset) { 165a171fe39Sbalrog case OSMR3: tm ++; 166de16017dSPeter Maydell /* fall through */ 167a171fe39Sbalrog case OSMR2: tm ++; 168de16017dSPeter Maydell /* fall through */ 169a171fe39Sbalrog case OSMR1: tm ++; 170de16017dSPeter Maydell /* fall through */ 171a171fe39Sbalrog case OSMR0: 172a171fe39Sbalrog return s->timer[tm].value; 173a171fe39Sbalrog case OSMR11: tm ++; 174de16017dSPeter Maydell /* fall through */ 175a171fe39Sbalrog case OSMR10: tm ++; 176de16017dSPeter Maydell /* fall through */ 177a171fe39Sbalrog case OSMR9: tm ++; 178de16017dSPeter Maydell /* fall through */ 179a171fe39Sbalrog case OSMR8: tm ++; 180de16017dSPeter Maydell /* fall through */ 181a171fe39Sbalrog case OSMR7: tm ++; 182de16017dSPeter Maydell /* fall through */ 183a171fe39Sbalrog case OSMR6: tm ++; 184de16017dSPeter Maydell /* fall through */ 185a171fe39Sbalrog case OSMR5: tm ++; 186de16017dSPeter Maydell /* fall through */ 187a171fe39Sbalrog case OSMR4: 188797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 189a171fe39Sbalrog goto badreg; 1903bdd58a4Sbalrog return s->tm4[tm].tm.value; 191a171fe39Sbalrog case OSCR: 192bc72ad67SAlex Bligh return s->clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - 1936ee093c9SJuan Quintela s->lastload, s->freq, get_ticks_per_sec()); 194a171fe39Sbalrog case OSCR11: tm ++; 195de16017dSPeter Maydell /* fall through */ 196a171fe39Sbalrog case OSCR10: tm ++; 197de16017dSPeter Maydell /* fall through */ 198a171fe39Sbalrog case OSCR9: tm ++; 199de16017dSPeter Maydell /* fall through */ 200a171fe39Sbalrog case OSCR8: tm ++; 201de16017dSPeter Maydell /* fall through */ 202a171fe39Sbalrog case OSCR7: tm ++; 203de16017dSPeter Maydell /* fall through */ 204a171fe39Sbalrog case OSCR6: tm ++; 205de16017dSPeter Maydell /* fall through */ 206a171fe39Sbalrog case OSCR5: tm ++; 207de16017dSPeter Maydell /* fall through */ 208a171fe39Sbalrog case OSCR4: 209797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 210a171fe39Sbalrog goto badreg; 211a171fe39Sbalrog 212a171fe39Sbalrog if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) { 213a171fe39Sbalrog if (s->tm4[tm - 1].freq) 214a171fe39Sbalrog s->snapshot = s->tm4[tm - 1].clock + muldiv64( 215bc72ad67SAlex Bligh qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - 216a171fe39Sbalrog s->tm4[tm - 1].lastload, 2176ee093c9SJuan Quintela s->tm4[tm - 1].freq, get_ticks_per_sec()); 218a171fe39Sbalrog else 219a171fe39Sbalrog s->snapshot = s->tm4[tm - 1].clock; 220a171fe39Sbalrog } 221a171fe39Sbalrog 222a171fe39Sbalrog if (!s->tm4[tm].freq) 223a171fe39Sbalrog return s->tm4[tm].clock; 224bc72ad67SAlex Bligh return s->tm4[tm].clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - 2256ee093c9SJuan Quintela s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec()); 226a171fe39Sbalrog case OIER: 227a171fe39Sbalrog return s->irq_enabled; 228a171fe39Sbalrog case OSSR: /* Status register */ 229a171fe39Sbalrog return s->events; 230a171fe39Sbalrog case OWER: 231a171fe39Sbalrog return s->reset3; 232a171fe39Sbalrog case OMCR11: tm ++; 233de16017dSPeter Maydell /* fall through */ 234a171fe39Sbalrog case OMCR10: tm ++; 235de16017dSPeter Maydell /* fall through */ 236a171fe39Sbalrog case OMCR9: tm ++; 237de16017dSPeter Maydell /* fall through */ 238a171fe39Sbalrog case OMCR8: tm ++; 239de16017dSPeter Maydell /* fall through */ 240a171fe39Sbalrog case OMCR7: tm ++; 241de16017dSPeter Maydell /* fall through */ 242a171fe39Sbalrog case OMCR6: tm ++; 243de16017dSPeter Maydell /* fall through */ 244a171fe39Sbalrog case OMCR5: tm ++; 245de16017dSPeter Maydell /* fall through */ 246a171fe39Sbalrog case OMCR4: 247797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 248a171fe39Sbalrog goto badreg; 249a171fe39Sbalrog return s->tm4[tm].control; 250a171fe39Sbalrog case OSNR: 251a171fe39Sbalrog return s->snapshot; 252a171fe39Sbalrog default: 253a171fe39Sbalrog badreg: 2542ac71179SPaul Brook hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset); 255a171fe39Sbalrog } 256a171fe39Sbalrog 257a171fe39Sbalrog return 0; 258a171fe39Sbalrog } 259a171fe39Sbalrog 260a8170e5eSAvi Kivity static void pxa2xx_timer_write(void *opaque, hwaddr offset, 261b755bde3SBenoît Canet uint64_t value, unsigned size) 262a171fe39Sbalrog { 263a171fe39Sbalrog int i, tm = 0; 264d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 265a171fe39Sbalrog 266a171fe39Sbalrog switch (offset) { 267a171fe39Sbalrog case OSMR3: tm ++; 268de16017dSPeter Maydell /* fall through */ 269a171fe39Sbalrog case OSMR2: tm ++; 270de16017dSPeter Maydell /* fall through */ 271a171fe39Sbalrog case OSMR1: tm ++; 272de16017dSPeter Maydell /* fall through */ 273a171fe39Sbalrog case OSMR0: 274a171fe39Sbalrog s->timer[tm].value = value; 275bc72ad67SAlex Bligh pxa2xx_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 276a171fe39Sbalrog break; 277a171fe39Sbalrog case OSMR11: tm ++; 278de16017dSPeter Maydell /* fall through */ 279a171fe39Sbalrog case OSMR10: tm ++; 280de16017dSPeter Maydell /* fall through */ 281a171fe39Sbalrog case OSMR9: tm ++; 282de16017dSPeter Maydell /* fall through */ 283a171fe39Sbalrog case OSMR8: tm ++; 284de16017dSPeter Maydell /* fall through */ 285a171fe39Sbalrog case OSMR7: tm ++; 286de16017dSPeter Maydell /* fall through */ 287a171fe39Sbalrog case OSMR6: tm ++; 288de16017dSPeter Maydell /* fall through */ 289a171fe39Sbalrog case OSMR5: tm ++; 290de16017dSPeter Maydell /* fall through */ 291a171fe39Sbalrog case OSMR4: 292797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 293a171fe39Sbalrog goto badreg; 2943bdd58a4Sbalrog s->tm4[tm].tm.value = value; 295bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); 296a171fe39Sbalrog break; 297a171fe39Sbalrog case OSCR: 298a171fe39Sbalrog s->oldclock = s->clock; 299bc72ad67SAlex Bligh s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 300a171fe39Sbalrog s->clock = value; 301a171fe39Sbalrog pxa2xx_timer_update(s, s->lastload); 302a171fe39Sbalrog break; 303a171fe39Sbalrog case OSCR11: tm ++; 304de16017dSPeter Maydell /* fall through */ 305a171fe39Sbalrog case OSCR10: tm ++; 306de16017dSPeter Maydell /* fall through */ 307a171fe39Sbalrog case OSCR9: tm ++; 308de16017dSPeter Maydell /* fall through */ 309a171fe39Sbalrog case OSCR8: tm ++; 310de16017dSPeter Maydell /* fall through */ 311a171fe39Sbalrog case OSCR7: tm ++; 312de16017dSPeter Maydell /* fall through */ 313a171fe39Sbalrog case OSCR6: tm ++; 314de16017dSPeter Maydell /* fall through */ 315a171fe39Sbalrog case OSCR5: tm ++; 316de16017dSPeter Maydell /* fall through */ 317a171fe39Sbalrog case OSCR4: 318797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 319a171fe39Sbalrog goto badreg; 320a171fe39Sbalrog s->tm4[tm].oldclock = s->tm4[tm].clock; 321bc72ad67SAlex Bligh s->tm4[tm].lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 322a171fe39Sbalrog s->tm4[tm].clock = value; 323a171fe39Sbalrog pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm); 324a171fe39Sbalrog break; 325a171fe39Sbalrog case OIER: 326a171fe39Sbalrog s->irq_enabled = value & 0xfff; 327a171fe39Sbalrog break; 328a171fe39Sbalrog case OSSR: /* Status register */ 3298034ce7dSAndrzej Zaborowski value &= s->events; 330a171fe39Sbalrog s->events &= ~value; 3318034ce7dSAndrzej Zaborowski for (i = 0; i < 4; i ++, value >>= 1) 3328034ce7dSAndrzej Zaborowski if (value & 1) 3335251d196SAndrzej Zaborowski qemu_irq_lower(s->timer[i].irq); 3348034ce7dSAndrzej Zaborowski if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value) 3354ff927ccSDmitry Eremin-Solenikov qemu_irq_lower(s->irq4); 336a171fe39Sbalrog break; 337a171fe39Sbalrog case OWER: /* XXX: Reset on OSMR3 match? */ 338a171fe39Sbalrog s->reset3 = value; 339a171fe39Sbalrog break; 340a171fe39Sbalrog case OMCR7: tm ++; 341de16017dSPeter Maydell /* fall through */ 342a171fe39Sbalrog case OMCR6: tm ++; 343de16017dSPeter Maydell /* fall through */ 344a171fe39Sbalrog case OMCR5: tm ++; 345de16017dSPeter Maydell /* fall through */ 346a171fe39Sbalrog case OMCR4: 347797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 348a171fe39Sbalrog goto badreg; 349a171fe39Sbalrog s->tm4[tm].control = value & 0x0ff; 350a171fe39Sbalrog /* XXX Stop if running (shouldn't happen) */ 351a171fe39Sbalrog if ((value & (1 << 7)) || tm == 0) 352a171fe39Sbalrog s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7]; 353a171fe39Sbalrog else { 354a171fe39Sbalrog s->tm4[tm].freq = 0; 355bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); 356a171fe39Sbalrog } 357a171fe39Sbalrog break; 358a171fe39Sbalrog case OMCR11: tm ++; 359de16017dSPeter Maydell /* fall through */ 360a171fe39Sbalrog case OMCR10: tm ++; 361de16017dSPeter Maydell /* fall through */ 362a171fe39Sbalrog case OMCR9: tm ++; 363de16017dSPeter Maydell /* fall through */ 364a171fe39Sbalrog case OMCR8: tm += 4; 365797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 366a171fe39Sbalrog goto badreg; 367a171fe39Sbalrog s->tm4[tm].control = value & 0x3ff; 368a171fe39Sbalrog /* XXX Stop if running (shouldn't happen) */ 369a171fe39Sbalrog if ((value & (1 << 7)) || !(tm & 1)) 370a171fe39Sbalrog s->tm4[tm].freq = 371a171fe39Sbalrog pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)]; 372a171fe39Sbalrog else { 373a171fe39Sbalrog s->tm4[tm].freq = 0; 374bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); 375a171fe39Sbalrog } 376a171fe39Sbalrog break; 377a171fe39Sbalrog default: 378a171fe39Sbalrog badreg: 3792ac71179SPaul Brook hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset); 380a171fe39Sbalrog } 381a171fe39Sbalrog } 382a171fe39Sbalrog 383b755bde3SBenoît Canet static const MemoryRegionOps pxa2xx_timer_ops = { 384b755bde3SBenoît Canet .read = pxa2xx_timer_read, 385b755bde3SBenoît Canet .write = pxa2xx_timer_write, 386b755bde3SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 387a171fe39Sbalrog }; 388a171fe39Sbalrog 389a171fe39Sbalrog static void pxa2xx_timer_tick(void *opaque) 390a171fe39Sbalrog { 391bc24a225SPaul Brook PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque; 392797e9542SDmitry Eremin-Solenikov PXA2xxTimerInfo *i = t->info; 393a171fe39Sbalrog 394a171fe39Sbalrog if (i->irq_enabled & (1 << t->num)) { 395a171fe39Sbalrog i->events |= 1 << t->num; 3965251d196SAndrzej Zaborowski qemu_irq_raise(t->irq); 397a171fe39Sbalrog } 398a171fe39Sbalrog 399a171fe39Sbalrog if (t->num == 3) 400a171fe39Sbalrog if (i->reset3 & 1) { 401a171fe39Sbalrog i->reset3 = 0; 4023f582262Sbalrog qemu_system_reset_request(); 403a171fe39Sbalrog } 404a171fe39Sbalrog } 405a171fe39Sbalrog 406a171fe39Sbalrog static void pxa2xx_timer_tick4(void *opaque) 407a171fe39Sbalrog { 408bc24a225SPaul Brook PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque; 409d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info; 410a171fe39Sbalrog 4113bdd58a4Sbalrog pxa2xx_timer_tick(&t->tm); 412a171fe39Sbalrog if (t->control & (1 << 3)) 413a171fe39Sbalrog t->clock = 0; 414a171fe39Sbalrog if (t->control & (1 << 6)) 415bc72ad67SAlex Bligh pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4); 4164ff927ccSDmitry Eremin-Solenikov if (i->events & 0xff0) 4174ff927ccSDmitry Eremin-Solenikov qemu_irq_raise(i->irq4); 418a171fe39Sbalrog } 419a171fe39Sbalrog 420797e9542SDmitry Eremin-Solenikov static int pxa25x_timer_post_load(void *opaque, int version_id) 421aa941b94Sbalrog { 422d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 423aa941b94Sbalrog int64_t now; 424aa941b94Sbalrog int i; 425aa941b94Sbalrog 426bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 427aa941b94Sbalrog pxa2xx_timer_update(s, now); 428aa941b94Sbalrog 429797e9542SDmitry Eremin-Solenikov if (pxa2xx_timer_has_tm4(s)) 430797e9542SDmitry Eremin-Solenikov for (i = 0; i < 8; i ++) 431aa941b94Sbalrog pxa2xx_timer_update4(s, now, i); 432aa941b94Sbalrog 433aa941b94Sbalrog return 0; 434aa941b94Sbalrog } 435aa941b94Sbalrog 436797e9542SDmitry Eremin-Solenikov static int pxa2xx_timer_init(SysBusDevice *dev) 437a171fe39Sbalrog { 438feea4361SAndreas Färber PXA2xxTimerInfo *s = PXA2XX_TIMER(dev); 439a171fe39Sbalrog int i; 440a171fe39Sbalrog 441a171fe39Sbalrog s->irq_enabled = 0; 442a171fe39Sbalrog s->oldclock = 0; 443a171fe39Sbalrog s->clock = 0; 444bc72ad67SAlex Bligh s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 445a171fe39Sbalrog s->reset3 = 0; 446a171fe39Sbalrog 447a171fe39Sbalrog for (i = 0; i < 4; i ++) { 448a171fe39Sbalrog s->timer[i].value = 0; 4495251d196SAndrzej Zaborowski sysbus_init_irq(dev, &s->timer[i].irq); 450a171fe39Sbalrog s->timer[i].info = s; 451a171fe39Sbalrog s->timer[i].num = i; 452bc72ad67SAlex Bligh s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 453a171fe39Sbalrog pxa2xx_timer_tick, &s->timer[i]); 454a171fe39Sbalrog } 455797e9542SDmitry Eremin-Solenikov if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) { 4564ff927ccSDmitry Eremin-Solenikov sysbus_init_irq(dev, &s->irq4); 457a171fe39Sbalrog 458a171fe39Sbalrog for (i = 0; i < 8; i ++) { 4593bdd58a4Sbalrog s->tm4[i].tm.value = 0; 4603bdd58a4Sbalrog s->tm4[i].tm.info = s; 4613bdd58a4Sbalrog s->tm4[i].tm.num = i + 4; 462a171fe39Sbalrog s->tm4[i].freq = 0; 463a171fe39Sbalrog s->tm4[i].control = 0x0; 464bc72ad67SAlex Bligh s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 465a171fe39Sbalrog pxa2xx_timer_tick4, &s->tm4[i]); 466a171fe39Sbalrog } 467a171fe39Sbalrog } 468797e9542SDmitry Eremin-Solenikov 469853dca12SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_timer_ops, s, 470b755bde3SBenoît Canet "pxa2xx-timer", 0x00001000); 471750ecd44SAvi Kivity sysbus_init_mmio(dev, &s->iomem); 472797e9542SDmitry Eremin-Solenikov 473797e9542SDmitry Eremin-Solenikov return 0; 474797e9542SDmitry Eremin-Solenikov } 475797e9542SDmitry Eremin-Solenikov 476797e9542SDmitry Eremin-Solenikov static const VMStateDescription vmstate_pxa2xx_timer0_regs = { 477797e9542SDmitry Eremin-Solenikov .name = "pxa2xx_timer0", 4788034ce7dSAndrzej Zaborowski .version_id = 2, 4798034ce7dSAndrzej Zaborowski .minimum_version_id = 2, 480797e9542SDmitry Eremin-Solenikov .fields = (VMStateField[]) { 481797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(value, PXA2xxTimer0), 482797e9542SDmitry Eremin-Solenikov VMSTATE_END_OF_LIST(), 483797e9542SDmitry Eremin-Solenikov }, 484797e9542SDmitry Eremin-Solenikov }; 485797e9542SDmitry Eremin-Solenikov 486797e9542SDmitry Eremin-Solenikov static const VMStateDescription vmstate_pxa2xx_timer4_regs = { 487797e9542SDmitry Eremin-Solenikov .name = "pxa2xx_timer4", 488797e9542SDmitry Eremin-Solenikov .version_id = 1, 489797e9542SDmitry Eremin-Solenikov .minimum_version_id = 1, 490797e9542SDmitry Eremin-Solenikov .fields = (VMStateField[]) { 491797e9542SDmitry Eremin-Solenikov VMSTATE_STRUCT(tm, PXA2xxTimer4, 1, 492797e9542SDmitry Eremin-Solenikov vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), 493797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(oldclock, PXA2xxTimer4), 494797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(clock, PXA2xxTimer4), 495797e9542SDmitry Eremin-Solenikov VMSTATE_UINT64(lastload, PXA2xxTimer4), 496797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(freq, PXA2xxTimer4), 497797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(control, PXA2xxTimer4), 498797e9542SDmitry Eremin-Solenikov VMSTATE_END_OF_LIST(), 499797e9542SDmitry Eremin-Solenikov }, 500797e9542SDmitry Eremin-Solenikov }; 501797e9542SDmitry Eremin-Solenikov 502797e9542SDmitry Eremin-Solenikov static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id) 503797e9542SDmitry Eremin-Solenikov { 504797e9542SDmitry Eremin-Solenikov return pxa2xx_timer_has_tm4(opaque); 505797e9542SDmitry Eremin-Solenikov } 506797e9542SDmitry Eremin-Solenikov 507797e9542SDmitry Eremin-Solenikov static const VMStateDescription vmstate_pxa2xx_timer_regs = { 508797e9542SDmitry Eremin-Solenikov .name = "pxa2xx_timer", 509797e9542SDmitry Eremin-Solenikov .version_id = 1, 510797e9542SDmitry Eremin-Solenikov .minimum_version_id = 1, 511797e9542SDmitry Eremin-Solenikov .post_load = pxa25x_timer_post_load, 512797e9542SDmitry Eremin-Solenikov .fields = (VMStateField[]) { 513797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(clock, PXA2xxTimerInfo), 514797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(oldclock, PXA2xxTimerInfo), 515797e9542SDmitry Eremin-Solenikov VMSTATE_UINT64(lastload, PXA2xxTimerInfo), 516797e9542SDmitry Eremin-Solenikov VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1, 517797e9542SDmitry Eremin-Solenikov vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), 518797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(events, PXA2xxTimerInfo), 519797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo), 520797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(reset3, PXA2xxTimerInfo), 521797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(snapshot, PXA2xxTimerInfo), 522797e9542SDmitry Eremin-Solenikov VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8, 523797e9542SDmitry Eremin-Solenikov pxa2xx_timer_has_tm4_test, 0, 524797e9542SDmitry Eremin-Solenikov vmstate_pxa2xx_timer4_regs, PXA2xxTimer4), 525797e9542SDmitry Eremin-Solenikov VMSTATE_END_OF_LIST(), 526797e9542SDmitry Eremin-Solenikov } 527797e9542SDmitry Eremin-Solenikov }; 528797e9542SDmitry Eremin-Solenikov 529999e12bbSAnthony Liguori static Property pxa25x_timer_dev_properties[] = { 530797e9542SDmitry Eremin-Solenikov DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ), 531797e9542SDmitry Eremin-Solenikov DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, 532797e9542SDmitry Eremin-Solenikov PXA2XX_TIMER_HAVE_TM4, false), 533797e9542SDmitry Eremin-Solenikov DEFINE_PROP_END_OF_LIST(), 534797e9542SDmitry Eremin-Solenikov }; 535797e9542SDmitry Eremin-Solenikov 536999e12bbSAnthony Liguori static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data) 537999e12bbSAnthony Liguori { 53839bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 539999e12bbSAnthony Liguori 54039bffca2SAnthony Liguori dc->desc = "PXA25x timer"; 54139bffca2SAnthony Liguori dc->props = pxa25x_timer_dev_properties; 542999e12bbSAnthony Liguori } 543999e12bbSAnthony Liguori 5448c43a6f0SAndreas Färber static const TypeInfo pxa25x_timer_dev_info = { 545999e12bbSAnthony Liguori .name = "pxa25x-timer", 546feea4361SAndreas Färber .parent = TYPE_PXA2XX_TIMER, 54739bffca2SAnthony Liguori .instance_size = sizeof(PXA2xxTimerInfo), 548999e12bbSAnthony Liguori .class_init = pxa25x_timer_dev_class_init, 549999e12bbSAnthony Liguori }; 550999e12bbSAnthony Liguori 551999e12bbSAnthony Liguori static Property pxa27x_timer_dev_properties[] = { 552797e9542SDmitry Eremin-Solenikov DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ), 553797e9542SDmitry Eremin-Solenikov DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, 554797e9542SDmitry Eremin-Solenikov PXA2XX_TIMER_HAVE_TM4, true), 555797e9542SDmitry Eremin-Solenikov DEFINE_PROP_END_OF_LIST(), 556999e12bbSAnthony Liguori }; 557999e12bbSAnthony Liguori 558999e12bbSAnthony Liguori static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data) 559999e12bbSAnthony Liguori { 56039bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 561999e12bbSAnthony Liguori 56239bffca2SAnthony Liguori dc->desc = "PXA27x timer"; 56339bffca2SAnthony Liguori dc->props = pxa27x_timer_dev_properties; 564999e12bbSAnthony Liguori } 565999e12bbSAnthony Liguori 5668c43a6f0SAndreas Färber static const TypeInfo pxa27x_timer_dev_info = { 567999e12bbSAnthony Liguori .name = "pxa27x-timer", 568feea4361SAndreas Färber .parent = TYPE_PXA2XX_TIMER, 56939bffca2SAnthony Liguori .instance_size = sizeof(PXA2xxTimerInfo), 570999e12bbSAnthony Liguori .class_init = pxa27x_timer_dev_class_init, 571797e9542SDmitry Eremin-Solenikov }; 572797e9542SDmitry Eremin-Solenikov 573feea4361SAndreas Färber static void pxa2xx_timer_class_init(ObjectClass *oc, void *data) 574feea4361SAndreas Färber { 575feea4361SAndreas Färber DeviceClass *dc = DEVICE_CLASS(oc); 576feea4361SAndreas Färber SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(oc); 577feea4361SAndreas Färber 578feea4361SAndreas Färber sdc->init = pxa2xx_timer_init; 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), 586feea4361SAndreas Färber .abstract = true, 587feea4361SAndreas Färber .class_init = pxa2xx_timer_class_init, 588feea4361SAndreas Färber }; 589feea4361SAndreas Färber 59083f7d43aSAndreas Färber static void pxa2xx_timer_register_types(void) 591797e9542SDmitry Eremin-Solenikov { 592feea4361SAndreas Färber type_register_static(&pxa2xx_timer_type_info); 59339bffca2SAnthony Liguori type_register_static(&pxa25x_timer_dev_info); 59439bffca2SAnthony Liguori type_register_static(&pxa27x_timer_dev_info); 59583f7d43aSAndreas Färber } 59683f7d43aSAndreas Färber 59783f7d43aSAndreas Färber type_init(pxa2xx_timer_register_types) 598