From patchwork Fri Mar 15 13:13:45 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuo-Jung Su X-Patchwork-Id: 227974 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id F14DA2C0086 for ; Sat, 16 Mar 2013 00:18:29 +1100 (EST) Received: from localhost ([::1]:46354 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UGUWi-00039N-3o for incoming@patchwork.ozlabs.org; Fri, 15 Mar 2013 09:18:28 -0400 Received: from eggs.gnu.org ([208.118.235.92]:33814) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UGUSx-00070O-Uu for qemu-devel@nongnu.org; Fri, 15 Mar 2013 09:14:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UGUSt-0003zf-Hx for qemu-devel@nongnu.org; Fri, 15 Mar 2013 09:14:35 -0400 Received: from mail-pb0-f47.google.com ([209.85.160.47]:38214) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UGUSt-0003zZ-8E for qemu-devel@nongnu.org; Fri, 15 Mar 2013 09:14:31 -0400 Received: by mail-pb0-f47.google.com with SMTP id rp2so3788789pbb.6 for ; Fri, 15 Mar 2013 06:14:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=ZnISag9fRZ8CGoyZc0qSsfa2GEuktjBbNOzGwM3GbDU=; b=k+7RAUyw2anA27sIxpuvlxcZwRDhEasH5Wh07CLLXaSlk3+H1YlO45KnyCde6kau7f I/kD6MK8qJ0whjk9HpHZQ82h44eva3snfWpvT2YX3e0rFUorrSC86Kqs2VGoexCzPXTD kdWtodHO9UT3TbGJu29bGU+7tTgTkdyuCsdpV4YXJmmRFEfCAe8LPqSJ+3GwL/uUC8ke uIyb3PJQRQeRbdYg1ZweUcYtn1cZdIUWGvhpHDpsZRVoz96dOf/O1zHFOgAQUIOPxClL i2/C9GLKlNtwNDKfcnA5rTLpCInRzXawqAe6d/Yq8SjLDyLV0yx0sdr78xEmwrVtq+Fh t/hA== X-Received: by 10.68.129.101 with SMTP id nv5mr15555705pbb.204.1363353270611; Fri, 15 Mar 2013 06:14:30 -0700 (PDT) Received: from localhost.localdomain ([220.132.37.35]) by mx.google.com with ESMTPS id y1sm8752292pbg.10.2013.03.15.06.14.27 (version=TLSv1 cipher=DES-CBC3-SHA bits=168/168); Fri, 15 Mar 2013 06:14:29 -0700 (PDT) From: Kuo-Jung Su To: qemu-devel@nongnu.org Date: Fri, 15 Mar 2013 21:13:45 +0800 Message-Id: <1363353243-11112-8-git-send-email-dantesu@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1363353243-11112-1-git-send-email-dantesu@gmail.com> References: <1363353243-11112-1-git-send-email-dantesu@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 209.85.160.47 Cc: Peter Maydell , i.mitsyanko@samsung.com, Wei-Ren Chen , Blue Swirl , Paul Brook , Kuo-Jung Su , Paolo Bonzini , Andreas , fred.konrad@greensocs.com Subject: [Qemu-devel] [PATCH v8 07/24] hw/arm: add FTWDT010 watchdog timer support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Kuo-Jung Su The FTWDT010 is used to prevent system from infinite loop while software gets trapped in the deadlock. Under the normal operation, users should restart FTWDT010 at the regular intervals before counter counts down to 0. If the counter does reach 0, FTWDT010 will try to reset the system by generating one or a combination of signals, system reset, system interrupt, and external interrupt. Signed-off-by: Kuo-Jung Su --- hw/arm/Makefile.objs | 1 + hw/arm/faraday_a369_soc.c | 14 +++ hw/arm/ftwdt010.c | 209 +++++++++++++++++++++++++++++++++++++++++++++ hw/arm/ftwdt010.h | 35 ++++++++ 4 files changed, 259 insertions(+) create mode 100644 hw/arm/ftwdt010.c create mode 100644 hw/arm/ftwdt010.h diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index bc18e22..bd330f2 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -41,3 +41,4 @@ obj-y += ftintc020.o obj-y += ftahbc020.o obj-y += ftddrii030.o obj-y += ftpwmtmr010.o +obj-y += ftwdt010.o diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c index 874dc74..2ec066d 100644 --- a/hw/arm/faraday_a369_soc.c +++ b/hw/arm/faraday_a369_soc.c @@ -68,6 +68,16 @@ static void a369soc_reset(DeviceState *ds) } static void +a369soc_system_reset(void *opaque) +{ + FaradaySoCState *s = FARADAY_SOC(opaque); + + if (s->cpu) { + cpu_reset(CPU(s->cpu)); + } +} + +static void a369soc_device_init(FaradaySoCState *s) { Error *local_errp = NULL; @@ -177,6 +187,10 @@ a369soc_device_init(FaradaySoCState *s) sysbus_connect_irq(SYS_BUS_DEVICE(ds), 1, s->pic[9]); sysbus_connect_irq(SYS_BUS_DEVICE(ds), 2, s->pic[10]); sysbus_connect_irq(SYS_BUS_DEVICE(ds), 3, s->pic[11]); + + /* ftwdt010 */ + sysbus_create_simple("ftwdt010", 0x92200000, s->pic[46]); + qemu_register_reset(a369soc_system_reset, s); } static void a369soc_realize(DeviceState *dev, Error **errp) diff --git a/hw/arm/ftwdt010.c b/hw/arm/ftwdt010.c new file mode 100644 index 0000000..d9613ca --- /dev/null +++ b/hw/arm/ftwdt010.c @@ -0,0 +1,209 @@ +/* + * QEMU model of the FTWDT010 WatchDog Timer + * + * Copyright (C) 2012 Faraday Technology + * Written by Dante Su + * + * This file is licensed under GNU GPL v2+. + */ + +#include "hw/sysbus.h" +#include "hw/watchdog.h" +#include "sysemu/sysemu.h" +#include "qemu/timer.h" + +#include "ftwdt010.h" + +#define TYPE_FTWDT010 "ftwdt010" + +typedef struct Ftwdt010State { + SysBusDevice busdev; + MemoryRegion mmio; + + qemu_irq irq; + + QEMUTimer *qtimer; + + uint64_t timeout; + uint64_t freq; /* desired source clock */ + uint64_t step; /* get_ticks_per_sec() / freq */ + bool running; + + /* HW register cache */ + uint32_t load; + uint32_t cr; + uint32_t sr; +} Ftwdt010State; + +#define FTWDT010(obj) \ + OBJECT_CHECK(Ftwdt010State, obj, TYPE_FTWDT010) + +static uint64_t +ftwdt010_mem_read(void *opaque, hwaddr addr, unsigned size) +{ + Ftwdt010State *s = FTWDT010(opaque); + uint32_t ret = 0; + + switch (addr) { + case REG_COUNTER: + if (s->cr & CR_EN) { + ret = s->timeout - qemu_get_clock_ms(rt_clock); + ret = MIN(s->load, ret * 1000000ULL / s->step); + } else { + ret = s->load; + } + break; + case REG_LOAD: + return s->load; + case REG_CR: + return s->cr; + case REG_SR: + return s->sr; + case REG_REVR: + return 0x00010601; /* rev. 1.6.1 */ + default: + qemu_log_mask(LOG_GUEST_ERROR, + "ftwdt010: undefined memory access@%#" HWADDR_PRIx "\n", addr); + break; + } + + return ret; +} + +static void +ftwdt010_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + Ftwdt010State *s = FTWDT010(opaque); + + switch (addr) { + case REG_LOAD: + s->load = (uint32_t)val; + break; + case REG_RESTART: + if ((s->cr & CR_EN) && (val == WDT_MAGIC)) { + s->timeout = (s->step * (uint64_t)s->load) / 1000000ULL; + s->timeout = qemu_get_clock_ms(rt_clock) + MAX(s->timeout, 1); + qemu_mod_timer(s->qtimer, s->timeout); + } + break; + case REG_CR: + s->cr = (uint32_t)val; + if (s->cr & CR_EN) { + if (s->running) { + break; + } + s->running = true; + s->timeout = (s->step * (uint64_t)s->load) / 1000000ULL; + s->timeout = qemu_get_clock_ms(rt_clock) + MAX(s->timeout, 1); + qemu_mod_timer(s->qtimer, s->timeout); + } else { + s->running = false; + qemu_del_timer(s->qtimer); + } + break; + case REG_SCR: + s->sr &= ~(uint32_t)val; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "ftwdt010: undefined memory access@%#" HWADDR_PRIx "\n", addr); + break; + } +} + +static const MemoryRegionOps mmio_ops = { + .read = ftwdt010_mem_read, + .write = ftwdt010_mem_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static void ftwdt010_timer_tick(void *opaque) +{ + Ftwdt010State *s = FTWDT010(opaque); + + s->sr = SR_SRST; + + /* send interrupt signal */ + qemu_set_irq(s->irq, (s->cr & CR_INTR) ? 1 : 0); + + /* send system reset */ + if (s->cr & CR_SRST) { + watchdog_perform_action(); + } +} + +static void ftwdt010_reset(DeviceState *ds) +{ + Ftwdt010State *s = FTWDT010(SYS_BUS_DEVICE(ds)); + + s->cr = 0; + s->sr = 0; + s->load = 0x3ef1480; + s->timeout = 0; +} + +static void ftwdt010_realize(DeviceState *dev, Error **errp) +{ + Ftwdt010State *s = FTWDT010(dev); + + s->step = (uint64_t)get_ticks_per_sec() / s->freq; + s->qtimer = qemu_new_timer_ms(rt_clock, ftwdt010_timer_tick, s); + + memory_region_init_io(&s->mmio, + &mmio_ops, + s, + TYPE_FTWDT010, + 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); +} + +static const VMStateDescription vmstate_ftwdt010 = { + .name = TYPE_FTWDT010, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(timeout, Ftwdt010State), + VMSTATE_UINT64(freq, Ftwdt010State), + VMSTATE_UINT64(step, Ftwdt010State), + VMSTATE_UINT32(load, Ftwdt010State), + VMSTATE_UINT32(cr, Ftwdt010State), + VMSTATE_UINT32(sr, Ftwdt010State), + VMSTATE_END_OF_LIST() + } +}; + +static Property ftwdt010_properties[] = { + DEFINE_PROP_UINT64("freq", Ftwdt010State, freq, 66000000ULL), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ftwdt010_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_ftwdt010; + dc->props = ftwdt010_properties; + dc->reset = ftwdt010_reset; + dc->realize = ftwdt010_realize; + dc->no_user = 1; +} + +static const TypeInfo ftwdt010_info = { + .name = TYPE_FTWDT010, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Ftwdt010State), + .class_init = ftwdt010_class_init, +}; + +static void ftwdt010_register_types(void) +{ + type_register_static(&ftwdt010_info); +} + +type_init(ftwdt010_register_types) diff --git a/hw/arm/ftwdt010.h b/hw/arm/ftwdt010.h new file mode 100644 index 0000000..46c0871 --- /dev/null +++ b/hw/arm/ftwdt010.h @@ -0,0 +1,35 @@ +/* + * QEMU model of the FTWDT010 WatchDog Timer + * + * Copyright (C) 2012 Faraday Technology + * Written by Dante Su + * + * This file is licensed under GNU GPL v2+. + */ + +#ifndef HW_ARM_FTWDT010_H +#define HW_ARM_FTWDT010_H + +#include "qemu/bitops.h" + +/* Hardware registers */ +#define REG_COUNTER 0x00 /* counter register */ +#define REG_LOAD 0x04 /* (re)load register */ +#define REG_RESTART 0x08 /* restart register */ +#define REG_CR 0x0C /* control register */ +#define REG_SR 0x10 /* status register */ +#define REG_SCR 0x14 /* status clear register */ +#define REG_INTR_LEN 0x18 /* interrupt length register */ +#define REG_REVR 0x1C /* revision register */ + +#define CR_CLKS BIT(4) /* clock source */ +#define CR_ESIG BIT(3) /* external signal enabled */ +#define CR_INTR BIT(2) /* system reset interrupt enabled */ +#define CR_SRST BIT(1) /* system reset enabled */ +#define CR_EN BIT(0) /* chip enabled */ + +#define SR_SRST BIT(1) /* system reset */ + +#define WDT_MAGIC 0x5ab9 /* magic for watchdog restart */ + +#endif