Revision 797e9542 hw/pxa2xx_timer.c
b/hw/pxa2xx_timer.c | ||
---|---|---|
10 | 10 |
#include "hw.h" |
11 | 11 |
#include "qemu-timer.h" |
12 | 12 |
#include "sysemu.h" |
13 |
#include "qdev.h" |
|
14 | 13 |
#include "pxa.h" |
14 |
#include "sysbus.h" |
|
15 | 15 |
|
16 | 16 |
#define OSMR0 0x00 |
17 | 17 |
#define OSMR1 0x04 |
... | ... | |
60 | 60 |
[5 ... 7] = 0, |
61 | 61 |
}; |
62 | 62 |
|
63 |
typedef struct PXA2xxTimerInfo PXA2xxTimerInfo; |
|
64 |
|
|
63 | 65 |
typedef struct { |
64 | 66 |
uint32_t value; |
65 | 67 |
int level; |
66 |
qemu_irq irq; |
|
67 | 68 |
QEMUTimer *qtimer; |
68 | 69 |
int num; |
69 |
void *info;
|
|
70 |
PXA2xxTimerInfo *info;
|
|
70 | 71 |
} PXA2xxTimer0; |
71 | 72 |
|
72 | 73 |
typedef struct { |
... | ... | |
78 | 79 |
uint32_t control; |
79 | 80 |
} PXA2xxTimer4; |
80 | 81 |
|
81 |
typedef struct { |
|
82 |
struct PXA2xxTimerInfo { |
|
83 |
SysBusDevice busdev; |
|
84 |
uint32_t flags; |
|
85 |
|
|
82 | 86 |
int32_t clock; |
83 | 87 |
int32_t oldclock; |
84 | 88 |
uint64_t lastload; |
85 | 89 |
uint32_t freq; |
86 | 90 |
PXA2xxTimer0 timer[4]; |
87 |
PXA2xxTimer4 *tm4;
|
|
91 |
qemu_irq irqs[5];
|
|
88 | 92 |
uint32_t events; |
89 | 93 |
uint32_t irq_enabled; |
90 | 94 |
uint32_t reset3; |
91 | 95 |
uint32_t snapshot; |
92 |
} PXA2xxTimerInfo; |
|
96 |
|
|
97 |
PXA2xxTimer4 tm4[8]; |
|
98 |
qemu_irq irq4; |
|
99 |
}; |
|
100 |
|
|
101 |
#define PXA2XX_TIMER_HAVE_TM4 0 |
|
102 |
|
|
103 |
static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s) |
|
104 |
{ |
|
105 |
return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4); |
|
106 |
} |
|
93 | 107 |
|
94 | 108 |
static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu) |
95 | 109 |
{ |
... | ... | |
154 | 168 |
case OSMR6: tm ++; |
155 | 169 |
case OSMR5: tm ++; |
156 | 170 |
case OSMR4: |
157 |
if (!s->tm4)
|
|
171 |
if (!pxa2xx_timer_has_tm4(s))
|
|
158 | 172 |
goto badreg; |
159 | 173 |
return s->tm4[tm].tm.value; |
160 | 174 |
case OSCR: |
... | ... | |
168 | 182 |
case OSCR6: tm ++; |
169 | 183 |
case OSCR5: tm ++; |
170 | 184 |
case OSCR4: |
171 |
if (!s->tm4)
|
|
185 |
if (!pxa2xx_timer_has_tm4(s))
|
|
172 | 186 |
goto badreg; |
173 | 187 |
|
174 | 188 |
if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) { |
... | ... | |
199 | 213 |
case OMCR6: tm ++; |
200 | 214 |
case OMCR5: tm ++; |
201 | 215 |
case OMCR4: |
202 |
if (!s->tm4)
|
|
216 |
if (!pxa2xx_timer_has_tm4(s))
|
|
203 | 217 |
goto badreg; |
204 | 218 |
return s->tm4[tm].control; |
205 | 219 |
case OSNR: |
... | ... | |
234 | 248 |
case OSMR6: tm ++; |
235 | 249 |
case OSMR5: tm ++; |
236 | 250 |
case OSMR4: |
237 |
if (!s->tm4)
|
|
251 |
if (!pxa2xx_timer_has_tm4(s))
|
|
238 | 252 |
goto badreg; |
239 | 253 |
s->tm4[tm].tm.value = value; |
240 | 254 |
pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm); |
... | ... | |
253 | 267 |
case OSCR6: tm ++; |
254 | 268 |
case OSCR5: tm ++; |
255 | 269 |
case OSCR4: |
256 |
if (!s->tm4)
|
|
270 |
if (!pxa2xx_timer_has_tm4(s))
|
|
257 | 271 |
goto badreg; |
258 | 272 |
s->tm4[tm].oldclock = s->tm4[tm].clock; |
259 | 273 |
s->tm4[tm].lastload = qemu_get_clock(vm_clock); |
... | ... | |
268 | 282 |
for (i = 0; i < 4; i ++, value >>= 1) { |
269 | 283 |
if (s->timer[i].level && (value & 1)) { |
270 | 284 |
s->timer[i].level = 0; |
271 |
qemu_irq_lower(s->timer[i].irq);
|
|
285 |
qemu_irq_lower(s->irqs[i]);
|
|
272 | 286 |
} |
273 | 287 |
} |
274 |
if (s->tm4) {
|
|
288 |
if (pxa2xx_timer_has_tm4(s)) {
|
|
275 | 289 |
for (i = 0; i < 8; i ++, value >>= 1) |
276 | 290 |
if (s->tm4[i].tm.level && (value & 1)) |
277 | 291 |
s->tm4[i].tm.level = 0; |
278 | 292 |
if (!(s->events & 0xff0)) |
279 |
qemu_irq_lower(s->tm4->tm.irq);
|
|
293 |
qemu_irq_lower(s->irq4);
|
|
280 | 294 |
} |
281 | 295 |
break; |
282 | 296 |
case OWER: /* XXX: Reset on OSMR3 match? */ |
... | ... | |
286 | 300 |
case OMCR6: tm ++; |
287 | 301 |
case OMCR5: tm ++; |
288 | 302 |
case OMCR4: |
289 |
if (!s->tm4)
|
|
303 |
if (!pxa2xx_timer_has_tm4(s))
|
|
290 | 304 |
goto badreg; |
291 | 305 |
s->tm4[tm].control = value & 0x0ff; |
292 | 306 |
/* XXX Stop if running (shouldn't happen) */ |
... | ... | |
301 | 315 |
case OMCR10: tm ++; |
302 | 316 |
case OMCR9: tm ++; |
303 | 317 |
case OMCR8: tm += 4; |
304 |
if (!s->tm4)
|
|
318 |
if (!pxa2xx_timer_has_tm4(s))
|
|
305 | 319 |
goto badreg; |
306 | 320 |
s->tm4[tm].control = value & 0x3ff; |
307 | 321 |
/* XXX Stop if running (shouldn't happen) */ |
... | ... | |
334 | 348 |
static void pxa2xx_timer_tick(void *opaque) |
335 | 349 |
{ |
336 | 350 |
PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque; |
337 |
PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->info;
|
|
351 |
PXA2xxTimerInfo *i = t->info; |
|
338 | 352 |
|
339 | 353 |
if (i->irq_enabled & (1 << t->num)) { |
340 | 354 |
t->level = 1; |
341 | 355 |
i->events |= 1 << t->num; |
342 |
qemu_irq_raise(t->irq);
|
|
356 |
qemu_irq_raise(t->num < 4 ? i->irqs[t->num] : i->irq4);
|
|
343 | 357 |
} |
344 | 358 |
|
345 | 359 |
if (t->num == 3) |
... | ... | |
361 | 375 |
pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->tm.num - 4); |
362 | 376 |
} |
363 | 377 |
|
364 |
static void pxa2xx_timer_save(QEMUFile *f, void *opaque) |
|
365 |
{ |
|
366 |
PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; |
|
367 |
int i; |
|
368 |
|
|
369 |
qemu_put_be32s(f, (uint32_t *) &s->clock); |
|
370 |
qemu_put_be32s(f, (uint32_t *) &s->oldclock); |
|
371 |
qemu_put_be64s(f, &s->lastload); |
|
372 |
|
|
373 |
for (i = 0; i < 4; i ++) { |
|
374 |
qemu_put_be32s(f, &s->timer[i].value); |
|
375 |
qemu_put_be32(f, s->timer[i].level); |
|
376 |
} |
|
377 |
if (s->tm4) |
|
378 |
for (i = 0; i < 8; i ++) { |
|
379 |
qemu_put_be32s(f, &s->tm4[i].tm.value); |
|
380 |
qemu_put_be32(f, s->tm4[i].tm.level); |
|
381 |
qemu_put_sbe32s(f, &s->tm4[i].oldclock); |
|
382 |
qemu_put_sbe32s(f, &s->tm4[i].clock); |
|
383 |
qemu_put_be64s(f, &s->tm4[i].lastload); |
|
384 |
qemu_put_be32s(f, &s->tm4[i].freq); |
|
385 |
qemu_put_be32s(f, &s->tm4[i].control); |
|
386 |
} |
|
387 |
|
|
388 |
qemu_put_be32s(f, &s->events); |
|
389 |
qemu_put_be32s(f, &s->irq_enabled); |
|
390 |
qemu_put_be32s(f, &s->reset3); |
|
391 |
qemu_put_be32s(f, &s->snapshot); |
|
392 |
} |
|
393 |
|
|
394 |
static int pxa2xx_timer_load(QEMUFile *f, void *opaque, int version_id) |
|
378 |
static int pxa25x_timer_post_load(void *opaque, int version_id) |
|
395 | 379 |
{ |
396 | 380 |
PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; |
397 | 381 |
int64_t now; |
398 | 382 |
int i; |
399 | 383 |
|
400 |
qemu_get_be32s(f, (uint32_t *) &s->clock); |
|
401 |
qemu_get_be32s(f, (uint32_t *) &s->oldclock); |
|
402 |
qemu_get_be64s(f, &s->lastload); |
|
403 |
|
|
404 | 384 |
now = qemu_get_clock(vm_clock); |
405 |
for (i = 0; i < 4; i ++) { |
|
406 |
qemu_get_be32s(f, &s->timer[i].value); |
|
407 |
s->timer[i].level = qemu_get_be32(f); |
|
408 |
} |
|
409 | 385 |
pxa2xx_timer_update(s, now); |
410 | 386 |
|
411 |
if (s->tm4) |
|
412 |
for (i = 0; i < 8; i ++) { |
|
413 |
qemu_get_be32s(f, &s->tm4[i].tm.value); |
|
414 |
s->tm4[i].tm.level = qemu_get_be32(f); |
|
415 |
qemu_get_sbe32s(f, &s->tm4[i].oldclock); |
|
416 |
qemu_get_sbe32s(f, &s->tm4[i].clock); |
|
417 |
qemu_get_be64s(f, &s->tm4[i].lastload); |
|
418 |
qemu_get_be32s(f, &s->tm4[i].freq); |
|
419 |
qemu_get_be32s(f, &s->tm4[i].control); |
|
387 |
if (pxa2xx_timer_has_tm4(s)) |
|
388 |
for (i = 0; i < 8; i ++) |
|
420 | 389 |
pxa2xx_timer_update4(s, now, i); |
421 |
} |
|
422 |
|
|
423 |
qemu_get_be32s(f, &s->events); |
|
424 |
qemu_get_be32s(f, &s->irq_enabled); |
|
425 |
qemu_get_be32s(f, &s->reset3); |
|
426 |
qemu_get_be32s(f, &s->snapshot); |
|
427 | 390 |
|
428 | 391 |
return 0; |
429 | 392 |
} |
430 | 393 |
|
431 |
static PXA2xxTimerInfo *pxa2xx_timer_init(target_phys_addr_t base, |
|
432 |
DeviceState *pic) |
|
394 |
static int pxa2xx_timer_init(SysBusDevice *dev) |
|
433 | 395 |
{ |
434 | 396 |
int i; |
435 | 397 |
int iomemtype; |
436 | 398 |
PXA2xxTimerInfo *s; |
437 | 399 |
|
438 |
s = (PXA2xxTimerInfo *) qemu_mallocz(sizeof(PXA2xxTimerInfo));
|
|
400 |
s = FROM_SYSBUS(PXA2xxTimerInfo, dev);
|
|
439 | 401 |
s->irq_enabled = 0; |
440 | 402 |
s->oldclock = 0; |
441 | 403 |
s->clock = 0; |
... | ... | |
444 | 406 |
|
445 | 407 |
for (i = 0; i < 4; i ++) { |
446 | 408 |
s->timer[i].value = 0; |
447 |
s->timer[i].irq = qdev_get_gpio_in(pic, PXA2XX_PIC_OST_0 + i);
|
|
409 |
sysbus_init_irq(dev, &s->irqs[i]);
|
|
448 | 410 |
s->timer[i].info = s; |
449 | 411 |
s->timer[i].num = i; |
450 | 412 |
s->timer[i].level = 0; |
451 | 413 |
s->timer[i].qtimer = qemu_new_timer(vm_clock, |
452 | 414 |
pxa2xx_timer_tick, &s->timer[i]); |
453 | 415 |
} |
416 |
if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) { |
|
417 |
sysbus_init_irq(dev, &s->irq4); |
|
418 |
|
|
419 |
for (i = 0; i < 8; i ++) { |
|
420 |
s->tm4[i].tm.value = 0; |
|
421 |
s->tm4[i].tm.info = s; |
|
422 |
s->tm4[i].tm.num = i + 4; |
|
423 |
s->tm4[i].tm.level = 0; |
|
424 |
s->tm4[i].freq = 0; |
|
425 |
s->tm4[i].control = 0x0; |
|
426 |
s->tm4[i].tm.qtimer = qemu_new_timer(vm_clock, |
|
427 |
pxa2xx_timer_tick4, &s->tm4[i]); |
|
428 |
} |
|
429 |
} |
|
454 | 430 |
|
455 | 431 |
iomemtype = cpu_register_io_memory(pxa2xx_timer_readfn, |
456 | 432 |
pxa2xx_timer_writefn, s, DEVICE_NATIVE_ENDIAN); |
457 |
cpu_register_physical_memory(base, 0x00001000, iomemtype);
|
|
433 |
sysbus_init_mmio(dev, 0x00001000, iomemtype);
|
|
458 | 434 |
|
459 |
register_savevm(NULL, "pxa2xx_timer", 0, 0, |
|
460 |
pxa2xx_timer_save, pxa2xx_timer_load, s); |
|
461 |
|
|
462 |
return s; |
|
435 |
return 0; |
|
463 | 436 |
} |
464 | 437 |
|
465 |
void pxa25x_timer_init(target_phys_addr_t base, DeviceState *pic) |
|
438 |
static const VMStateDescription vmstate_pxa2xx_timer0_regs = { |
|
439 |
.name = "pxa2xx_timer0", |
|
440 |
.version_id = 1, |
|
441 |
.minimum_version_id = 1, |
|
442 |
.minimum_version_id_old = 1, |
|
443 |
.fields = (VMStateField[]) { |
|
444 |
VMSTATE_UINT32(value, PXA2xxTimer0), |
|
445 |
VMSTATE_INT32(level, PXA2xxTimer0), |
|
446 |
VMSTATE_END_OF_LIST(), |
|
447 |
}, |
|
448 |
}; |
|
449 |
|
|
450 |
static const VMStateDescription vmstate_pxa2xx_timer4_regs = { |
|
451 |
.name = "pxa2xx_timer4", |
|
452 |
.version_id = 1, |
|
453 |
.minimum_version_id = 1, |
|
454 |
.minimum_version_id_old = 1, |
|
455 |
.fields = (VMStateField[]) { |
|
456 |
VMSTATE_STRUCT(tm, PXA2xxTimer4, 1, |
|
457 |
vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), |
|
458 |
VMSTATE_INT32(oldclock, PXA2xxTimer4), |
|
459 |
VMSTATE_INT32(clock, PXA2xxTimer4), |
|
460 |
VMSTATE_UINT64(lastload, PXA2xxTimer4), |
|
461 |
VMSTATE_UINT32(freq, PXA2xxTimer4), |
|
462 |
VMSTATE_UINT32(control, PXA2xxTimer4), |
|
463 |
VMSTATE_END_OF_LIST(), |
|
464 |
}, |
|
465 |
}; |
|
466 |
|
|
467 |
static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id) |
|
466 | 468 |
{ |
467 |
PXA2xxTimerInfo *s = pxa2xx_timer_init(base, pic); |
|
468 |
s->freq = PXA25X_FREQ; |
|
469 |
s->tm4 = NULL; |
|
469 |
return pxa2xx_timer_has_tm4(opaque); |
|
470 | 470 |
} |
471 | 471 |
|
472 |
void pxa27x_timer_init(target_phys_addr_t base, DeviceState *pic) |
|
473 |
{ |
|
474 |
PXA2xxTimerInfo *s = pxa2xx_timer_init(base, pic); |
|
475 |
int i; |
|
476 |
s->freq = PXA27X_FREQ; |
|
477 |
s->tm4 = (PXA2xxTimer4 *) qemu_mallocz(8 * |
|
478 |
sizeof(PXA2xxTimer4)); |
|
479 |
for (i = 0; i < 8; i ++) { |
|
480 |
s->tm4[i].tm.value = 0; |
|
481 |
s->tm4[i].tm.irq = qdev_get_gpio_in(pic, PXA27X_PIC_OST_4_11); |
|
482 |
s->tm4[i].tm.info = s; |
|
483 |
s->tm4[i].tm.num = i + 4; |
|
484 |
s->tm4[i].tm.level = 0; |
|
485 |
s->tm4[i].freq = 0; |
|
486 |
s->tm4[i].control = 0x0; |
|
487 |
s->tm4[i].tm.qtimer = qemu_new_timer(vm_clock, |
|
488 |
pxa2xx_timer_tick4, &s->tm4[i]); |
|
472 |
static const VMStateDescription vmstate_pxa2xx_timer_regs = { |
|
473 |
.name = "pxa2xx_timer", |
|
474 |
.version_id = 1, |
|
475 |
.minimum_version_id = 1, |
|
476 |
.minimum_version_id_old = 1, |
|
477 |
.post_load = pxa25x_timer_post_load, |
|
478 |
.fields = (VMStateField[]) { |
|
479 |
VMSTATE_INT32(clock, PXA2xxTimerInfo), |
|
480 |
VMSTATE_INT32(oldclock, PXA2xxTimerInfo), |
|
481 |
VMSTATE_UINT64(lastload, PXA2xxTimerInfo), |
|
482 |
VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1, |
|
483 |
vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), |
|
484 |
VMSTATE_UINT32(events, PXA2xxTimerInfo), |
|
485 |
VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo), |
|
486 |
VMSTATE_UINT32(reset3, PXA2xxTimerInfo), |
|
487 |
VMSTATE_UINT32(snapshot, PXA2xxTimerInfo), |
|
488 |
VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8, |
|
489 |
pxa2xx_timer_has_tm4_test, 0, |
|
490 |
vmstate_pxa2xx_timer4_regs, PXA2xxTimer4), |
|
491 |
VMSTATE_END_OF_LIST(), |
|
489 | 492 |
} |
490 |
} |
|
493 |
}; |
|
494 |
|
|
495 |
static SysBusDeviceInfo pxa25x_timer_dev_info = { |
|
496 |
.init = pxa2xx_timer_init, |
|
497 |
.qdev.name = "pxa25x-timer", |
|
498 |
.qdev.desc = "PXA25x timer", |
|
499 |
.qdev.size = sizeof(PXA2xxTimerInfo), |
|
500 |
.qdev.vmsd = &vmstate_pxa2xx_timer_regs, |
|
501 |
.qdev.props = (Property[]) { |
|
502 |
DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ), |
|
503 |
DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, |
|
504 |
PXA2XX_TIMER_HAVE_TM4, false), |
|
505 |
DEFINE_PROP_END_OF_LIST(), |
|
506 |
}, |
|
507 |
}; |
|
508 |
|
|
509 |
static SysBusDeviceInfo pxa27x_timer_dev_info = { |
|
510 |
.init = pxa2xx_timer_init, |
|
511 |
.qdev.name = "pxa27x-timer", |
|
512 |
.qdev.desc = "PXA27x timer", |
|
513 |
.qdev.size = sizeof(PXA2xxTimerInfo), |
|
514 |
.qdev.vmsd = &vmstate_pxa2xx_timer_regs, |
|
515 |
.qdev.props = (Property[]) { |
|
516 |
DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ), |
|
517 |
DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, |
|
518 |
PXA2XX_TIMER_HAVE_TM4, true), |
|
519 |
DEFINE_PROP_END_OF_LIST(), |
|
520 |
}, |
|
521 |
}; |
|
522 |
|
|
523 |
static void pxa2xx_timer_register(void) |
|
524 |
{ |
|
525 |
sysbus_register_withprop(&pxa25x_timer_dev_info); |
|
526 |
sysbus_register_withprop(&pxa27x_timer_dev_info); |
|
527 |
}; |
|
528 |
device_init(pxa2xx_timer_register); |
Also available in: Unified diff