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 108ef94f0bSPeter 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 + 12273bcb24dSRutuja Shah muldiv64(now_qemu - s->lastload, s->freq, NANOSECONDS_PER_SECOND); 123a171fe39Sbalrog 124a171fe39Sbalrog for (i = 0; i < 4; i ++) { 125a171fe39Sbalrog new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm), 12673bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, 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, 15173bcb24dSRutuja Shah s->tm4[counter].freq, NANOSECONDS_PER_SECOND); 152a171fe39Sbalrog 1533bdd58a4Sbalrog new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm), 15473bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, 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) - 19373bcb24dSRutuja Shah s->lastload, s->freq, NANOSECONDS_PER_SECOND); 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, 21773bcb24dSRutuja Shah s->tm4[tm - 1].freq, NANOSECONDS_PER_SECOND); 218a171fe39Sbalrog else 219a171fe39Sbalrog s->snapshot = s->tm4[tm - 1].clock; 220a171fe39Sbalrog } 221a171fe39Sbalrog 222a171fe39Sbalrog if (!s->tm4[tm].freq) 223a171fe39Sbalrog return s->tm4[tm].clock; 22473bcb24dSRutuja Shah return s->tm4[tm].clock + 22573bcb24dSRutuja Shah muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - 22673bcb24dSRutuja Shah s->tm4[tm].lastload, s->tm4[tm].freq, 22773bcb24dSRutuja Shah NANOSECONDS_PER_SECOND); 228a171fe39Sbalrog case OIER: 229a171fe39Sbalrog return s->irq_enabled; 230a171fe39Sbalrog case OSSR: /* Status register */ 231a171fe39Sbalrog return s->events; 232a171fe39Sbalrog case OWER: 233a171fe39Sbalrog return s->reset3; 234a171fe39Sbalrog case OMCR11: tm ++; 235de16017dSPeter Maydell /* fall through */ 236a171fe39Sbalrog case OMCR10: tm ++; 237de16017dSPeter Maydell /* fall through */ 238a171fe39Sbalrog case OMCR9: tm ++; 239de16017dSPeter Maydell /* fall through */ 240a171fe39Sbalrog case OMCR8: tm ++; 241de16017dSPeter Maydell /* fall through */ 242a171fe39Sbalrog case OMCR7: tm ++; 243de16017dSPeter Maydell /* fall through */ 244a171fe39Sbalrog case OMCR6: tm ++; 245de16017dSPeter Maydell /* fall through */ 246a171fe39Sbalrog case OMCR5: tm ++; 247de16017dSPeter Maydell /* fall through */ 248a171fe39Sbalrog case OMCR4: 249797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 250a171fe39Sbalrog goto badreg; 251a171fe39Sbalrog return s->tm4[tm].control; 252a171fe39Sbalrog case OSNR: 253a171fe39Sbalrog return s->snapshot; 254a171fe39Sbalrog default: 255a171fe39Sbalrog badreg: 2562ac71179SPaul Brook hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset); 257a171fe39Sbalrog } 258a171fe39Sbalrog 259a171fe39Sbalrog return 0; 260a171fe39Sbalrog } 261a171fe39Sbalrog 262a8170e5eSAvi Kivity static void pxa2xx_timer_write(void *opaque, hwaddr offset, 263b755bde3SBenoît Canet uint64_t value, unsigned size) 264a171fe39Sbalrog { 265a171fe39Sbalrog int i, tm = 0; 266d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 267a171fe39Sbalrog 268a171fe39Sbalrog switch (offset) { 269a171fe39Sbalrog case OSMR3: tm ++; 270de16017dSPeter Maydell /* fall through */ 271a171fe39Sbalrog case OSMR2: tm ++; 272de16017dSPeter Maydell /* fall through */ 273a171fe39Sbalrog case OSMR1: tm ++; 274de16017dSPeter Maydell /* fall through */ 275a171fe39Sbalrog case OSMR0: 276a171fe39Sbalrog s->timer[tm].value = value; 277bc72ad67SAlex Bligh pxa2xx_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 278a171fe39Sbalrog break; 279a171fe39Sbalrog case OSMR11: tm ++; 280de16017dSPeter Maydell /* fall through */ 281a171fe39Sbalrog case OSMR10: tm ++; 282de16017dSPeter Maydell /* fall through */ 283a171fe39Sbalrog case OSMR9: tm ++; 284de16017dSPeter Maydell /* fall through */ 285a171fe39Sbalrog case OSMR8: tm ++; 286de16017dSPeter Maydell /* fall through */ 287a171fe39Sbalrog case OSMR7: tm ++; 288de16017dSPeter Maydell /* fall through */ 289a171fe39Sbalrog case OSMR6: tm ++; 290de16017dSPeter Maydell /* fall through */ 291a171fe39Sbalrog case OSMR5: tm ++; 292de16017dSPeter Maydell /* fall through */ 293a171fe39Sbalrog case OSMR4: 294797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 295a171fe39Sbalrog goto badreg; 2963bdd58a4Sbalrog s->tm4[tm].tm.value = value; 297bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); 298a171fe39Sbalrog break; 299a171fe39Sbalrog case OSCR: 300a171fe39Sbalrog s->oldclock = s->clock; 301bc72ad67SAlex Bligh s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 302a171fe39Sbalrog s->clock = value; 303a171fe39Sbalrog pxa2xx_timer_update(s, s->lastload); 304a171fe39Sbalrog break; 305a171fe39Sbalrog case OSCR11: tm ++; 306de16017dSPeter Maydell /* fall through */ 307a171fe39Sbalrog case OSCR10: tm ++; 308de16017dSPeter Maydell /* fall through */ 309a171fe39Sbalrog case OSCR9: tm ++; 310de16017dSPeter Maydell /* fall through */ 311a171fe39Sbalrog case OSCR8: tm ++; 312de16017dSPeter Maydell /* fall through */ 313a171fe39Sbalrog case OSCR7: tm ++; 314de16017dSPeter Maydell /* fall through */ 315a171fe39Sbalrog case OSCR6: tm ++; 316de16017dSPeter Maydell /* fall through */ 317a171fe39Sbalrog case OSCR5: tm ++; 318de16017dSPeter Maydell /* fall through */ 319a171fe39Sbalrog case OSCR4: 320797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 321a171fe39Sbalrog goto badreg; 322a171fe39Sbalrog s->tm4[tm].oldclock = s->tm4[tm].clock; 323bc72ad67SAlex Bligh s->tm4[tm].lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 324a171fe39Sbalrog s->tm4[tm].clock = value; 325a171fe39Sbalrog pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm); 326a171fe39Sbalrog break; 327a171fe39Sbalrog case OIER: 328a171fe39Sbalrog s->irq_enabled = value & 0xfff; 329a171fe39Sbalrog break; 330a171fe39Sbalrog case OSSR: /* Status register */ 3318034ce7dSAndrzej Zaborowski value &= s->events; 332a171fe39Sbalrog s->events &= ~value; 3338034ce7dSAndrzej Zaborowski for (i = 0; i < 4; i ++, value >>= 1) 3348034ce7dSAndrzej Zaborowski if (value & 1) 3355251d196SAndrzej Zaborowski qemu_irq_lower(s->timer[i].irq); 3368034ce7dSAndrzej Zaborowski if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value) 3374ff927ccSDmitry Eremin-Solenikov qemu_irq_lower(s->irq4); 338a171fe39Sbalrog break; 339a171fe39Sbalrog case OWER: /* XXX: Reset on OSMR3 match? */ 340a171fe39Sbalrog s->reset3 = value; 341a171fe39Sbalrog break; 342a171fe39Sbalrog case OMCR7: tm ++; 343de16017dSPeter Maydell /* fall through */ 344a171fe39Sbalrog case OMCR6: tm ++; 345de16017dSPeter Maydell /* fall through */ 346a171fe39Sbalrog case OMCR5: tm ++; 347de16017dSPeter Maydell /* fall through */ 348a171fe39Sbalrog case OMCR4: 349797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 350a171fe39Sbalrog goto badreg; 351a171fe39Sbalrog s->tm4[tm].control = value & 0x0ff; 352a171fe39Sbalrog /* XXX Stop if running (shouldn't happen) */ 353a171fe39Sbalrog if ((value & (1 << 7)) || tm == 0) 354a171fe39Sbalrog s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7]; 355a171fe39Sbalrog else { 356a171fe39Sbalrog s->tm4[tm].freq = 0; 357bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); 358a171fe39Sbalrog } 359a171fe39Sbalrog break; 360a171fe39Sbalrog case OMCR11: tm ++; 361de16017dSPeter Maydell /* fall through */ 362a171fe39Sbalrog case OMCR10: tm ++; 363de16017dSPeter Maydell /* fall through */ 364a171fe39Sbalrog case OMCR9: tm ++; 365de16017dSPeter Maydell /* fall through */ 366a171fe39Sbalrog case OMCR8: tm += 4; 367797e9542SDmitry Eremin-Solenikov if (!pxa2xx_timer_has_tm4(s)) 368a171fe39Sbalrog goto badreg; 369a171fe39Sbalrog s->tm4[tm].control = value & 0x3ff; 370a171fe39Sbalrog /* XXX Stop if running (shouldn't happen) */ 371a171fe39Sbalrog if ((value & (1 << 7)) || !(tm & 1)) 372a171fe39Sbalrog s->tm4[tm].freq = 373a171fe39Sbalrog pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)]; 374a171fe39Sbalrog else { 375a171fe39Sbalrog s->tm4[tm].freq = 0; 376bc72ad67SAlex Bligh pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); 377a171fe39Sbalrog } 378a171fe39Sbalrog break; 379a171fe39Sbalrog default: 380a171fe39Sbalrog badreg: 3812ac71179SPaul Brook hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset); 382a171fe39Sbalrog } 383a171fe39Sbalrog } 384a171fe39Sbalrog 385b755bde3SBenoît Canet static const MemoryRegionOps pxa2xx_timer_ops = { 386b755bde3SBenoît Canet .read = pxa2xx_timer_read, 387b755bde3SBenoît Canet .write = pxa2xx_timer_write, 388b755bde3SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 389a171fe39Sbalrog }; 390a171fe39Sbalrog 391a171fe39Sbalrog static void pxa2xx_timer_tick(void *opaque) 392a171fe39Sbalrog { 393bc24a225SPaul Brook PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque; 394797e9542SDmitry Eremin-Solenikov PXA2xxTimerInfo *i = t->info; 395a171fe39Sbalrog 396a171fe39Sbalrog if (i->irq_enabled & (1 << t->num)) { 397a171fe39Sbalrog i->events |= 1 << t->num; 3985251d196SAndrzej Zaborowski qemu_irq_raise(t->irq); 399a171fe39Sbalrog } 400a171fe39Sbalrog 401a171fe39Sbalrog if (t->num == 3) 402a171fe39Sbalrog if (i->reset3 & 1) { 403a171fe39Sbalrog i->reset3 = 0; 404*cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 405a171fe39Sbalrog } 406a171fe39Sbalrog } 407a171fe39Sbalrog 408a171fe39Sbalrog static void pxa2xx_timer_tick4(void *opaque) 409a171fe39Sbalrog { 410bc24a225SPaul Brook PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque; 411d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info; 412a171fe39Sbalrog 4133bdd58a4Sbalrog pxa2xx_timer_tick(&t->tm); 414a171fe39Sbalrog if (t->control & (1 << 3)) 415a171fe39Sbalrog t->clock = 0; 416a171fe39Sbalrog if (t->control & (1 << 6)) 417bc72ad67SAlex Bligh pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4); 4184ff927ccSDmitry Eremin-Solenikov if (i->events & 0xff0) 4194ff927ccSDmitry Eremin-Solenikov qemu_irq_raise(i->irq4); 420a171fe39Sbalrog } 421a171fe39Sbalrog 422797e9542SDmitry Eremin-Solenikov static int pxa25x_timer_post_load(void *opaque, int version_id) 423aa941b94Sbalrog { 424d353eb43SDmitry Eremin-Solenikov PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; 425aa941b94Sbalrog int64_t now; 426aa941b94Sbalrog int i; 427aa941b94Sbalrog 428bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 429aa941b94Sbalrog pxa2xx_timer_update(s, now); 430aa941b94Sbalrog 431797e9542SDmitry Eremin-Solenikov if (pxa2xx_timer_has_tm4(s)) 432797e9542SDmitry Eremin-Solenikov for (i = 0; i < 8; i ++) 433aa941b94Sbalrog pxa2xx_timer_update4(s, now, i); 434aa941b94Sbalrog 435aa941b94Sbalrog return 0; 436aa941b94Sbalrog } 437aa941b94Sbalrog 4385d83e348Sxiaoqiang.zhao static void pxa2xx_timer_init(Object *obj) 439a171fe39Sbalrog { 4405d83e348Sxiaoqiang.zhao PXA2xxTimerInfo *s = PXA2XX_TIMER(obj); 4415d83e348Sxiaoqiang.zhao SysBusDevice *dev = SYS_BUS_DEVICE(obj); 442a171fe39Sbalrog 443a171fe39Sbalrog s->irq_enabled = 0; 444a171fe39Sbalrog s->oldclock = 0; 445a171fe39Sbalrog s->clock = 0; 446bc72ad67SAlex Bligh s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 447a171fe39Sbalrog s->reset3 = 0; 448a171fe39Sbalrog 4495d83e348Sxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &pxa2xx_timer_ops, s, 4505d83e348Sxiaoqiang.zhao "pxa2xx-timer", 0x00001000); 4515d83e348Sxiaoqiang.zhao sysbus_init_mmio(dev, &s->iomem); 4525d83e348Sxiaoqiang.zhao } 4535d83e348Sxiaoqiang.zhao 4545d83e348Sxiaoqiang.zhao static void pxa2xx_timer_realize(DeviceState *dev, Error **errp) 4555d83e348Sxiaoqiang.zhao { 4565d83e348Sxiaoqiang.zhao PXA2xxTimerInfo *s = PXA2XX_TIMER(dev); 4575d83e348Sxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 4585d83e348Sxiaoqiang.zhao int i; 4595d83e348Sxiaoqiang.zhao 460a171fe39Sbalrog for (i = 0; i < 4; i ++) { 461a171fe39Sbalrog s->timer[i].value = 0; 4625d83e348Sxiaoqiang.zhao sysbus_init_irq(sbd, &s->timer[i].irq); 463a171fe39Sbalrog s->timer[i].info = s; 464a171fe39Sbalrog s->timer[i].num = i; 465bc72ad67SAlex Bligh s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 466a171fe39Sbalrog pxa2xx_timer_tick, &s->timer[i]); 467a171fe39Sbalrog } 4685d83e348Sxiaoqiang.zhao 469797e9542SDmitry Eremin-Solenikov if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) { 4705d83e348Sxiaoqiang.zhao sysbus_init_irq(sbd, &s->irq4); 471a171fe39Sbalrog 472a171fe39Sbalrog for (i = 0; i < 8; i ++) { 4733bdd58a4Sbalrog s->tm4[i].tm.value = 0; 4743bdd58a4Sbalrog s->tm4[i].tm.info = s; 4753bdd58a4Sbalrog s->tm4[i].tm.num = i + 4; 476a171fe39Sbalrog s->tm4[i].freq = 0; 477a171fe39Sbalrog s->tm4[i].control = 0x0; 478bc72ad67SAlex Bligh s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 479a171fe39Sbalrog pxa2xx_timer_tick4, &s->tm4[i]); 480a171fe39Sbalrog } 481a171fe39Sbalrog } 482797e9542SDmitry Eremin-Solenikov } 483797e9542SDmitry Eremin-Solenikov 484797e9542SDmitry Eremin-Solenikov static const VMStateDescription vmstate_pxa2xx_timer0_regs = { 485797e9542SDmitry Eremin-Solenikov .name = "pxa2xx_timer0", 4868034ce7dSAndrzej Zaborowski .version_id = 2, 4878034ce7dSAndrzej Zaborowski .minimum_version_id = 2, 488797e9542SDmitry Eremin-Solenikov .fields = (VMStateField[]) { 489797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(value, PXA2xxTimer0), 490797e9542SDmitry Eremin-Solenikov VMSTATE_END_OF_LIST(), 491797e9542SDmitry Eremin-Solenikov }, 492797e9542SDmitry Eremin-Solenikov }; 493797e9542SDmitry Eremin-Solenikov 494797e9542SDmitry Eremin-Solenikov static const VMStateDescription vmstate_pxa2xx_timer4_regs = { 495797e9542SDmitry Eremin-Solenikov .name = "pxa2xx_timer4", 496797e9542SDmitry Eremin-Solenikov .version_id = 1, 497797e9542SDmitry Eremin-Solenikov .minimum_version_id = 1, 498797e9542SDmitry Eremin-Solenikov .fields = (VMStateField[]) { 499797e9542SDmitry Eremin-Solenikov VMSTATE_STRUCT(tm, PXA2xxTimer4, 1, 500797e9542SDmitry Eremin-Solenikov vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), 501797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(oldclock, PXA2xxTimer4), 502797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(clock, PXA2xxTimer4), 503797e9542SDmitry Eremin-Solenikov VMSTATE_UINT64(lastload, PXA2xxTimer4), 504797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(freq, PXA2xxTimer4), 505797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(control, PXA2xxTimer4), 506797e9542SDmitry Eremin-Solenikov VMSTATE_END_OF_LIST(), 507797e9542SDmitry Eremin-Solenikov }, 508797e9542SDmitry Eremin-Solenikov }; 509797e9542SDmitry Eremin-Solenikov 510797e9542SDmitry Eremin-Solenikov static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id) 511797e9542SDmitry Eremin-Solenikov { 512797e9542SDmitry Eremin-Solenikov return pxa2xx_timer_has_tm4(opaque); 513797e9542SDmitry Eremin-Solenikov } 514797e9542SDmitry Eremin-Solenikov 515797e9542SDmitry Eremin-Solenikov static const VMStateDescription vmstate_pxa2xx_timer_regs = { 516797e9542SDmitry Eremin-Solenikov .name = "pxa2xx_timer", 517797e9542SDmitry Eremin-Solenikov .version_id = 1, 518797e9542SDmitry Eremin-Solenikov .minimum_version_id = 1, 519797e9542SDmitry Eremin-Solenikov .post_load = pxa25x_timer_post_load, 520797e9542SDmitry Eremin-Solenikov .fields = (VMStateField[]) { 521797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(clock, PXA2xxTimerInfo), 522797e9542SDmitry Eremin-Solenikov VMSTATE_INT32(oldclock, PXA2xxTimerInfo), 523797e9542SDmitry Eremin-Solenikov VMSTATE_UINT64(lastload, PXA2xxTimerInfo), 524797e9542SDmitry Eremin-Solenikov VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1, 525797e9542SDmitry Eremin-Solenikov vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), 526797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(events, PXA2xxTimerInfo), 527797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo), 528797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(reset3, PXA2xxTimerInfo), 529797e9542SDmitry Eremin-Solenikov VMSTATE_UINT32(snapshot, PXA2xxTimerInfo), 530797e9542SDmitry Eremin-Solenikov VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8, 531797e9542SDmitry Eremin-Solenikov pxa2xx_timer_has_tm4_test, 0, 532797e9542SDmitry Eremin-Solenikov vmstate_pxa2xx_timer4_regs, PXA2xxTimer4), 533797e9542SDmitry Eremin-Solenikov VMSTATE_END_OF_LIST(), 534797e9542SDmitry Eremin-Solenikov } 535797e9542SDmitry Eremin-Solenikov }; 536797e9542SDmitry Eremin-Solenikov 537999e12bbSAnthony Liguori static Property pxa25x_timer_dev_properties[] = { 538797e9542SDmitry Eremin-Solenikov DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ), 539797e9542SDmitry Eremin-Solenikov DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, 540797e9542SDmitry Eremin-Solenikov PXA2XX_TIMER_HAVE_TM4, false), 541797e9542SDmitry Eremin-Solenikov DEFINE_PROP_END_OF_LIST(), 542797e9542SDmitry Eremin-Solenikov }; 543797e9542SDmitry Eremin-Solenikov 544999e12bbSAnthony Liguori static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data) 545999e12bbSAnthony Liguori { 54639bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 547999e12bbSAnthony Liguori 54839bffca2SAnthony Liguori dc->desc = "PXA25x timer"; 54939bffca2SAnthony Liguori dc->props = pxa25x_timer_dev_properties; 550999e12bbSAnthony Liguori } 551999e12bbSAnthony Liguori 5528c43a6f0SAndreas Färber static const TypeInfo pxa25x_timer_dev_info = { 553999e12bbSAnthony Liguori .name = "pxa25x-timer", 554feea4361SAndreas Färber .parent = TYPE_PXA2XX_TIMER, 55539bffca2SAnthony Liguori .instance_size = sizeof(PXA2xxTimerInfo), 556999e12bbSAnthony Liguori .class_init = pxa25x_timer_dev_class_init, 557999e12bbSAnthony Liguori }; 558999e12bbSAnthony Liguori 559999e12bbSAnthony Liguori static Property pxa27x_timer_dev_properties[] = { 560797e9542SDmitry Eremin-Solenikov DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ), 561797e9542SDmitry Eremin-Solenikov DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, 562797e9542SDmitry Eremin-Solenikov PXA2XX_TIMER_HAVE_TM4, true), 563797e9542SDmitry Eremin-Solenikov DEFINE_PROP_END_OF_LIST(), 564999e12bbSAnthony Liguori }; 565999e12bbSAnthony Liguori 566999e12bbSAnthony Liguori static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data) 567999e12bbSAnthony Liguori { 56839bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 569999e12bbSAnthony Liguori 57039bffca2SAnthony Liguori dc->desc = "PXA27x timer"; 57139bffca2SAnthony Liguori dc->props = pxa27x_timer_dev_properties; 572999e12bbSAnthony Liguori } 573999e12bbSAnthony Liguori 5748c43a6f0SAndreas Färber static const TypeInfo pxa27x_timer_dev_info = { 575999e12bbSAnthony Liguori .name = "pxa27x-timer", 576feea4361SAndreas Färber .parent = TYPE_PXA2XX_TIMER, 57739bffca2SAnthony Liguori .instance_size = sizeof(PXA2xxTimerInfo), 578999e12bbSAnthony Liguori .class_init = pxa27x_timer_dev_class_init, 579797e9542SDmitry Eremin-Solenikov }; 580797e9542SDmitry Eremin-Solenikov 581feea4361SAndreas Färber static void pxa2xx_timer_class_init(ObjectClass *oc, void *data) 582feea4361SAndreas Färber { 583feea4361SAndreas Färber DeviceClass *dc = DEVICE_CLASS(oc); 584feea4361SAndreas Färber 5855d83e348Sxiaoqiang.zhao dc->realize = pxa2xx_timer_realize; 586feea4361SAndreas Färber dc->vmsd = &vmstate_pxa2xx_timer_regs; 587feea4361SAndreas Färber } 588feea4361SAndreas Färber 589feea4361SAndreas Färber static const TypeInfo pxa2xx_timer_type_info = { 590feea4361SAndreas Färber .name = TYPE_PXA2XX_TIMER, 591feea4361SAndreas Färber .parent = TYPE_SYS_BUS_DEVICE, 592feea4361SAndreas Färber .instance_size = sizeof(PXA2xxTimerInfo), 5935d83e348Sxiaoqiang.zhao .instance_init = pxa2xx_timer_init, 594feea4361SAndreas Färber .abstract = true, 595feea4361SAndreas Färber .class_init = pxa2xx_timer_class_init, 596feea4361SAndreas Färber }; 597feea4361SAndreas Färber 59883f7d43aSAndreas Färber static void pxa2xx_timer_register_types(void) 599797e9542SDmitry Eremin-Solenikov { 600feea4361SAndreas Färber type_register_static(&pxa2xx_timer_type_info); 60139bffca2SAnthony Liguori type_register_static(&pxa25x_timer_dev_info); 60239bffca2SAnthony Liguori type_register_static(&pxa27x_timer_dev_info); 60383f7d43aSAndreas Färber } 60483f7d43aSAndreas Färber 60583f7d43aSAndreas Färber type_init(pxa2xx_timer_register_types) 606