|
|
1.1 ! root 1: /* ! 2: * Intel XScale PXA255/270 OS Timers. ! 3: * ! 4: * Copyright (c) 2006 Openedhand Ltd. ! 5: * Copyright (c) 2006 Thorsten Zitterell ! 6: * ! 7: * This code is licenced under the GPL. ! 8: */ ! 9: ! 10: #include "hw.h" ! 11: #include "qemu-timer.h" ! 12: #include "sysemu.h" ! 13: #include "pxa.h" ! 14: ! 15: #define OSMR0 0x00 ! 16: #define OSMR1 0x04 ! 17: #define OSMR2 0x08 ! 18: #define OSMR3 0x0c ! 19: #define OSMR4 0x80 ! 20: #define OSMR5 0x84 ! 21: #define OSMR6 0x88 ! 22: #define OSMR7 0x8c ! 23: #define OSMR8 0x90 ! 24: #define OSMR9 0x94 ! 25: #define OSMR10 0x98 ! 26: #define OSMR11 0x9c ! 27: #define OSCR 0x10 /* OS Timer Count */ ! 28: #define OSCR4 0x40 ! 29: #define OSCR5 0x44 ! 30: #define OSCR6 0x48 ! 31: #define OSCR7 0x4c ! 32: #define OSCR8 0x50 ! 33: #define OSCR9 0x54 ! 34: #define OSCR10 0x58 ! 35: #define OSCR11 0x5c ! 36: #define OSSR 0x14 /* Timer status register */ ! 37: #define OWER 0x18 ! 38: #define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */ ! 39: #define OMCR4 0xc0 /* OS Match Control registers */ ! 40: #define OMCR5 0xc4 ! 41: #define OMCR6 0xc8 ! 42: #define OMCR7 0xcc ! 43: #define OMCR8 0xd0 ! 44: #define OMCR9 0xd4 ! 45: #define OMCR10 0xd8 ! 46: #define OMCR11 0xdc ! 47: #define OSNR 0x20 ! 48: ! 49: #define PXA25X_FREQ 3686400 /* 3.6864 MHz */ ! 50: #define PXA27X_FREQ 3250000 /* 3.25 MHz */ ! 51: ! 52: static int pxa2xx_timer4_freq[8] = { ! 53: [0] = 0, ! 54: [1] = 32768, ! 55: [2] = 1000, ! 56: [3] = 1, ! 57: [4] = 1000000, ! 58: /* [5] is the "Externally supplied clock". Assign if necessary. */ ! 59: [5 ... 7] = 0, ! 60: }; ! 61: ! 62: struct pxa2xx_timer0_s { ! 63: uint32_t value; ! 64: int level; ! 65: qemu_irq irq; ! 66: QEMUTimer *qtimer; ! 67: int num; ! 68: void *info; ! 69: }; ! 70: ! 71: struct pxa2xx_timer4_s { ! 72: struct pxa2xx_timer0_s tm; ! 73: int32_t oldclock; ! 74: int32_t clock; ! 75: uint64_t lastload; ! 76: uint32_t freq; ! 77: uint32_t control; ! 78: }; ! 79: ! 80: typedef struct { ! 81: target_phys_addr_t base; ! 82: int32_t clock; ! 83: int32_t oldclock; ! 84: uint64_t lastload; ! 85: uint32_t freq; ! 86: struct pxa2xx_timer0_s timer[4]; ! 87: struct pxa2xx_timer4_s *tm4; ! 88: uint32_t events; ! 89: uint32_t irq_enabled; ! 90: uint32_t reset3; ! 91: uint32_t snapshot; ! 92: } pxa2xx_timer_info; ! 93: ! 94: static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu) ! 95: { ! 96: pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; ! 97: int i; ! 98: uint32_t now_vm; ! 99: uint64_t new_qemu; ! 100: ! 101: now_vm = s->clock + ! 102: muldiv64(now_qemu - s->lastload, s->freq, ticks_per_sec); ! 103: ! 104: for (i = 0; i < 4; i ++) { ! 105: new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm), ! 106: ticks_per_sec, s->freq); ! 107: qemu_mod_timer(s->timer[i].qtimer, new_qemu); ! 108: } ! 109: } ! 110: ! 111: static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) ! 112: { ! 113: pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; ! 114: uint32_t now_vm; ! 115: uint64_t new_qemu; ! 116: static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 }; ! 117: int counter; ! 118: ! 119: if (s->tm4[n].control & (1 << 7)) ! 120: counter = n; ! 121: else ! 122: counter = counters[n]; ! 123: ! 124: if (!s->tm4[counter].freq) { ! 125: qemu_del_timer(s->tm4[n].tm.qtimer); ! 126: return; ! 127: } ! 128: ! 129: now_vm = s->tm4[counter].clock + muldiv64(now_qemu - ! 130: s->tm4[counter].lastload, ! 131: s->tm4[counter].freq, ticks_per_sec); ! 132: ! 133: new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm), ! 134: ticks_per_sec, s->tm4[counter].freq); ! 135: qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu); ! 136: } ! 137: ! 138: static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset) ! 139: { ! 140: pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; ! 141: int tm = 0; ! 142: ! 143: offset -= s->base; ! 144: ! 145: switch (offset) { ! 146: case OSMR3: tm ++; ! 147: case OSMR2: tm ++; ! 148: case OSMR1: tm ++; ! 149: case OSMR0: ! 150: return s->timer[tm].value; ! 151: case OSMR11: tm ++; ! 152: case OSMR10: tm ++; ! 153: case OSMR9: tm ++; ! 154: case OSMR8: tm ++; ! 155: case OSMR7: tm ++; ! 156: case OSMR6: tm ++; ! 157: case OSMR5: tm ++; ! 158: case OSMR4: ! 159: if (!s->tm4) ! 160: goto badreg; ! 161: return s->tm4[tm].tm.value; ! 162: case OSCR: ! 163: return s->clock + muldiv64(qemu_get_clock(vm_clock) - ! 164: s->lastload, s->freq, ticks_per_sec); ! 165: case OSCR11: tm ++; ! 166: case OSCR10: tm ++; ! 167: case OSCR9: tm ++; ! 168: case OSCR8: tm ++; ! 169: case OSCR7: tm ++; ! 170: case OSCR6: tm ++; ! 171: case OSCR5: tm ++; ! 172: case OSCR4: ! 173: if (!s->tm4) ! 174: goto badreg; ! 175: ! 176: if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) { ! 177: if (s->tm4[tm - 1].freq) ! 178: s->snapshot = s->tm4[tm - 1].clock + muldiv64( ! 179: qemu_get_clock(vm_clock) - ! 180: s->tm4[tm - 1].lastload, ! 181: s->tm4[tm - 1].freq, ticks_per_sec); ! 182: else ! 183: s->snapshot = s->tm4[tm - 1].clock; ! 184: } ! 185: ! 186: if (!s->tm4[tm].freq) ! 187: return s->tm4[tm].clock; ! 188: return s->tm4[tm].clock + muldiv64(qemu_get_clock(vm_clock) - ! 189: s->tm4[tm].lastload, s->tm4[tm].freq, ticks_per_sec); ! 190: case OIER: ! 191: return s->irq_enabled; ! 192: case OSSR: /* Status register */ ! 193: return s->events; ! 194: case OWER: ! 195: return s->reset3; ! 196: case OMCR11: tm ++; ! 197: case OMCR10: tm ++; ! 198: case OMCR9: tm ++; ! 199: case OMCR8: tm ++; ! 200: case OMCR7: tm ++; ! 201: case OMCR6: tm ++; ! 202: case OMCR5: tm ++; ! 203: case OMCR4: ! 204: if (!s->tm4) ! 205: goto badreg; ! 206: return s->tm4[tm].control; ! 207: case OSNR: ! 208: return s->snapshot; ! 209: default: ! 210: badreg: ! 211: cpu_abort(cpu_single_env, "pxa2xx_timer_read: Bad offset " ! 212: REG_FMT "\n", offset); ! 213: } ! 214: ! 215: return 0; ! 216: } ! 217: ! 218: static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset, ! 219: uint32_t value) ! 220: { ! 221: int i, tm = 0; ! 222: pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; ! 223: ! 224: offset -= s->base; ! 225: ! 226: switch (offset) { ! 227: case OSMR3: tm ++; ! 228: case OSMR2: tm ++; ! 229: case OSMR1: tm ++; ! 230: case OSMR0: ! 231: s->timer[tm].value = value; ! 232: pxa2xx_timer_update(s, qemu_get_clock(vm_clock)); ! 233: break; ! 234: case OSMR11: tm ++; ! 235: case OSMR10: tm ++; ! 236: case OSMR9: tm ++; ! 237: case OSMR8: tm ++; ! 238: case OSMR7: tm ++; ! 239: case OSMR6: tm ++; ! 240: case OSMR5: tm ++; ! 241: case OSMR4: ! 242: if (!s->tm4) ! 243: goto badreg; ! 244: s->tm4[tm].tm.value = value; ! 245: pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm); ! 246: break; ! 247: case OSCR: ! 248: s->oldclock = s->clock; ! 249: s->lastload = qemu_get_clock(vm_clock); ! 250: s->clock = value; ! 251: pxa2xx_timer_update(s, s->lastload); ! 252: break; ! 253: case OSCR11: tm ++; ! 254: case OSCR10: tm ++; ! 255: case OSCR9: tm ++; ! 256: case OSCR8: tm ++; ! 257: case OSCR7: tm ++; ! 258: case OSCR6: tm ++; ! 259: case OSCR5: tm ++; ! 260: case OSCR4: ! 261: if (!s->tm4) ! 262: goto badreg; ! 263: s->tm4[tm].oldclock = s->tm4[tm].clock; ! 264: s->tm4[tm].lastload = qemu_get_clock(vm_clock); ! 265: s->tm4[tm].clock = value; ! 266: pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm); ! 267: break; ! 268: case OIER: ! 269: s->irq_enabled = value & 0xfff; ! 270: break; ! 271: case OSSR: /* Status register */ ! 272: s->events &= ~value; ! 273: for (i = 0; i < 4; i ++, value >>= 1) { ! 274: if (s->timer[i].level && (value & 1)) { ! 275: s->timer[i].level = 0; ! 276: qemu_irq_lower(s->timer[i].irq); ! 277: } ! 278: } ! 279: if (s->tm4) { ! 280: for (i = 0; i < 8; i ++, value >>= 1) ! 281: if (s->tm4[i].tm.level && (value & 1)) ! 282: s->tm4[i].tm.level = 0; ! 283: if (!(s->events & 0xff0)) ! 284: qemu_irq_lower(s->tm4->tm.irq); ! 285: } ! 286: break; ! 287: case OWER: /* XXX: Reset on OSMR3 match? */ ! 288: s->reset3 = value; ! 289: break; ! 290: case OMCR7: tm ++; ! 291: case OMCR6: tm ++; ! 292: case OMCR5: tm ++; ! 293: case OMCR4: ! 294: if (!s->tm4) ! 295: goto badreg; ! 296: s->tm4[tm].control = value & 0x0ff; ! 297: /* XXX Stop if running (shouldn't happen) */ ! 298: if ((value & (1 << 7)) || tm == 0) ! 299: s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7]; ! 300: else { ! 301: s->tm4[tm].freq = 0; ! 302: pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm); ! 303: } ! 304: break; ! 305: case OMCR11: tm ++; ! 306: case OMCR10: tm ++; ! 307: case OMCR9: tm ++; ! 308: case OMCR8: tm += 4; ! 309: if (!s->tm4) ! 310: goto badreg; ! 311: s->tm4[tm].control = value & 0x3ff; ! 312: /* XXX Stop if running (shouldn't happen) */ ! 313: if ((value & (1 << 7)) || !(tm & 1)) ! 314: s->tm4[tm].freq = ! 315: pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)]; ! 316: else { ! 317: s->tm4[tm].freq = 0; ! 318: pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm); ! 319: } ! 320: break; ! 321: default: ! 322: badreg: ! 323: cpu_abort(cpu_single_env, "pxa2xx_timer_write: Bad offset " ! 324: REG_FMT "\n", offset); ! 325: } ! 326: } ! 327: ! 328: static CPUReadMemoryFunc *pxa2xx_timer_readfn[] = { ! 329: pxa2xx_timer_read, ! 330: pxa2xx_timer_read, ! 331: pxa2xx_timer_read, ! 332: }; ! 333: ! 334: static CPUWriteMemoryFunc *pxa2xx_timer_writefn[] = { ! 335: pxa2xx_timer_write, ! 336: pxa2xx_timer_write, ! 337: pxa2xx_timer_write, ! 338: }; ! 339: ! 340: static void pxa2xx_timer_tick(void *opaque) ! 341: { ! 342: struct pxa2xx_timer0_s *t = (struct pxa2xx_timer0_s *) opaque; ! 343: pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info; ! 344: ! 345: if (i->irq_enabled & (1 << t->num)) { ! 346: t->level = 1; ! 347: i->events |= 1 << t->num; ! 348: qemu_irq_raise(t->irq); ! 349: } ! 350: ! 351: if (t->num == 3) ! 352: if (i->reset3 & 1) { ! 353: i->reset3 = 0; ! 354: qemu_system_reset_request(); ! 355: } ! 356: } ! 357: ! 358: static void pxa2xx_timer_tick4(void *opaque) ! 359: { ! 360: struct pxa2xx_timer4_s *t = (struct pxa2xx_timer4_s *) opaque; ! 361: pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->tm.info; ! 362: ! 363: pxa2xx_timer_tick(&t->tm); ! 364: if (t->control & (1 << 3)) ! 365: t->clock = 0; ! 366: if (t->control & (1 << 6)) ! 367: pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->tm.num - 4); ! 368: } ! 369: ! 370: static void pxa2xx_timer_save(QEMUFile *f, void *opaque) ! 371: { ! 372: pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; ! 373: int i; ! 374: ! 375: qemu_put_be32s(f, &s->clock); ! 376: qemu_put_be32s(f, &s->oldclock); ! 377: qemu_put_be64s(f, &s->lastload); ! 378: ! 379: for (i = 0; i < 4; i ++) { ! 380: qemu_put_be32s(f, &s->timer[i].value); ! 381: qemu_put_be32(f, s->timer[i].level); ! 382: } ! 383: if (s->tm4) ! 384: for (i = 0; i < 8; i ++) { ! 385: qemu_put_be32s(f, &s->tm4[i].tm.value); ! 386: qemu_put_be32(f, s->tm4[i].tm.level); ! 387: qemu_put_be32s(f, &s->tm4[i].oldclock); ! 388: qemu_put_be32s(f, &s->tm4[i].clock); ! 389: qemu_put_be64s(f, &s->tm4[i].lastload); ! 390: qemu_put_be32s(f, &s->tm4[i].freq); ! 391: qemu_put_be32s(f, &s->tm4[i].control); ! 392: } ! 393: ! 394: qemu_put_be32s(f, &s->events); ! 395: qemu_put_be32s(f, &s->irq_enabled); ! 396: qemu_put_be32s(f, &s->reset3); ! 397: qemu_put_be32s(f, &s->snapshot); ! 398: } ! 399: ! 400: static int pxa2xx_timer_load(QEMUFile *f, void *opaque, int version_id) ! 401: { ! 402: pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; ! 403: int64_t now; ! 404: int i; ! 405: ! 406: qemu_get_be32s(f, &s->clock); ! 407: qemu_get_be32s(f, &s->oldclock); ! 408: qemu_get_be64s(f, &s->lastload); ! 409: ! 410: now = qemu_get_clock(vm_clock); ! 411: for (i = 0; i < 4; i ++) { ! 412: qemu_get_be32s(f, &s->timer[i].value); ! 413: s->timer[i].level = qemu_get_be32(f); ! 414: } ! 415: pxa2xx_timer_update(s, now); ! 416: ! 417: if (s->tm4) ! 418: for (i = 0; i < 8; i ++) { ! 419: qemu_get_be32s(f, &s->tm4[i].tm.value); ! 420: s->tm4[i].tm.level = qemu_get_be32(f); ! 421: qemu_get_be32s(f, &s->tm4[i].oldclock); ! 422: qemu_get_be32s(f, &s->tm4[i].clock); ! 423: qemu_get_be64s(f, &s->tm4[i].lastload); ! 424: qemu_get_be32s(f, &s->tm4[i].freq); ! 425: qemu_get_be32s(f, &s->tm4[i].control); ! 426: pxa2xx_timer_update4(s, now, i); ! 427: } ! 428: ! 429: qemu_get_be32s(f, &s->events); ! 430: qemu_get_be32s(f, &s->irq_enabled); ! 431: qemu_get_be32s(f, &s->reset3); ! 432: qemu_get_be32s(f, &s->snapshot); ! 433: ! 434: return 0; ! 435: } ! 436: ! 437: static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base, ! 438: qemu_irq *irqs) ! 439: { ! 440: int i; ! 441: int iomemtype; ! 442: pxa2xx_timer_info *s; ! 443: ! 444: s = (pxa2xx_timer_info *) qemu_mallocz(sizeof(pxa2xx_timer_info)); ! 445: s->base = base; ! 446: s->irq_enabled = 0; ! 447: s->oldclock = 0; ! 448: s->clock = 0; ! 449: s->lastload = qemu_get_clock(vm_clock); ! 450: s->reset3 = 0; ! 451: ! 452: for (i = 0; i < 4; i ++) { ! 453: s->timer[i].value = 0; ! 454: s->timer[i].irq = irqs[i]; ! 455: s->timer[i].info = s; ! 456: s->timer[i].num = i; ! 457: s->timer[i].level = 0; ! 458: s->timer[i].qtimer = qemu_new_timer(vm_clock, ! 459: pxa2xx_timer_tick, &s->timer[i]); ! 460: } ! 461: ! 462: iomemtype = cpu_register_io_memory(0, pxa2xx_timer_readfn, ! 463: pxa2xx_timer_writefn, s); ! 464: cpu_register_physical_memory(base, 0x00001000, iomemtype); ! 465: ! 466: register_savevm("pxa2xx_timer", 0, 0, ! 467: pxa2xx_timer_save, pxa2xx_timer_load, s); ! 468: ! 469: return s; ! 470: } ! 471: ! 472: void pxa25x_timer_init(target_phys_addr_t base, qemu_irq *irqs) ! 473: { ! 474: pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs); ! 475: s->freq = PXA25X_FREQ; ! 476: s->tm4 = 0; ! 477: } ! 478: ! 479: void pxa27x_timer_init(target_phys_addr_t base, ! 480: qemu_irq *irqs, qemu_irq irq4) ! 481: { ! 482: pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs); ! 483: int i; ! 484: s->freq = PXA27X_FREQ; ! 485: s->tm4 = (struct pxa2xx_timer4_s *) qemu_mallocz(8 * ! 486: sizeof(struct pxa2xx_timer4_s)); ! 487: for (i = 0; i < 8; i ++) { ! 488: s->tm4[i].tm.value = 0; ! 489: s->tm4[i].tm.irq = irq4; ! 490: s->tm4[i].tm.info = s; ! 491: s->tm4[i].tm.num = i + 4; ! 492: s->tm4[i].tm.level = 0; ! 493: s->tm4[i].freq = 0; ! 494: s->tm4[i].control = 0x0; ! 495: s->tm4[i].tm.qtimer = qemu_new_timer(vm_clock, ! 496: pxa2xx_timer_tick4, &s->tm4[i]); ! 497: } ! 498: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.