aboutsummaryrefslogtreecommitdiff
path: root/hw/timer/aspeed_timer.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-06-13 15:49:07 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-06-13 15:49:07 +0100
commit3f0602927b120a480b35dcf58cf6f95435b3ae91 (patch)
tree1fbc5246de0adb98a9800000374a3a1e977e0c6b /hw/timer/aspeed_timer.c
parent6f153ceb9bb8233dd3887320737aba90554ddd70 (diff)
parent252a7a6a968c279a4636a86b0559ba3a930a90b5 (diff)
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20170613' into staging
target-arm queue: * vITS: Support save/restore * timer/aspeed: Fix timer enablement when reload is not set * aspped: add temperature sensor device * timer.h: Provide better monotonic time on ARM hosts * exynos4210: various cleanups * exynos4210: support system poweroff # gpg: Signature made Tue 13 Jun 2017 15:05:49 BST # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20170613: hw/intc/arm_gicv3_its: Allow save/restore hw/intc/arm_gicv3_kvm: Implement pending table save hw/intc/arm_gicv3_its: Implement state save/restore kvm-all: Pass an error object to kvm_device_access timer/aspeed: fix timer enablement when a reload is not set aspeed: add a temp sensor device on I2C bus 3 hw/misc: add a TMP42{1, 2, 3} device model timer.h: Provide better monotonic time hw/misc/exynos4210_pmu: Add support for system poweroff hw/intc/exynos4210_gic: Constify array of combiner interrupts hw/arm/exynos: Use type define instead of hard-coded a9mpcore_priv string hw/arm/exynos: Declare local variables in some order hw/arm/exynos: Move DRAM initialization next boards hw/timer/exynos4210_mct: Remove unused defines hw/timer/exynos4210_mct: Cleanup indentation and empty new lines hw/timer/exynos4210_mct: Fix checkpatch style errors hw/intc/exynos4210_gic: Use more meaningful name for local variable Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/timer/aspeed_timer.c')
-rw-r--r--hw/timer/aspeed_timer.c37
1 files changed, 29 insertions, 8 deletions
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index 9b70ee09b0..50acbf530a 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -130,15 +130,26 @@ static uint64_t calculate_next(struct AspeedTimer *t)
next = seq[1];
} else if (now < seq[2]) {
next = seq[2];
- } else {
+ } else if (t->reload) {
reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate);
t->start = now - ((now - t->start) % reload_ns);
+ } else {
+ /* no reload value, return 0 */
+ break;
}
}
return next;
}
+static void aspeed_timer_mod(AspeedTimer *t)
+{
+ uint64_t next = calculate_next(t);
+ if (next) {
+ timer_mod(&t->timer, next);
+ }
+}
+
static void aspeed_timer_expire(void *opaque)
{
AspeedTimer *t = opaque;
@@ -164,7 +175,7 @@ static void aspeed_timer_expire(void *opaque)
qemu_set_irq(t->irq, t->level);
}
- timer_mod(&t->timer, calculate_next(t));
+ aspeed_timer_mod(t);
}
static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
@@ -227,10 +238,23 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
uint32_t value)
{
AspeedTimer *t;
+ uint32_t old_reload;
trace_aspeed_timer_set_value(timer, reg, value);
t = &s->timers[timer];
switch (reg) {
+ case TIMER_REG_RELOAD:
+ old_reload = t->reload;
+ t->reload = value;
+
+ /* If the reload value was not previously set, or zero, and
+ * the current value is valid, try to start the timer if it is
+ * enabled.
+ */
+ if (old_reload || !t->reload) {
+ break;
+ }
+
case TIMER_REG_STATUS:
if (timer_enabled(t)) {
uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
@@ -238,17 +262,14 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
uint32_t rate = calculate_rate(t);
t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
- timer_mod(&t->timer, calculate_next(t));
+ aspeed_timer_mod(t);
}
break;
- case TIMER_REG_RELOAD:
- t->reload = value;
- break;
case TIMER_REG_MATCH_FIRST:
case TIMER_REG_MATCH_SECOND:
t->match[reg - 2] = value;
if (timer_enabled(t)) {
- timer_mod(&t->timer, calculate_next(t));
+ aspeed_timer_mod(t);
}
break;
default:
@@ -268,7 +289,7 @@ static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable)
trace_aspeed_timer_ctrl_enable(t->id, enable);
if (enable) {
t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- timer_mod(&t->timer, calculate_next(t));
+ aspeed_timer_mod(t);
} else {
timer_del(&t->timer);
}