aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/arm/stellaris.c12
-rw-r--r--hw/timer/stellaris-gptm.c26
-rw-r--r--include/hw/timer/stellaris-gptm.h3
3 files changed, 34 insertions, 7 deletions
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index 8c547f146a..3e7d1dabad 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -1090,9 +1090,15 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
}
for (i = 0; i < 4; i++) {
if (board->dc2 & (0x10000 << i)) {
- dev = sysbus_create_simple(TYPE_STELLARIS_GPTM,
- 0x40030000 + i * 0x1000,
- qdev_get_gpio_in(nvic, timer_irq[i]));
+ SysBusDevice *sbd;
+
+ dev = qdev_new(TYPE_STELLARIS_GPTM);
+ sbd = SYS_BUS_DEVICE(dev);
+ qdev_connect_clock_in(dev, "clk",
+ qdev_get_clock_out(ssys_dev, "SYSCLK"));
+ sysbus_realize_and_unref(sbd, &error_fatal);
+ sysbus_mmio_map(sbd, 0, 0x40030000 + i * 0x1000);
+ sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(nvic, timer_irq[i]));
/* TODO: This is incorrect, but we get away with it because
the ADC output is only ever pulsed. */
qdev_connect_gpio_out(dev, 0, adc);
diff --git a/hw/timer/stellaris-gptm.c b/hw/timer/stellaris-gptm.c
index 7846fe5f84..fd71c79be4 100644
--- a/hw/timer/stellaris-gptm.c
+++ b/hw/timer/stellaris-gptm.c
@@ -10,9 +10,10 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/timer.h"
+#include "qapi/error.h"
#include "migration/vmstate.h"
+#include "hw/qdev-clock.h"
#include "hw/timer/stellaris-gptm.h"
-#include "hw/timer/armv7m_systick.h" /* Needed only for system_clock_scale */
static void gptm_update_irq(gptm_state *s)
{
@@ -39,7 +40,7 @@ static void gptm_reload(gptm_state *s, int n, int reset)
/* 32-bit CountDown. */
uint32_t count;
count = s->load[0] | (s->load[1] << 16);
- tick += (int64_t)count * system_clock_scale;
+ tick += clock_ticks_to_ns(s->clk, count);
} else if (s->config == 1) {
/* 32-bit RTC. 1Hz tick. */
tick += NANOSECONDS_PER_SECOND;
@@ -247,8 +248,8 @@ static const MemoryRegionOps gptm_ops = {
static const VMStateDescription vmstate_stellaris_gptm = {
.name = "stellaris_gptm",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT32(config, gptm_state),
VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
@@ -263,6 +264,7 @@ static const VMStateDescription vmstate_stellaris_gptm = {
VMSTATE_UINT32(rtc, gptm_state),
VMSTATE_INT64_ARRAY(tick, gptm_state, 2),
VMSTATE_TIMER_PTR_ARRAY(timer, gptm_state, 2),
+ VMSTATE_CLOCK(clk, gptm_state),
VMSTATE_END_OF_LIST()
}
};
@@ -281,11 +283,27 @@ static void stellaris_gptm_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
s->opaque[0] = s->opaque[1] = s;
+
+ /*
+ * TODO: in an ideal world we would model the effects of changing
+ * the input clock frequency while the countdown timer is active.
+ * The best way to do this would be to convert the device to use
+ * ptimer instead of hand-rolling its own timer. This would also
+ * make it easy to implement reading the current count from the
+ * TAR and TBR registers.
+ */
+ s->clk = qdev_init_clock_in(dev, "clk", NULL, NULL, 0);
}
static void stellaris_gptm_realize(DeviceState *dev, Error **errp)
{
gptm_state *s = STELLARIS_GPTM(dev);
+
+ if (!clock_has_source(s->clk)) {
+ error_setg(errp, "stellaris-gptm: clk must be connected");
+ return;
+ }
+
s->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[0]);
s->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[1]);
}
diff --git a/include/hw/timer/stellaris-gptm.h b/include/hw/timer/stellaris-gptm.h
index b8fa43c94b..fde1fc6f0c 100644
--- a/include/hw/timer/stellaris-gptm.h
+++ b/include/hw/timer/stellaris-gptm.h
@@ -13,6 +13,7 @@
#include "qom/object.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
+#include "hw/clock.h"
#define TYPE_STELLARIS_GPTM "stellaris-gptm"
OBJECT_DECLARE_SIMPLE_TYPE(gptm_state, STELLARIS_GPTM)
@@ -22,6 +23,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(gptm_state, STELLARIS_GPTM)
* + sysbus MMIO region 0: register bank
* + sysbus IRQ 0: timer interrupt
* + unnamed GPIO output 0: trigger output for the ADC
+ * + Clock input "clk": the 32-bit countdown timer runs at this speed
*/
struct gptm_state {
SysBusDevice parent_obj;
@@ -43,6 +45,7 @@ struct gptm_state {
/* The timers have an alternate output used to trigger the ADC. */
qemu_irq trigger;
qemu_irq irq;
+ Clock *clk;
};
#endif