diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 5adf9c2..b5762e9 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 d4b2677..ce58fa7 100644
--- a/hw/arm/faraday_a369_soc.c
+++ b/hw/arm/faraday_a369_soc.c
@@ -69,6 +69,25 @@ static void a369soc_reset(DeviceState *ds)
 }
 
 static void
+a369soc_system_reset(void *opaque)
+{
+    FaradaySoCState *s = FARADAY_SOC(opaque);
+
+    if (s->scu) {
+        device_reset(s->scu);
+    }
+    if (s->ddrc) {
+        device_reset(s->ddrc);
+    }
+    if (s->ahbc) {
+        device_reset(s->ahbc);
+    }
+    if (s->cpu) {
+        cpu_reset(CPU(s->cpu));
+    }
+}
+
+static void
 a369soc_device_init(FaradaySoCState *s)
 {
     DriveInfo *dinfo;
@@ -161,6 +180,10 @@ a369soc_device_init(FaradaySoCState *s)
     sysbus_connect_irq(SYS_BUS_DEVICE(ds), 1, pic[9]);
     sysbus_connect_irq(SYS_BUS_DEVICE(ds), 2, pic[10]);
     sysbus_connect_irq(SYS_BUS_DEVICE(ds), 3, pic[11]);
+
+    /* ftwdt010 */
+    sysbus_create_simple("ftwdt010", 0x92200000, pic[46]);
+    qemu_register_reset(a369soc_system_reset, s);
 }
 
 static int a369soc_init(SysBusDevice *busdev)
diff --git a/hw/arm/ftwdt010.c b/hw/arm/ftwdt010.c
new file mode 100644
index 0000000..c641cc8
--- /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 <dantesu@faraday-tech.com>
+ *
+ * This file is licensed under GNU GPL v2+.
+ */
+
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "qemu/timer.h"
+
+#include "faraday.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:
+        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:
+        break;
+    }
+}
+
+static const MemoryRegionOps ftwdt010_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) {
+        qemu_system_reset_request();
+    }
+}
+
+static void ftwdt010_reset(DeviceState *ds)
+{
+    SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
+    Ftwdt010State *s = FTWDT010(FROM_SYSBUS(Ftwdt010State, busdev));
+
+    s->cr      = 0;
+    s->sr      = 0;
+    s->load    = 0x3ef1480;
+    s->timeout = 0;
+}
+
+static int ftwdt010_init(SysBusDevice *dev)
+{
+    Ftwdt010State *s = FTWDT010(FROM_SYSBUS(Ftwdt010State, 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,
+                          &ftwdt010_ops,
+                          s,
+                          TYPE_FTWDT010,
+                          0x1000);
+    sysbus_init_mmio(dev, &s->mmio);
+    sysbus_init_irq(dev, &s->irq);
+
+    return 0;
+}
+
+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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init     = ftwdt010_init;
+    dc->vmsd    = &vmstate_ftwdt010;
+    dc->props   = ftwdt010_properties;
+    dc->reset   = ftwdt010_reset;
+    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..606fd78
--- /dev/null
+++ b/hw/arm/ftwdt010.h
@@ -0,0 +1,33 @@
+/*
+ * QEMU model of the FTWDT010 WatchDog Timer
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is licensed under GNU GPL v2+.
+ */
+
+#ifndef HW_ARM_FTWDT010_H
+#define HW_ARM_FTWDT010_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
