qemu-arm
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-arm] [PATCH v3] hw/arm/stellaris: Implement watchdog timer


From: Peter Maydell
Subject: Re: [Qemu-arm] [PATCH v3] hw/arm/stellaris: Implement watchdog timer
Date: Tue, 5 Mar 2019 13:40:28 +0000

This didn't make it to the mailing lists for some reason (the
server does occasionally eat emails :-(). Sending this as a
reply to see if that makes it through OK...

(I'll also review it in a moment.)

thanks
-- PMM

On Mon, 4 Mar 2019 at 23:16, <address@hidden> wrote:
>
> From: Michel Heily <address@hidden>
>
> I've added the stellaris watchdog functionality because I needed it for a 
> home project.
> Documentation for the hardware can be found at 
> http://www.ti.com/lit/ds/symlink/lm3s6965.pdf.
>
> Signed-off-by: Michel Heily <address@hidden>
> ---
>  hw/arm/stellaris.c                       | 22 ++++++++++-
>  hw/watchdog/cmsdk-apb-watchdog.c         | 66 
> +++++++++++++++++++++++++++++++-
>  include/hw/watchdog/cmsdk-apb-watchdog.h |  5 +++
>  3 files changed, 89 insertions(+), 4 deletions(-)
>
> diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
> index 442529c..7918b28 100644
> --- a/hw/arm/stellaris.c
> +++ b/hw/arm/stellaris.c
> @@ -22,6 +22,7 @@
>  #include "sysemu/sysemu.h"
>  #include "hw/arm/armv7m.h"
>  #include "hw/char/pl011.h"
> +#include "hw/watchdog/cmsdk-apb-watchdog.h"
>  #include "hw/misc/unimp.h"
>  #include "cpu.h"
>
> @@ -1243,7 +1244,7 @@ static void stellaris_init(MachineState *ms, 
> stellaris_board_info *board)
>       * Stellaris LM3S6965 Microcontroller Data Sheet (rev I)
>       * http://www.ti.com/lit/ds/symlink/lm3s6965.pdf
>       *
> -     * 40000000 wdtimer (unimplemented)
> +     * 40000000 wdtimer
>       * 40002000 i2c (unimplemented)
>       * 40004000 GPIO
>       * 40005000 GPIO
> @@ -1338,6 +1339,24 @@ static void stellaris_init(MachineState *ms, 
> stellaris_board_info *board)
>      stellaris_sys_init(0x400fe000, qdev_get_gpio_in(nvic, 28),
>                         board, nd_table[0].macaddr.a);
>
> +
> +    if (board->dc1 & (1 << 3)) { /* watchdog present */
> +        dev = qdev_create(NULL, TYPE_LUMINARY_WATCHDOG);
> +
> +        /* system_clock_scale is valid now */
> +        uint32_t mainclk = NANOSECONDS_PER_SECOND / system_clock_scale;
> +        qdev_prop_set_uint32(dev, "wdogclk-frq", mainclk);
> +
> +        qdev_init_nofail(dev);
> +        sysbus_mmio_map(SYS_BUS_DEVICE(dev),
> +                        0,
> +                        0x40000000u);
> +        sysbus_connect_irq(SYS_BUS_DEVICE(dev),
> +                           0,
> +                           qdev_get_gpio_in(nvic, 18));
> +    }
> +
> +
>      for (i = 0; i < 7; i++) {
>          if (board->dc4 & (1 << i)) {
>              gpio_dev[i] = sysbus_create_simple("pl061_luminary", 
> gpio_addr[i],
> @@ -1431,7 +1450,6 @@ static void stellaris_init(MachineState *ms, 
> stellaris_board_info *board)
>      /* Add dummy regions for the devices we don't implement yet,
>       * so guest accesses don't cause unlogged crashes.
>       */
> -    create_unimplemented_device("wdtimer", 0x40000000, 0x1000);
>      create_unimplemented_device("i2c-0", 0x40002000, 0x1000);
>      create_unimplemented_device("i2c-2", 0x40021000, 0x1000);
>      create_unimplemented_device("PWM", 0x40028000, 0x1000);
> diff --git a/hw/watchdog/cmsdk-apb-watchdog.c 
> b/hw/watchdog/cmsdk-apb-watchdog.c
> index eb79a73..f20f573 100644
> --- a/hw/watchdog/cmsdk-apb-watchdog.c
> +++ b/hw/watchdog/cmsdk-apb-watchdog.c
> @@ -37,6 +37,7 @@ REG32(WDOGINTCLR, 0xc)
>  REG32(WDOGRIS, 0x10)
>      FIELD(WDOGRIS, INT, 0, 1)
>  REG32(WDOGMIS, 0x14)
> +REG32(WDOGTEST, 0x418) /* only in the Stellaris/Luminary version of the 
> device */
>  REG32(WDOGLOCK, 0xc00)
>  #define WDOG_UNLOCK_VALUE 0x1ACCE551
>  REG32(WDOGITCR, 0xf00)
> @@ -61,12 +62,18 @@ REG32(CID2, 0xff8)
>  REG32(CID3, 0xffc)
>
>  /* PID/CID values */
> -static const int watchdog_id[] = {
> +static const uint32_t cmsdk_apb_watchdog_id[] = {
>      0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
>      0x24, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
>      0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
>  };
>
> +static const uint32_t luminary_watchdog_id[] = {
> +    0x00, 0x00, 0x00, 0x00, /* PID4..PID7 */
> +    0x05, 0x18, 0x18, 0x01, /* PID0..PID3 */
> +    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
> +};
> +
>  static bool cmsdk_apb_watchdog_intstatus(CMSDKAPBWatchdog *s)
>  {
>      /* Return masked interrupt status */
> @@ -85,6 +92,10 @@ static void cmsdk_apb_watchdog_update(CMSDKAPBWatchdog *s)
>      bool wdogres;
>
>      if (s->itcr) {
> +        /*
> +         * Not checking that !s->is_luminary since s->itcr can't be written
> +         * when s->is_luminary in the first place.
> +         */
>          wdogint = s->itop & R_WDOGITOP_WDOGINT_MASK;
>          wdogres = s->itop & R_WDOGITOP_WDOGRES_MASK;
>      } else {
> @@ -124,19 +135,34 @@ static uint64_t cmsdk_apb_watchdog_read(void *opaque, 
> hwaddr offset,
>          r = s->lock;
>          break;
>      case A_WDOGITCR:
> +        if (s->is_luminary) {
> +            goto bad_offset;
> +        }
>          r = s->itcr;
>          break;
>      case A_PID4 ... A_CID3:
> -        r = watchdog_id[(offset - A_PID4) / 4];
> +        r = s->id[(offset - A_PID4) / 4];
>          break;
>      case A_WDOGINTCLR:
>      case A_WDOGITOP:
> +        if (s->is_luminary) {
> +            goto bad_offset;
> +        }
>          qemu_log_mask(LOG_GUEST_ERROR,
>                        "CMSDK APB watchdog read: read of WO offset %x\n",
>                        (int)offset);
>          r = 0;
>          break;
> +    case A_WDOGTEST:
> +        if (!s->is_luminary) {
> +            goto bad_offset;
> +        }
> +        qemu_log_mask(LOG_UNIMP,
> +                      "Luminary watchdog read: stall not implemented\n");
> +        r = 0;
> +        break;
>      default:
> +bad_offset:
>          qemu_log_mask(LOG_GUEST_ERROR,
>                        "CMSDK APB watchdog read: bad offset %x\n", 
> (int)offset);
>          r = 0;
> @@ -170,6 +196,10 @@ static void cmsdk_apb_watchdog_write(void *opaque, 
> hwaddr offset,
>          ptimer_run(s->timer, 0);
>          break;
>      case A_WDOGCONTROL:
> +        if (s->is_luminary && 0 != (R_WDOGCONTROL_INTEN_MASK & s->control)) {
> +            /* ignore writes to the control register since interrupts were 
> enabled */
> +            break;
> +        }
>          s->control = value & R_WDOGCONTROL_VALID_MASK;
>          cmsdk_apb_watchdog_update(s);
>          break;
> @@ -182,10 +212,16 @@ static void cmsdk_apb_watchdog_write(void *opaque, 
> hwaddr offset,
>          s->lock = (value != WDOG_UNLOCK_VALUE);
>          break;
>      case A_WDOGITCR:
> +        if (s->is_luminary) {
> +            goto bad_offset;
> +        }
>          s->itcr = value & R_WDOGITCR_VALID_MASK;
>          cmsdk_apb_watchdog_update(s);
>          break;
>      case A_WDOGITOP:
> +        if (s->is_luminary) {
> +            goto bad_offset;
> +        }
>          s->itop = value & R_WDOGITOP_VALID_MASK;
>          cmsdk_apb_watchdog_update(s);
>          break;
> @@ -197,7 +233,15 @@ static void cmsdk_apb_watchdog_write(void *opaque, 
> hwaddr offset,
>                        "CMSDK APB watchdog write: write to RO offset 0x%x\n",
>                        (int)offset);
>          break;
> +    case A_WDOGTEST:
> +        if (!s->is_luminary) {
> +            goto bad_offset;
> +        }
> +        qemu_log_mask(LOG_UNIMP,
> +                      "Luminary watchdog write: stall not implemented\n");
> +        break;
>      default:
> +bad_offset:
>          qemu_log_mask(LOG_GUEST_ERROR,
>                        "CMSDK APB watchdog write: bad offset 0x%x\n",
>                        (int)offset);
> @@ -256,6 +300,9 @@ static void cmsdk_apb_watchdog_init(Object *obj)
>                            s, "cmsdk-apb-watchdog", 0x1000);
>      sysbus_init_mmio(sbd, &s->iomem);
>      sysbus_init_irq(sbd, &s->wdogint);
> +
> +    s->is_luminary = false;
> +    s->id = cmsdk_apb_watchdog_id;
>  }
>
>  static void cmsdk_apb_watchdog_realize(DeviceState *dev, Error **errp)
> @@ -318,9 +365,24 @@ static const TypeInfo cmsdk_apb_watchdog_info = {
>      .class_init = cmsdk_apb_watchdog_class_init,
>  };
>
> +static void luminary_watchdog_init(Object *obj)
> +{
> +    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(obj);
> +
> +    s->is_luminary = true;
> +    s->id = luminary_watchdog_id;
> +}
> +
> +static const TypeInfo luminary_watchdog_info = {
> +    .name = TYPE_LUMINARY_WATCHDOG,
> +    .parent = TYPE_CMSDK_APB_WATCHDOG,
> +    .instance_init = luminary_watchdog_init
> +};
> +
>  static void cmsdk_apb_watchdog_register_types(void)
>  {
>      type_register_static(&cmsdk_apb_watchdog_info);
> +    type_register_static(&luminary_watchdog_info);
>  }
>
>  type_init(cmsdk_apb_watchdog_register_types);
> diff --git a/include/hw/watchdog/cmsdk-apb-watchdog.h 
> b/include/hw/watchdog/cmsdk-apb-watchdog.h
> index ab8b598..070b804 100644
> --- a/include/hw/watchdog/cmsdk-apb-watchdog.h
> +++ b/include/hw/watchdog/cmsdk-apb-watchdog.h
> @@ -38,6 +38,9 @@
>  #define CMSDK_APB_WATCHDOG(obj) OBJECT_CHECK(CMSDKAPBWatchdog, (obj), \
>                                                TYPE_CMSDK_APB_WATCHDOG)
>
> +/* This shares the same struct (and cast macro) as the base 
> cmsdk-apb-watchdog device */
> +#define TYPE_LUMINARY_WATCHDOG "luminary-watchdog"
> +
>  typedef struct CMSDKAPBWatchdog {
>      /*< private >*/
>      SysBusDevice parent_obj;
> @@ -46,6 +49,7 @@ typedef struct CMSDKAPBWatchdog {
>      MemoryRegion iomem;
>      qemu_irq wdogint;
>      uint32_t wdogclk_frq;
> +    bool is_luminary;
>      struct ptimer_state *timer;
>
>      uint32_t control;
> @@ -54,6 +58,7 @@ typedef struct CMSDKAPBWatchdog {
>      uint32_t itcr;
>      uint32_t itop;
>      uint32_t resetstatus;
> +    const uint32_t* id;
>  } CMSDKAPBWatchdog;
>
>  #endif
> --
> 2.7.4
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]