[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
- [Qemu-arm] [PATCH 1/2] arm_mptimer: add watchdog mode support,
Rabin Vincent <=