aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Stanley <joel@jms.id.au>2019-11-19 15:12:03 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-12-16 10:46:34 +0000
commit28c80f15fc9c4c1ee980e87e693374f196aa20fe (patch)
tree803e45958f1b9fbee16adc86a0a3ea366da492e1
parentaabf1de4b7a2fb14797946f8eb970d391cecf0d8 (diff)
downloadqemu-28c80f15fc9c4c1ee980e87e693374f196aa20fe.zip
qemu-28c80f15fc9c4c1ee980e87e693374f196aa20fe.tar.gz
qemu-28c80f15fc9c4c1ee980e87e693374f196aa20fe.tar.bz2
watchdog/aspeed: Fix AST2600 frequency behaviour
The AST2600 control register sneakily changed the meaning of bit 4 without anyone noticing. It no longer controls the 1MHz vs APB clock select, and instead always runs at 1MHz. The AST2500 was always 1MHz too, but it retained bit 4, making it read only. We can model both using the same fixed 1MHz calculation. Fixes: 6b2b2a703cad ("hw: wdt_aspeed: Add AST2600 support") Reviewed-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Joel Stanley <joel@jms.id.au> Signed-off-by: Cédric Le Goater <clg@kaod.org> Message-id: 20191119141211.25716-10-clg@kaod.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/watchdog/wdt_aspeed.c21
-rw-r--r--include/hw/watchdog/wdt_aspeed.h1
2 files changed, 18 insertions, 4 deletions
diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c
index d283d07..122aa8d 100644
--- a/hw/watchdog/wdt_aspeed.c
+++ b/hw/watchdog/wdt_aspeed.c
@@ -93,11 +93,11 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size)
}
-static void aspeed_wdt_reload(AspeedWDTState *s, bool pclk)
+static void aspeed_wdt_reload(AspeedWDTState *s)
{
uint64_t reload;
- if (pclk) {
+ if (!(s->regs[WDT_CTRL] & WDT_CTRL_1MHZ_CLK)) {
reload = muldiv64(s->regs[WDT_RELOAD_VALUE], NANOSECONDS_PER_SECOND,
s->pclk_freq);
} else {
@@ -109,6 +109,16 @@ static void aspeed_wdt_reload(AspeedWDTState *s, bool pclk)
}
}
+static void aspeed_wdt_reload_1mhz(AspeedWDTState *s)
+{
+ uint64_t reload = s->regs[WDT_RELOAD_VALUE] * 1000ULL;
+
+ if (aspeed_wdt_is_enabled(s)) {
+ timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + reload);
+ }
+}
+
+
static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size)
{
@@ -130,13 +140,13 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
case WDT_RESTART:
if ((data & 0xFFFF) == WDT_RESTART_MAGIC) {
s->regs[WDT_STATUS] = s->regs[WDT_RELOAD_VALUE];
- aspeed_wdt_reload(s, !(s->regs[WDT_CTRL] & WDT_CTRL_1MHZ_CLK));
+ awc->wdt_reload(s);
}
break;
case WDT_CTRL:
if (enable && !aspeed_wdt_is_enabled(s)) {
s->regs[WDT_CTRL] = data;
- aspeed_wdt_reload(s, !(data & WDT_CTRL_1MHZ_CLK));
+ awc->wdt_reload(s);
} else if (!enable && aspeed_wdt_is_enabled(s)) {
s->regs[WDT_CTRL] = data;
timer_del(s->timer);
@@ -283,6 +293,7 @@ static void aspeed_2400_wdt_class_init(ObjectClass *klass, void *data)
awc->offset = 0x20;
awc->ext_pulse_width_mask = 0xff;
awc->reset_ctrl_reg = SCU_RESET_CONTROL1;
+ awc->wdt_reload = aspeed_wdt_reload;
}
static const TypeInfo aspeed_2400_wdt_info = {
@@ -317,6 +328,7 @@ static void aspeed_2500_wdt_class_init(ObjectClass *klass, void *data)
awc->ext_pulse_width_mask = 0xfffff;
awc->reset_ctrl_reg = SCU_RESET_CONTROL1;
awc->reset_pulse = aspeed_2500_wdt_reset_pulse;
+ awc->wdt_reload = aspeed_wdt_reload_1mhz;
}
static const TypeInfo aspeed_2500_wdt_info = {
@@ -336,6 +348,7 @@ static void aspeed_2600_wdt_class_init(ObjectClass *klass, void *data)
awc->ext_pulse_width_mask = 0xfffff; /* TODO */
awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1;
awc->reset_pulse = aspeed_2500_wdt_reset_pulse;
+ awc->wdt_reload = aspeed_wdt_reload_1mhz;
}
static const TypeInfo aspeed_2600_wdt_info = {
diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h
index dfedd76..819c229 100644
--- a/include/hw/watchdog/wdt_aspeed.h
+++ b/include/hw/watchdog/wdt_aspeed.h
@@ -47,6 +47,7 @@ typedef struct AspeedWDTClass {
uint32_t ext_pulse_width_mask;
uint32_t reset_ctrl_reg;
void (*reset_pulse)(AspeedWDTState *s, uint32_t property);
+ void (*wdt_reload)(AspeedWDTState *s);
} AspeedWDTClass;
#endif /* WDT_ASPEED_H */