qemu-arm
[Top][All Lists]
Advanced

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

[Qemu-arm] [PATCH 1/2] arm_mptimer: add watchdog mode support


From: Rabin Vincent
Subject: [Qemu-arm] [PATCH 1/2] arm_mptimer: add watchdog mode support
Date: Wed, 9 Dec 2015 11:26:47 +0100

Add support for the watchdog mode of the MPTimer.

Signed-off-by: Rabin Vincent <address@hidden>
---
 hw/timer/arm_mptimer.c         |   49 ++++++++++++++++++++++++++++++++++++----
 include/hw/timer/arm_mptimer.h |    4 ++++
 2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
index 3e59c2a..2be4551 100644
--- a/hw/timer/arm_mptimer.c
+++ b/hw/timer/arm_mptimer.c
@@ -21,8 +21,11 @@
 
 #include "hw/timer/arm_mptimer.h"
 #include "qemu/timer.h"
+#include "sysemu/sysemu.h"
 #include "qom/cpu.h"
 
+#define TWD_CONTROL_WDOG_MODE   (1 << 3)
+
 /* This device implements the per-cpu private timer and watchdog block
  * which is used in both the ARM11MPCore and Cortex-A9MP.
  */
@@ -38,7 +41,12 @@ static inline int get_current_cpu(ARMMPTimerState *s)
 
 static inline void timerblock_update_irq(TimerBlock *tb)
 {
-    qemu_set_irq(tb->irq, tb->status && (tb->control & 4));
+    if ((tb->control & TWD_CONTROL_WDOG_MODE) && tb->status) {
+        qemu_log_mask(CPU_LOG_RESET, "MPCore Watchdog Reset\n");
+        qemu_system_reset_request();
+    } else {
+        qemu_set_irq(tb->irq, tb->status && (tb->control & 4));
+    }
 }
 
 /* Return conversion factor from mpcore timer ticks to qemu timer ticks.  */
@@ -63,7 +71,7 @@ static void timerblock_tick(void *opaque)
 {
     TimerBlock *tb = (TimerBlock *)opaque;
     tb->status = 1;
-    if (tb->control & 2) {
+    if (!(tb->control & TWD_CONTROL_WDOG_MODE) && (tb->control & 2)) {
         tb->count = tb->load;
         timerblock_reload(tb, 0);
     } else {
@@ -110,6 +118,9 @@ static void timerblock_write(void *opaque, hwaddr addr,
         tb->load = value;
         /* Fall through.  */
     case 4: /* Counter.  */
+        if ((tb->control & TWD_CONTROL_WDOG_MODE) && addr == 4) {
+            return;
+        }
         if ((tb->control & 1) && tb->count) {
             /* Cancel the previous timer.  */
             timer_del(tb->timer);
@@ -121,6 +132,11 @@ static void timerblock_write(void *opaque, hwaddr addr,
         break;
     case 8: /* Control.  */
         old = tb->control;
+        if (tb->wdog) {
+            value |= old & TWD_CONTROL_WDOG_MODE;
+        } else {
+            value &= ~TWD_CONTROL_WDOG_MODE;
+        }
         tb->control = value;
         if (value & 1) {
             if ((old & 1) && (tb->count != 0)) {
@@ -140,6 +156,16 @@ static void timerblock_write(void *opaque, hwaddr addr,
         tb->status &= ~value;
         timerblock_update_irq(tb);
         break;
+    case 20: /* Watchdog disable */
+        if (tb->wdog) {
+            uint32_t last = tb->last_wdog_disable;
+
+            tb->last_wdog_disable = value;
+            if (last == 0x12345678 && value == 0x87654321) {
+                tb->control &= ~TWD_CONTROL_WDOG_MODE;
+            }
+        }
+        break;
     }
 }
 
@@ -182,8 +208,9 @@ static const MemoryRegionOps timerblock_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void timerblock_reset(TimerBlock *tb)
+static void timerblock_reset(TimerBlock *tb, bool wdog)
 {
+    tb->wdog = wdog;
     tb->count = 0;
     tb->load = 0;
     tb->control = 0;
@@ -200,7 +227,7 @@ static void arm_mptimer_reset(DeviceState *dev)
     int i;
 
     for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) {
-        timerblock_reset(&s->timerblock[i]);
+        timerblock_reset(&s->timerblock[i], s->wdog);
     }
 }
 
@@ -213,6 +240,13 @@ static void arm_mptimer_init(Object *obj)
     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
 }
 
+static void arm_mptimer_wdog_init(Object *obj)
+{
+    ARMMPTimerState *s = ARM_MPTIMER(obj);
+
+    s->wdog = true;
+}
+
 static void arm_mptimer_realize(DeviceState *dev, Error **errp)
 {
     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
@@ -292,9 +326,16 @@ static const TypeInfo arm_mptimer_info = {
     .class_init    = arm_mptimer_class_init,
 };
 
+static const TypeInfo arm_mptimer_wdog_info = {
+    .name          = TYPE_ARM_MPTIMER_WDOG,
+    .parent        = TYPE_ARM_MPTIMER,
+    .instance_init = arm_mptimer_wdog_init,
+};
+
 static void arm_mptimer_register_types(void)
 {
     type_register_static(&arm_mptimer_info);
+    type_register_static(&arm_mptimer_wdog_info);
 }
 
 type_init(arm_mptimer_register_types)
diff --git a/include/hw/timer/arm_mptimer.h b/include/hw/timer/arm_mptimer.h
index b34cba0..cd119c1 100644
--- a/include/hw/timer/arm_mptimer.h
+++ b/include/hw/timer/arm_mptimer.h
@@ -31,13 +31,16 @@ typedef struct {
     uint32_t load;
     uint32_t control;
     uint32_t status;
+    uint32_t last_wdog_disable;
     int64_t tick;
+    bool wdog;
     QEMUTimer *timer;
     qemu_irq irq;
     MemoryRegion iomem;
 } TimerBlock;
 
 #define TYPE_ARM_MPTIMER "arm_mptimer"
+#define TYPE_ARM_MPTIMER_WDOG "arm_mptimer_wdog"
 #define ARM_MPTIMER(obj) \
     OBJECT_CHECK(ARMMPTimerState, (obj), TYPE_ARM_MPTIMER)
 
@@ -47,6 +50,7 @@ typedef struct {
     /*< public >*/
 
     uint32_t num_cpu;
+    bool wdog;
     TimerBlock timerblock[ARM_MPTIMER_MAX_CPUS];
     MemoryRegion iomem;
 } ARMMPTimerState;
-- 
1.7.10.4




reply via email to

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