Skip to content

Commit

Permalink
watchdog/aspeed: Fix AST2600 frequency behaviour
Browse files Browse the repository at this point in the history
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: 6b2b2a7 ("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>
  • Loading branch information
shenki authored and pm215 committed Dec 16, 2019
1 parent aabf1de commit 28c80f1
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 4 deletions.
21 changes: 17 additions & 4 deletions hw/watchdog/wdt_aspeed.c
Expand Up @@ -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 {
Expand All @@ -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)
{
Expand All @@ -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);
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 = {
Expand All @@ -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 = {
Expand Down
1 change: 1 addition & 0 deletions include/hw/watchdog/wdt_aspeed.h
Expand Up @@ -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 */

0 comments on commit 28c80f1

Please sign in to comment.