diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c index 3ebdc7be408c3deb6dfd134681dfee7eec0a76db..801d1dba7410849dd675b4eaa52664d295c6f84d 100644 --- a/hw/timer/cmsdk-apb-timer.c +++ b/hw/timer/cmsdk-apb-timer.c @@ -126,10 +126,26 @@ static void cmsdk_apb_timer_write(void *opaque, hwaddr offset, uint64_t value, break; case A_RELOAD: /* Writing to reload also sets the current timer value */ + if (!value) { + ptimer_stop(s->timer); + } ptimer_set_limit(s->timer, value, 1); + if (value && (s->ctrl & R_CTRL_EN_MASK)) { + /* + * Make sure timer is running (it might have stopped if this + * was an expired one-shot timer) + */ + ptimer_run(s->timer, 0); + } break; case A_VALUE: + if (!value && !ptimer_get_limit(s->timer)) { + ptimer_stop(s->timer); + } ptimer_set_count(s->timer, value); + if (value && (s->ctrl & R_CTRL_EN_MASK)) { + ptimer_run(s->timer, ptimer_get_limit(s->timer) == 0); + } break; case A_INTSTATUS: /* Just one bit, which is W1C. */