@@ -63,9 +63,9 @@ static inline int a9_gtimer_get_current_cpu(A9GTimerState *s)
static inline uint64_t a9_gtimer_get_conv(A9GTimerState *s)
{
uint64_t prescale = extract32(s->control, R_CONTROL_PRESCALER_SHIFT,
- R_CONTROL_PRESCALER_LEN);
-
- return (prescale + 1) * 10;
+ R_CONTROL_PRESCALER_LEN) + 1;
+ uint64_t ret = NANOSECONDS_PER_SECOND * prescale * 10;
+ return (uint32_t) (ret / s->cpu_clk_freq_hz);
}
static A9GTimerUpdate a9_gtimer_get_update(A9GTimerState *s)
@@ -374,6 +374,8 @@ static const VMStateDescription vmstate_a9_gtimer = {
};
static const Property a9_gtimer_properties[] = {
+ DEFINE_PROP_UINT64("cpu-freq", A9GTimerState, cpu_clk_freq_hz,
+ NANOSECONDS_PER_SECOND),
DEFINE_PROP_UINT32("num-cpu", A9GTimerState, num_cpu, 0),
};
@@ -59,9 +59,11 @@ static inline void timerblock_update_irq(TimerBlock *tb)
}
/* Return conversion factor from mpcore timer ticks to qemu timer ticks. */
-static inline uint32_t timerblock_scale(uint32_t control)
+static inline uint32_t timerblock_scale(TimerBlock *tb, uint32_t control)
{
- return (((control >> 8) & 0xff) + 1) * 10;
+ uint64_t prescale = (((control >> 8) & 0xff) + 1);
+ uint64_t ret = NANOSECONDS_PER_SECOND * prescale * 10;
+ return (uint32_t) (ret / tb->freq_hz);
}
/* Must be called within a ptimer transaction block */
@@ -155,7 +157,7 @@ static void timerblock_write(void *opaque, hwaddr addr,
ptimer_stop(tb->timer);
}
if ((control & 0xff00) != (value & 0xff00)) {
- ptimer_set_period(tb->timer, timerblock_scale(value));
+ ptimer_set_period(tb->timer, timerblock_scale(tb, value));
}
if (value & 1) {
uint64_t count = ptimer_get_count(tb->timer);
@@ -222,7 +224,8 @@ static void timerblock_reset(TimerBlock *tb)
ptimer_transaction_begin(tb->timer);
ptimer_stop(tb->timer);
ptimer_set_limit(tb->timer, 0, 1);
- ptimer_set_period(tb->timer, timerblock_scale(0));
+ ptimer_set_period(tb->timer,
+ timerblock_scale(tb, tb->control));
ptimer_transaction_commit(tb->timer);
}
}
@@ -269,6 +272,7 @@ static void arm_mptimer_realize(DeviceState *dev, Error **errp)
*/
for (i = 0; i < s->num_cpu; i++) {
TimerBlock *tb = &s->timerblock[i];
+ tb->freq_hz = s->clk_freq_hz;
tb->timer = ptimer_init(timerblock_tick, tb, PTIMER_POLICY);
sysbus_init_irq(sbd, &tb->irq);
memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb,
@@ -283,6 +287,7 @@ static const VMStateDescription vmstate_timerblock = {
.minimum_version_id = 3,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(control, TimerBlock),
+ VMSTATE_UINT64(freq_hz, TimerBlock),
VMSTATE_UINT32(status, TimerBlock),
VMSTATE_PTIMER(timer, TimerBlock),
VMSTATE_END_OF_LIST()
@@ -301,6 +306,8 @@ static const VMStateDescription vmstate_arm_mptimer = {
};
static const Property arm_mptimer_properties[] = {
+ DEFINE_PROP_UINT64("clk-freq", ARMMPTimerState, clk_freq_hz,
+ NANOSECONDS_PER_SECOND),
DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0),
};
@@ -76,6 +76,7 @@ struct A9GTimerState {
MemoryRegion iomem;
/* static props */
+ uint64_t cpu_clk_freq_hz;
uint32_t num_cpu;
QEMUTimer *timer;
@@ -31,6 +31,7 @@ typedef struct {
uint32_t control;
uint32_t status;
struct ptimer_state *timer;
+ uint64_t freq_hz;
qemu_irq irq;
MemoryRegion iomem;
} TimerBlock;
@@ -43,6 +44,7 @@ struct ARMMPTimerState {
SysBusDevice parent_obj;
/*< public >*/
+ uint64_t clk_freq_hz;
uint32_t num_cpu;
TimerBlock timerblock[ARM_MPTIMER_MAX_CPUS];
MemoryRegion iomem;