[PATCH qemu 30/38] wdt: Add Aspeed watchdog device model

Andrew Jeffery andrew at aj.id.au
Mon Nov 28 13:11:23 AEDT 2016


On Mon, 2016-11-21 at 14:03 +0100, Cédric Le Goater wrote:
> On 11/18/2016 03:22 PM, Cédric Le Goater wrote:
> > From: Joel Stanley <joel at jms.id.au>
> > 
> > Signed-off-by: Joel Stanley <joel at jms.id.au>
> > [clg: fixed compile breakage
> >       fixed io region size
> >       added  watchdog_perform_action() on timer expiry ]
> > Signed-off-by: Cédric Le Goater <clg at kaod.org>
> > ---
> >  hw/watchdog/Makefile.objs        |   1 +
> >  hw/watchdog/wdt_aspeed.c         | 194
> > +++++++++++++++++++++++++++++++++++++++
> >  include/hw/watchdog/wdt_aspeed.h |  41 +++++++++
> >  3 files changed, 236 insertions(+)
> >  create mode 100644 hw/watchdog/wdt_aspeed.c
> >  create mode 100644 include/hw/watchdog/wdt_aspeed.h
> > 
> > diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs
> > index 72e3ffd93c59..9589bed63a3d 100644
> > --- a/hw/watchdog/Makefile.objs
> > +++ b/hw/watchdog/Makefile.objs
> > @@ -2,3 +2,4 @@ common-obj-y += watchdog.o
> >  common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
> >  common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
> >  common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o
> > +common-obj-$(CONFIG_ASPEED_SOC) += wdt_aspeed.o
> > diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c
> > new file mode 100644
> > index 000000000000..29d9d7f91463
> > --- /dev/null
> > +++ b/hw/watchdog/wdt_aspeed.c
> > @@ -0,0 +1,194 @@
> > +/*
> > + * Copyright 2016 IBM Corporation
> > + *
> > + * This code is licensed under the GPL version 2 or later.  See
> > + * the COPYING file in the top-level directory.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qemu/log.h"
> > +#include "sysemu/watchdog.h"
> > +#include "hw/sysbus.h"
> > +#include "qemu/timer.h"
> > +#include "hw/watchdog/wdt_aspeed.h"
> > +
> > +#define WDT_IO_REGION_SIZE      0x1000
> > +
> > +#define WDT_STATUS              0x00
> > +#define WDT_RELOAD_VALUE        0x04
> > +#define WDT_RESTART             0x08
> > +#define WDT_CTRL                0x0C
> > +#define WDT_TIMEOUT_STATUS      0x10
> > +#define WDT_TIMEOUT_CLEAR       0x14
> > +#define WDT_RESET_WDITH         0x18
> 
> 
> May be we should reduce the size of WDT_IO_REGION_SIZE to 0x20
> to instantiate the three watchdog of the Aspeed AST2500 with 
> one class ? 
> 
> Here is the layout :
> 
> WDT00: WDT1 Counter Status Register
> WDT04: WDT1 Counter Reload Value Register
> WDT08: WDT1 Counter Restart Register
> WDT0C: WDT1 Control Register
> WDT10: WDT1 Timeout Status Register
> WDT14: WDT1 Clear Timeout Status Register
> WDT18: WDT1 Reset Width Register
> WDT1C: WDT1 Reset Mask Register (AST2500)
> 
> WDT20: WDT2 Counter Status Register
> WDT24: WDT2 Counter Reload Value Register
> WDT28: WDT2 Counter Restart Register
> WDT2C: WDT2 Control Register
> WDT30: WDT2 Timeout Status Register
> WDT34: WDT2 Clear Timeout Status Register
> WDT38: WDT2 Reset Width Register
> WDT3C: WDT2 Reset Mask Register  (AST2500)
> 
> WDT40: WDT3 Counter Status Register  (AST2500)
> WDT44: WDT3 Counter Reload Value Register  (AST2500)
> WDT48: WDT3 Counter Restart Register  (AST2500)
> WDT4C: WDT3 Control Register  (AST2500)
> WDT50: WDT3 Timeout Status Register  (AST2500)
> WDT54: WDT3 Clear Timeout Status Register  (AST2500)
> WDT5C: WDT3 Reset Mask Register  (AST2500)
> 

If we're hacking it, can we squash the timer fixups and clock rate
derivation into the initial commit? I don't like the idea of sending it
broken.

Andrew

> C.
> 
> 
> 
> 
> > +#define WDT_RESTART_MAGIC       0x4755
> > +
> > +static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset,
> > unsigned size)
> > +{
> > +    AspeedWDTState *s = ASPEED_WDT(opaque);
> > +
> > +    switch (offset) {
> > +    case WDT_STATUS:
> > +        return s->reg_status;
> > +    case WDT_RELOAD_VALUE:
> > +        return s->reg_reload_value;
> > +    case WDT_RESTART:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: read from write-only reg at offset 0x%"
> > +                      HWADDR_PRIx "\n", __func__, offset);
> > +        return 0;
> > +    case WDT_CTRL:
> > +        return s->reg_ctrl;
> > +    case WDT_TIMEOUT_STATUS:
> > +    case WDT_TIMEOUT_CLEAR:
> > +    case WDT_RESET_WDITH:
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: uninmplemented read at offset 0x%"
> > HWADDR_PRIx "\n",
> > +                      __func__, offset);
> > +        return 0;
> > +    default:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: Out-of-bounds read at offset 0x%"
> > HWADDR_PRIx "\n",
> > +                      __func__, offset);
> > +        return 0;
> > +    }
> > +
> > +}
> > +
> > +static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t
> > data,
> > +                             unsigned size)
> > +{
> > +    AspeedWDTState *s = ASPEED_WDT(opaque);
> > +    bool en = data & BIT(0);
> > +
> > +    switch (offset) {
> > +    case WDT_STATUS:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: write to read-only reg at offset 0x%"
> > +                      HWADDR_PRIx "\n", __func__, offset);
> > +        break;
> > +    case WDT_RELOAD_VALUE:
> > +        s->reg_reload_value = data;
> > +        break;
> > +    case WDT_RESTART:
> > +        if ((data & 0xFFFF) == 0x4755) {
> > +            s->reg_status = s->reg_reload_value;
> > +
> > +            if (s->enabled) {
> > +                timer_mod(s->timer,
> > +                          qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> > +                          s->reg_reload_value *
> > NANOSECONDS_PER_SECOND);
> > +            }
> > +        }
> > +        break;
> > +    case WDT_CTRL:
> > +        if (en && !s->enabled) {
> > +            s->enabled = true;
> > +            timer_mod(s->timer,
> > +                      qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> > +                      s->reg_reload_value *
> > NANOSECONDS_PER_SECOND);
> > +        } else if (!en && s->enabled) {
> > +            s->enabled = false;
> > +            timer_del(s->timer);
> > +        }
> > +        break;
> > +    case WDT_TIMEOUT_STATUS:
> > +    case WDT_TIMEOUT_CLEAR:
> > +    case WDT_RESET_WDITH:
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: uninmplemented write at offset 0x%"
> > HWADDR_PRIx "\n",
> > +                      __func__, offset);
> > +        break;
> > +    default:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: Out-of-bounds write at offset 0x%"
> > HWADDR_PRIx "\n",
> > +                      __func__, offset);
> > +    }
> > +    return;
> > +}
> > +
> > +static WatchdogTimerModel model = {
> > +    .wdt_name = TYPE_ASPEED_WDT,
> > +    .wdt_description = "aspeed watchdog device",
> > +};
> > +
> > +static const VMStateDescription vmstate_aspeed_wdt = {
> > +    .name = "vmstate_aspeed_wdt",
> > +    .version_id = 0,
> > +    .minimum_version_id = 0,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_TIMER_PTR(timer, AspeedWDTState),
> > +        VMSTATE_BOOL(enabled, AspeedWDTState),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static const MemoryRegionOps aspeed_wdt_ops = {
> > +    .read = aspeed_wdt_read,
> > +    .write = aspeed_wdt_write,
> > +    .endianness = DEVICE_LITTLE_ENDIAN,
> > +    .valid.min_access_size = 4,
> > +    .valid.max_access_size = 4,
> > +    .valid.unaligned = false,
> > +};
> > +
> > +static void aspeed_wdt_reset(DeviceState *dev)
> > +{
> > +    AspeedWDTState *s = ASPEED_WDT(dev);
> > +
> > +    s->reg_status = 0x3EF1480;
> > +    s->reg_reload_value = 0x03EF1480;
> > +    s->reg_restart = 0;
> > +    s->reg_ctrl = 0;
> > +
> > +    s->enabled = false;
> > +    timer_del(s->timer);
> > +}
> > +
> > +static void aspeed_wdt_timer_expired(void *dev)
> > +{
> > +    AspeedWDTState *s = ASPEED_WDT(dev);
> > +
> > +    qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
> > +    watchdog_perform_action();
> > +    timer_del(s->timer);
> > +}
> > +
> > +static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
> > +{
> > +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> > +    AspeedWDTState *s = ASPEED_WDT(dev);
> > +
> > +    s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > aspeed_wdt_timer_expired,
> > +                            dev);
> > +
> > +    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_wdt_ops,
> > s,
> > +                          TYPE_ASPEED_WDT, WDT_IO_REGION_SIZE);
> > +    sysbus_init_mmio(sbd, &s->iomem);
> > +}
> > +
> > +static void aspeed_wdt_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +
> > +    dc->realize = aspeed_wdt_realize;
> > +    dc->reset = aspeed_wdt_reset;
> > +    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> > +    dc->vmsd = &vmstate_aspeed_wdt;
> > +}
> > +
> > +static const TypeInfo aspeed_wdt_info = {
> > +    .parent = TYPE_SYS_BUS_DEVICE,
> > +    .name  = TYPE_ASPEED_WDT,
> > +    .instance_size  = sizeof(AspeedWDTState),
> > +    .class_init = aspeed_wdt_class_init,
> > +};
> > +
> > +static void wdt_aspeed_register_types(void)
> > +{
> > +    watchdog_add_model(&model);
> > +    type_register_static(&aspeed_wdt_info);
> > +}
> > +
> > +type_init(wdt_aspeed_register_types)
> > diff --git a/include/hw/watchdog/wdt_aspeed.h
> > b/include/hw/watchdog/wdt_aspeed.h
> > new file mode 100644
> > index 000000000000..dbf45ae968db
> > --- /dev/null
> > +++ b/include/hw/watchdog/wdt_aspeed.h
> > @@ -0,0 +1,41 @@
> > +/*
> > + * ASPEED Watchdog Controller
> > + *
> > + * Copyright (C) 2016 IBM Corp.
> > + *
> > + * This code is licensed under the GPL version 2 or later. See the
> > + * COPYING file in the top-level directory.
> > + */
> > +#ifndef ASPEED_WDT_H
> > +#define ASPEED_WDT_H
> > +
> > +#include "hw/sysbus.h"
> > +
> > +#define TYPE_ASPEED_WDT "aspeed.wdt"
> > +#define ASPEED_WDT(obj) \
> > +    OBJECT_CHECK(AspeedWDTState, (obj), TYPE_ASPEED_WDT)
> > +#define ASPEED_WDT_CLASS(klass) \
> > +    OBJECT_CLASS_CHECK(AspeedWDTClass, (klass), TYPE_ASPEED_WDT)
> > +#define ASPEED_WDT_GET_CLASS(obj) \
> > +    OBJECT_GET_CLASS(AspeedWDTClass, (obj), TYPE_ASPEED_WDT)
> > +
> > +#define WDT_ASPEED_INIT      0
> > +#define WDT_ASPEED_CHANGE    1
> > +#define WDT_ASPEED_CANCEL    2
> > +
> > +typedef struct AspeedWDTState {
> > +    /*< private >*/
> > +    SysBusDevice parent_obj;
> > +    QEMUTimer *timer;
> > +    bool enabled;
> > +
> > +    /*< public >*/
> > +    MemoryRegion iomem;
> > +
> > +    uint32_t reg_status;
> > +    uint32_t reg_reload_value;
> > +    uint32_t reg_restart;
> > +    uint32_t reg_ctrl;
> > +} AspeedWDTState;
> > +
> > +#endif  /* ASPEED_WDT_H */
> > 
> 
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: This is a digitally signed message part
URL: <http://lists.ozlabs.org/pipermail/openbmc/attachments/20161128/399e6309/attachment.sig>


More information about the openbmc mailing list