* This code is licenced under the GPL.
*/
-#include "vl.h"
+#include "hw.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "qdev.h"
+#include "pxa.h"
#define OSMR0 0x00
#define OSMR1 0x04
[5 ... 7] = 0,
};
-struct pxa2xx_timer0_s {
+typedef struct {
uint32_t value;
int level;
qemu_irq irq;
QEMUTimer *qtimer;
int num;
void *info;
-};
+} PXA2xxTimer0;
-struct pxa2xx_timer4_s {
- struct pxa2xx_timer0_s tm;
+typedef struct {
+ PXA2xxTimer0 tm;
int32_t oldclock;
int32_t clock;
uint64_t lastload;
uint32_t freq;
uint32_t control;
-};
+} PXA2xxTimer4;
typedef struct {
- uint32_t base;
int32_t clock;
int32_t oldclock;
uint64_t lastload;
uint32_t freq;
- struct pxa2xx_timer0_s timer[4];
- struct pxa2xx_timer4_s *tm4;
+ PXA2xxTimer0 timer[4];
+ PXA2xxTimer4 *tm4;
uint32_t events;
uint32_t irq_enabled;
uint32_t reset3;
- CPUState *cpustate;
- int64_t qemu_ticks;
uint32_t snapshot;
-} pxa2xx_timer_info;
+} PXA2xxTimerInfo;
static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
{
- pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+ PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
int i;
uint32_t now_vm;
uint64_t new_qemu;
now_vm = s->clock +
- muldiv64(now_qemu - s->lastload, s->freq, ticks_per_sec);
+ muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec());
for (i = 0; i < 4; i ++) {
new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
- ticks_per_sec, s->freq);
+ get_ticks_per_sec(), s->freq);
qemu_mod_timer(s->timer[i].qtimer, new_qemu);
}
}
static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
{
- pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+ PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
uint32_t now_vm;
uint64_t new_qemu;
static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
counter = counters[n];
if (!s->tm4[counter].freq) {
- qemu_del_timer(s->timer[n].qtimer);
+ qemu_del_timer(s->tm4[n].tm.qtimer);
return;
}
now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
s->tm4[counter].lastload,
- s->tm4[counter].freq, ticks_per_sec);
+ s->tm4[counter].freq, get_ticks_per_sec());
new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
- ticks_per_sec, s->tm4[counter].freq);
- qemu_mod_timer(s->timer[n].qtimer, new_qemu);
+ get_ticks_per_sec(), s->tm4[counter].freq);
+ qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu);
}
static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
{
- pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+ PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
int tm = 0;
- offset -= s->base;
-
switch (offset) {
case OSMR3: tm ++;
case OSMR2: tm ++;
return s->tm4[tm].tm.value;
case OSCR:
return s->clock + muldiv64(qemu_get_clock(vm_clock) -
- s->lastload, s->freq, ticks_per_sec);
+ s->lastload, s->freq, get_ticks_per_sec());
case OSCR11: tm ++;
case OSCR10: tm ++;
case OSCR9: tm ++;
s->snapshot = s->tm4[tm - 1].clock + muldiv64(
qemu_get_clock(vm_clock) -
s->tm4[tm - 1].lastload,
- s->tm4[tm - 1].freq, ticks_per_sec);
+ s->tm4[tm - 1].freq, get_ticks_per_sec());
else
s->snapshot = s->tm4[tm - 1].clock;
}
if (!s->tm4[tm].freq)
return s->tm4[tm].clock;
return s->tm4[tm].clock + muldiv64(qemu_get_clock(vm_clock) -
- s->tm4[tm].lastload, s->tm4[tm].freq, ticks_per_sec);
+ s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec());
case OIER:
return s->irq_enabled;
case OSSR: /* Status register */
return s->snapshot;
default:
badreg:
- cpu_abort(cpu_single_env, "pxa2xx_timer_read: Bad offset "
- REG_FMT "\n", offset);
+ hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
}
return 0;
uint32_t value)
{
int i, tm = 0;
- pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
-
- offset -= s->base;
+ PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
switch (offset) {
case OSMR3: tm ++;
break;
default:
badreg:
- cpu_abort(cpu_single_env, "pxa2xx_timer_write: Bad offset "
- REG_FMT "\n", offset);
+ hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
}
}
-static CPUReadMemoryFunc *pxa2xx_timer_readfn[] = {
+static CPUReadMemoryFunc * const pxa2xx_timer_readfn[] = {
pxa2xx_timer_read,
pxa2xx_timer_read,
pxa2xx_timer_read,
};
-static CPUWriteMemoryFunc *pxa2xx_timer_writefn[] = {
+static CPUWriteMemoryFunc * const pxa2xx_timer_writefn[] = {
pxa2xx_timer_write,
pxa2xx_timer_write,
pxa2xx_timer_write,
static void pxa2xx_timer_tick(void *opaque)
{
- struct pxa2xx_timer0_s *t = (struct pxa2xx_timer0_s *) opaque;
- pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info;
+ PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
+ PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->info;
if (i->irq_enabled & (1 << t->num)) {
t->level = 1;
if (t->num == 3)
if (i->reset3 & 1) {
i->reset3 = 0;
- cpu_reset(i->cpustate);
+ qemu_system_reset_request();
}
}
static void pxa2xx_timer_tick4(void *opaque)
{
- struct pxa2xx_timer4_s *t = (struct pxa2xx_timer4_s *) opaque;
- pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->tm.info;
+ PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
+ PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
pxa2xx_timer_tick(&t->tm);
if (t->control & (1 << 3))
pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->tm.num - 4);
}
-static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base,
- qemu_irq *irqs, CPUState *cpustate)
+static void pxa2xx_timer_save(QEMUFile *f, void *opaque)
+{
+ PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+ int i;
+
+ qemu_put_be32s(f, (uint32_t *) &s->clock);
+ qemu_put_be32s(f, (uint32_t *) &s->oldclock);
+ qemu_put_be64s(f, &s->lastload);
+
+ for (i = 0; i < 4; i ++) {
+ qemu_put_be32s(f, &s->timer[i].value);
+ qemu_put_be32(f, s->timer[i].level);
+ }
+ if (s->tm4)
+ for (i = 0; i < 8; i ++) {
+ qemu_put_be32s(f, &s->tm4[i].tm.value);
+ qemu_put_be32(f, s->tm4[i].tm.level);
+ qemu_put_sbe32s(f, &s->tm4[i].oldclock);
+ qemu_put_sbe32s(f, &s->tm4[i].clock);
+ qemu_put_be64s(f, &s->tm4[i].lastload);
+ qemu_put_be32s(f, &s->tm4[i].freq);
+ qemu_put_be32s(f, &s->tm4[i].control);
+ }
+
+ qemu_put_be32s(f, &s->events);
+ qemu_put_be32s(f, &s->irq_enabled);
+ qemu_put_be32s(f, &s->reset3);
+ qemu_put_be32s(f, &s->snapshot);
+}
+
+static int pxa2xx_timer_load(QEMUFile *f, void *opaque, int version_id)
+{
+ PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+ int64_t now;
+ int i;
+
+ qemu_get_be32s(f, (uint32_t *) &s->clock);
+ qemu_get_be32s(f, (uint32_t *) &s->oldclock);
+ qemu_get_be64s(f, &s->lastload);
+
+ now = qemu_get_clock(vm_clock);
+ for (i = 0; i < 4; i ++) {
+ qemu_get_be32s(f, &s->timer[i].value);
+ s->timer[i].level = qemu_get_be32(f);
+ }
+ pxa2xx_timer_update(s, now);
+
+ if (s->tm4)
+ for (i = 0; i < 8; i ++) {
+ qemu_get_be32s(f, &s->tm4[i].tm.value);
+ s->tm4[i].tm.level = qemu_get_be32(f);
+ qemu_get_sbe32s(f, &s->tm4[i].oldclock);
+ qemu_get_sbe32s(f, &s->tm4[i].clock);
+ qemu_get_be64s(f, &s->tm4[i].lastload);
+ qemu_get_be32s(f, &s->tm4[i].freq);
+ qemu_get_be32s(f, &s->tm4[i].control);
+ pxa2xx_timer_update4(s, now, i);
+ }
+
+ qemu_get_be32s(f, &s->events);
+ qemu_get_be32s(f, &s->irq_enabled);
+ qemu_get_be32s(f, &s->reset3);
+ qemu_get_be32s(f, &s->snapshot);
+
+ return 0;
+}
+
+static PXA2xxTimerInfo *pxa2xx_timer_init(target_phys_addr_t base,
+ DeviceState *pic)
{
int i;
int iomemtype;
- pxa2xx_timer_info *s;
+ PXA2xxTimerInfo *s;
- s = (pxa2xx_timer_info *) qemu_mallocz(sizeof(pxa2xx_timer_info));
- s->base = base;
+ s = (PXA2xxTimerInfo *) qemu_mallocz(sizeof(PXA2xxTimerInfo));
s->irq_enabled = 0;
s->oldclock = 0;
s->clock = 0;
s->lastload = qemu_get_clock(vm_clock);
s->reset3 = 0;
- s->cpustate = cpustate;
for (i = 0; i < 4; i ++) {
s->timer[i].value = 0;
- s->timer[i].irq = irqs[i];
+ s->timer[i].irq = qdev_get_gpio_in(pic, PXA2XX_PIC_OST_0 + i);
s->timer[i].info = s;
s->timer[i].num = i;
s->timer[i].level = 0;
pxa2xx_timer_tick, &s->timer[i]);
}
- iomemtype = cpu_register_io_memory(0, pxa2xx_timer_readfn,
- pxa2xx_timer_writefn, s);
- cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+ iomemtype = cpu_register_io_memory(pxa2xx_timer_readfn,
+ pxa2xx_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
+ cpu_register_physical_memory(base, 0x00001000, iomemtype);
+
+ register_savevm(NULL, "pxa2xx_timer", 0, 0,
+ pxa2xx_timer_save, pxa2xx_timer_load, s);
+
return s;
}
-void pxa25x_timer_init(target_phys_addr_t base,
- qemu_irq *irqs, CPUState *cpustate)
+void pxa25x_timer_init(target_phys_addr_t base, DeviceState *pic)
{
- pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs, cpustate);
+ PXA2xxTimerInfo *s = pxa2xx_timer_init(base, pic);
s->freq = PXA25X_FREQ;
- s->tm4 = 0;
+ s->tm4 = NULL;
}
-void pxa27x_timer_init(target_phys_addr_t base,
- qemu_irq *irqs, qemu_irq irq4, CPUState *cpustate)
+void pxa27x_timer_init(target_phys_addr_t base, DeviceState *pic)
{
- pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs, cpustate);
+ PXA2xxTimerInfo *s = pxa2xx_timer_init(base, pic);
int i;
s->freq = PXA27X_FREQ;
- s->tm4 = (struct pxa2xx_timer4_s *) qemu_mallocz(8 *
- sizeof(struct pxa2xx_timer4_s));
+ s->tm4 = (PXA2xxTimer4 *) qemu_mallocz(8 *
+ sizeof(PXA2xxTimer4));
for (i = 0; i < 8; i ++) {
s->tm4[i].tm.value = 0;
- s->tm4[i].tm.irq = irq4;
+ s->tm4[i].tm.irq = qdev_get_gpio_in(pic, PXA27X_PIC_OST_4_11);
s->tm4[i].tm.info = s;
s->tm4[i].tm.num = i + 4;
s->tm4[i].tm.level = 0;