* [Qemu-devel] [PATCH v8 1/5] vmstate: add VMSTATE_PTIMER_ARRAY
2013-12-04 8:09 [Qemu-devel] [PATCH v8 0/5] add allwinner A10 SoC support liguang
@ 2013-12-04 8:09 ` liguang
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 2/5] hw/timer: add allwinner a10 timer liguang
` (3 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: liguang @ 2013-12-04 8:09 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Peter Crosthwaite, Andreas Färber, liguang
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
---
include/migration/vmstate.h | 4 ++++
savevm.c | 31 +++++++++++++++++++++++++++++++
2 files changed, 35 insertions(+), 0 deletions(-)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 9d09e60..977cf52 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -165,6 +165,7 @@ extern const VMStateInfo vmstate_info_timer;
extern const VMStateInfo vmstate_info_buffer;
extern const VMStateInfo vmstate_info_unused_buffer;
extern const VMStateInfo vmstate_info_bitmap;
+extern const VMStateInfo vmstate_info_ptimer;
#define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)
#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
@@ -613,6 +614,9 @@ extern const VMStateInfo vmstate_info_bitmap;
#define VMSTATE_TIMER_ARRAY(_f, _s, _n) \
VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *)
+#define VMSTATE_PTIMER_ARRAY(_f, _s, _n) \
+ VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_ptimer, ptimer_state *)
+
#define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool)
diff --git a/savevm.c b/savevm.c
index 2f631d4..54dbb33 100644
--- a/savevm.c
+++ b/savevm.c
@@ -30,6 +30,7 @@
#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
#include "qemu/timer.h"
+#include "hw/ptimer.h"
#include "audio/audio.h"
#include "migration/migration.h"
#include "qemu/sockets.h"
@@ -1362,6 +1363,36 @@ const VMStateInfo vmstate_info_timer = {
.put = put_timer,
};
+static int get_ptimer(QEMUFile *f, void *pv, size_t size)
+{
+ ptimer_state *v = pv;
+ uint64_t count;
+
+ count = qemu_get_be64(f);
+ if (count != -1) {
+ ptimer_set_count(v, count);
+ } else {
+ ptimer_stop(v);
+ }
+
+ return 0;
+}
+
+static void put_ptimer(QEMUFile *f, void *pv, size_t size)
+{
+ ptimer_state *v = pv;
+ uint64_t count;
+
+ count = ptimer_get_count(v);
+ qemu_put_be64(f, count);
+}
+
+const VMStateInfo vmstate_info_ptimer = {
+ .name = "ptimer",
+ .get = get_ptimer,
+ .put = put_ptimer,
+};
+
/* uint8_t buffers */
static int get_buffer(QEMUFile *f, void *pv, size_t size)
--
1.7.2.5
^ permalink raw reply related [flat|nested] 10+ messages in thread* [Qemu-devel] [PATCH v8 2/5] hw/timer: add allwinner a10 timer
2013-12-04 8:09 [Qemu-devel] [PATCH v8 0/5] add allwinner A10 SoC support liguang
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 1/5] vmstate: add VMSTATE_PTIMER_ARRAY liguang
@ 2013-12-04 8:09 ` liguang
2013-12-05 1:28 ` Peter Crosthwaite
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 3/5] hw/intc: add allwinner A10 interrupt controller liguang
` (2 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: liguang @ 2013-12-04 8:09 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Peter Crosthwaite, Andreas Färber, liguang
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
---
default-configs/arm-softmmu.mak | 2 +
hw/timer/Makefile.objs | 2 +
hw/timer/allwinner-a10-pit.c | 253 ++++++++++++++++++++++++++++++++++
include/hw/timer/allwinner-a10-pit.h | 57 ++++++++
4 files changed, 314 insertions(+), 0 deletions(-)
create mode 100644 hw/timer/allwinner-a10-pit.c
create mode 100644 include/hw/timer/allwinner-a10-pit.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index a555eef..0029596 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -81,3 +81,5 @@ CONFIG_VERSATILE_I2C=y
CONFIG_SDHCI=y
CONFIG_INTEGRATOR_DEBUG=y
+
+CONFIG_ALLWINNER_A10=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index eca5905..3020388 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -27,3 +27,5 @@ obj-$(CONFIG_SH4) += sh_timer.o
obj-$(CONFIG_TUSB6010) += tusb6010.o
obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
+
+obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10-pit.o
diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c
new file mode 100644
index 0000000..2305813
--- /dev/null
+++ b/hw/timer/allwinner-a10-pit.c
@@ -0,0 +1,253 @@
+/*
+ * Allwinner A10 timer device emulation
+ *
+ * Copyright (C) 2013 Li Guang
+ * Written by Li Guang <lig.fnst@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "hw/timer/allwinner-a10-pit.h"
+
+
+static uint64_t a10_pit_read(void *opaque, hwaddr offset, unsigned size)
+{
+ AwA10PITState *s = AW_A10_PIT(opaque);
+ uint8_t index;
+
+ switch (offset) {
+ case AW_A10_PIT_TIMER_IRQ_EN:
+ return s->irq_enable;
+ case AW_A10_PIT_TIMER_IRQ_ST:
+ return s->irq_status;
+ case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE * 6 + AW_A10_PIT_TIMER_COUNT:
+ index = offset & 0xf0;
+ index >>= 4;
+ index -= 1;
+ switch (offset & 0x0f) {
+ case AW_A10_PIT_TIMER_CONTROL:
+ return s->control[index];
+ case AW_A10_PIT_TIMER_INTERVAL:
+ return s->interval[index];
+ case AW_A10_PIT_TIMER_COUNT:
+ s->count[index] = ptimer_get_count(s->timer[index]);
+ return s->count[index];
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ break;
+ }
+ case AW_A10_PIT_WDOG_CONTROL:
+ break;
+ case AW_A10_PIT_WDOG_MODE:
+ break;
+ case AW_A10_PIT_COUNT_LO:
+ return s->count_lo;
+ case AW_A10_PIT_COUNT_HI:
+ return s->count_hi;
+ case AW_A10_PIT_COUNT_CTL:
+ return s->count_ctl;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ break;
+ }
+
+ return 0;
+}
+
+static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ AwA10PITState *s = AW_A10_PIT(opaque);
+ uint8_t index;
+
+ switch (offset) {
+ case AW_A10_PIT_TIMER_IRQ_EN:
+ s->irq_enable = value;
+ break;
+ case AW_A10_PIT_TIMER_IRQ_ST:
+ s->irq_status &= ~value;
+ break;
+ case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE * 6 + AW_A10_PIT_TIMER_COUNT:
+ index = offset & 0xf0;
+ index >>= 4;
+ index -= 1;
+ switch (offset & 0x0f) {
+ case AW_A10_PIT_TIMER_CONTROL:
+ s->control[index] = value;
+ if (s->control[index] & AW_A10_PIT_TIMER_RELOAD) {
+ ptimer_set_count(s->timer[index], s->interval[index]);
+ }
+ if (s->control[index] & AW_A10_PIT_TIMER_EN) {
+ int oneshot = 0;
+ if (s->control[index] & AW_A10_PIT_TIMER_MODE) {
+ oneshot = 1;
+ }
+ ptimer_run(s->timer[index], oneshot);
+ } else {
+ ptimer_stop(s->timer[index]);
+ }
+ break;
+ case AW_A10_PIT_TIMER_INTERVAL:
+ s->interval[index] = value;
+ ptimer_set_limit(s->timer[index], s->interval[index], 1);
+ break;
+ case AW_A10_PIT_TIMER_COUNT:
+ s->count[index] = value;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ }
+ break;
+ case AW_A10_PIT_WDOG_CONTROL:
+ s->watch_dog_control = value;
+ break;
+ case AW_A10_PIT_WDOG_MODE:
+ s->watch_dog_mode = value;
+ break;
+ case AW_A10_PIT_COUNT_LO:
+ s->count_lo = value;
+ break;
+ case AW_A10_PIT_COUNT_HI:
+ s->count_hi = value;
+ break;
+ case AW_A10_PIT_COUNT_CTL:
+ s->count_ctl = value;
+ if (s->count_ctl & AW_A10_PIT_COUNT_RL_EN) {
+ s->count_lo = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ s->count_hi = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 32;
+ s->count_ctl &= ~AW_A10_PIT_COUNT_RL_EN;
+ }
+ if (s->count_ctl & AW_A10_PIT_COUNT_CLR_EN) {
+ s->count_lo = 0;
+ s->count_hi = 0;
+ s->count_ctl &= ~AW_A10_PIT_COUNT_CLR_EN;
+ }
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ break;
+ }
+}
+
+static const MemoryRegionOps a10_pit_ops = {
+ .read = a10_pit_read,
+ .write = a10_pit_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_a10_pit = {
+ .name = "a10.pit",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(irq_enable, AwA10PITState),
+ VMSTATE_UINT32(irq_status, AwA10PITState),
+ VMSTATE_UINT32_ARRAY(control, AwA10PITState, AW_A10_PIT_TIMER_NR),
+ VMSTATE_UINT32_ARRAY(interval, AwA10PITState, AW_A10_PIT_TIMER_NR),
+ VMSTATE_UINT32_ARRAY(count, AwA10PITState, AW_A10_PIT_TIMER_NR),
+ VMSTATE_UINT32(watch_dog_mode, AwA10PITState),
+ VMSTATE_UINT32(watch_dog_control, AwA10PITState),
+ VMSTATE_UINT32(count_lo, AwA10PITState),
+ VMSTATE_UINT32(count_hi, AwA10PITState),
+ VMSTATE_UINT32(count_ctl, AwA10PITState),
+ VMSTATE_PTIMER_ARRAY(timer, AwA10PITState, AW_A10_PIT_TIMER_NR),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void a10_pit_reset(DeviceState *dev)
+{
+ AwA10PITState *s = AW_A10_PIT(dev);
+ uint8_t i;
+
+ s->irq_enable = 0;
+ s->irq_status = 0;
+ for (i = 0; i < 6; i++) {
+ s->control[i] = AW_A10_PIT_DEFAULT_CLOCK;
+ s->interval[i] = 0;
+ s->count[i] = 0;
+ ptimer_stop(s->timer[i]);
+ }
+ s->watch_dog_mode = 0;
+ s->watch_dog_control = 0;
+ s->count_lo = 0;
+ s->count_hi = 0;
+ s->count_ctl = 0;
+}
+
+static void a10_pit_timer_cb(void *opaque)
+{
+ AwA10PITState *s = AW_A10_PIT(opaque);
+ uint8_t i;
+
+ for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
+ if (s->control[i] & AW_A10_PIT_TIMER_EN) {
+ s->irq_status |= 1 << i;
+ if (s->control[i] & AW_A10_PIT_TIMER_MODE) {
+ ptimer_stop(s->timer[i]);
+ s->control[i] &= ~AW_A10_PIT_TIMER_EN;
+ }
+ qemu_irq_pulse(s->irq[i]);
+ }
+ }
+}
+
+static void a10_pit_realize(DeviceState *dev, Error **errp)
+{
+ AwA10PITState *s = AW_A10_PIT(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ QEMUBH * bh[AW_A10_PIT_TIMER_NR];
+ uint8_t i;
+
+ for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
+ sysbus_init_irq(sbd, &s->irq[i]);
+ }
+ memory_region_init_io(&s->iomem, OBJECT(s), &a10_pit_ops, s,
+ TYPE_AW_A10_PIT, 0x400);
+ sysbus_init_mmio(sbd, &s->iomem);
+
+ for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
+ bh[i] = qemu_bh_new(a10_pit_timer_cb, s);
+ s->timer[i] = ptimer_init(bh[i]);
+ ptimer_set_freq(s->timer[i], 240000);
+ }
+}
+
+static void a10_pit_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = a10_pit_realize;
+ dc->reset = a10_pit_reset;
+ dc->desc = "allwinner a10 timer";
+ dc->vmsd = &vmstate_a10_pit;
+}
+
+static const TypeInfo a10_pit_info = {
+ .name = TYPE_AW_A10_PIT,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AwA10PITState),
+ .class_init = a10_pit_class_init,
+};
+
+static void a10_register_types(void)
+{
+ type_register_static(&a10_pit_info);
+}
+
+type_init(a10_register_types);
diff --git a/include/hw/timer/allwinner-a10-pit.h b/include/hw/timer/allwinner-a10-pit.h
new file mode 100644
index 0000000..329c05c
--- /dev/null
+++ b/include/hw/timer/allwinner-a10-pit.h
@@ -0,0 +1,57 @@
+#ifndef AW_A10_PIT_H
+#define AW_A10_PIT_H
+
+#include "hw/ptimer.h"
+
+#define TYPE_AW_A10_PIT "Allwinner-A10-timer"
+#define AW_A10_PIT(obj) OBJECT_CHECK(AwA10PITState, (obj), TYPE_AW_A10_PIT)
+
+#define AW_A10_PIT_TIMER_NR 6
+#define AW_A10_PIT_TIMER_IRQ 0x1
+#define AW_A10_PIT_WDOG_IRQ 0x100
+
+#define AW_A10_PIT_TIMER_IRQ_EN 0
+#define AW_A10_PIT_TIMER_IRQ_ST 0x4
+
+#define AW_A10_PIT_TIMER_CONTROL 0x0
+#define AW_A10_PIT_TIMER_EN 0x1
+#define AW_A10_PIT_TIMER_RELOAD 0x2
+#define AW_A10_PIT_TIMER_MODE 0x80
+
+#define AW_A10_PIT_TIMER_INTERVAL 0x4
+#define AW_A10_PIT_TIMER_COUNT 0x8
+#define AW_A10_PIT_WDOG_CONTROL 0x90
+#define AW_A10_PIT_WDOG_MODE 0x94
+
+#define AW_A10_PIT_COUNT_CTL 0xa0
+#define AW_A10_PIT_COUNT_RL_EN 0x2
+#define AW_A10_PIT_COUNT_CLR_EN 0x1
+#define AW_A10_PIT_COUNT_LO 0xa4
+#define AW_A10_PIT_COUNT_HI 0xa8
+
+#define AW_A10_PIT_TIMER_BASE 0x10
+
+#define AW_A10_PIT_DEFAULT_CLOCK 0x4
+
+typedef struct AwA10PITState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+ qemu_irq irq[AW_A10_PIT_TIMER_NR];
+ ptimer_state *timer[AW_A10_PIT_TIMER_NR];
+ MemoryRegion iomem;
+
+ uint32_t irq_enable;
+ uint32_t irq_status;
+ uint32_t control[AW_A10_PIT_TIMER_NR];
+ uint32_t interval[AW_A10_PIT_TIMER_NR];
+ uint32_t count[AW_A10_PIT_TIMER_NR];
+ uint32_t watch_dog_mode;
+ uint32_t watch_dog_control;
+ uint32_t count_lo;
+ uint32_t count_hi;
+ uint32_t count_ctl;
+} AwA10PITState;
+
+#endif
+
--
1.7.2.5
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [Qemu-devel] [PATCH v8 2/5] hw/timer: add allwinner a10 timer
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 2/5] hw/timer: add allwinner a10 timer liguang
@ 2013-12-05 1:28 ` Peter Crosthwaite
2013-12-05 1:51 ` Li Guang
0 siblings, 1 reply; 10+ messages in thread
From: Peter Crosthwaite @ 2013-12-05 1:28 UTC (permalink / raw)
To: liguang
Cc: Peter Maydell, qemu-devel@nongnu.org Developers,
Andreas Färber
On Wed, Dec 4, 2013 at 6:09 PM, liguang <lig.fnst@cn.fujitsu.com> wrote:
> Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
> ---
> default-configs/arm-softmmu.mak | 2 +
> hw/timer/Makefile.objs | 2 +
> hw/timer/allwinner-a10-pit.c | 253 ++++++++++++++++++++++++++++++++++
> include/hw/timer/allwinner-a10-pit.h | 57 ++++++++
> 4 files changed, 314 insertions(+), 0 deletions(-)
> create mode 100644 hw/timer/allwinner-a10-pit.c
> create mode 100644 include/hw/timer/allwinner-a10-pit.h
>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index a555eef..0029596 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -81,3 +81,5 @@ CONFIG_VERSATILE_I2C=y
>
> CONFIG_SDHCI=y
> CONFIG_INTEGRATOR_DEBUG=y
> +
> +CONFIG_ALLWINNER_A10=y
> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
> index eca5905..3020388 100644
> --- a/hw/timer/Makefile.objs
> +++ b/hw/timer/Makefile.objs
> @@ -27,3 +27,5 @@ obj-$(CONFIG_SH4) += sh_timer.o
> obj-$(CONFIG_TUSB6010) += tusb6010.o
>
> obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
> +
> +obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10-pit.o
> diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c
> new file mode 100644
> index 0000000..2305813
> --- /dev/null
> +++ b/hw/timer/allwinner-a10-pit.c
> @@ -0,0 +1,253 @@
> +/*
> + * Allwinner A10 timer device emulation
> + *
> + * Copyright (C) 2013 Li Guang
> + * Written by Li Guang <lig.fnst@cn.fujitsu.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> + * for more details.
> + */
> +
> +#include "hw/sysbus.h"
> +#include "sysemu/sysemu.h"
> +#include "hw/timer/allwinner-a10-pit.h"
> +
> +
Not sure of the motivation for extra blank lines.
> +static uint64_t a10_pit_read(void *opaque, hwaddr offset, unsigned size)
> +{
> + AwA10PITState *s = AW_A10_PIT(opaque);
> + uint8_t index;
> +
> + switch (offset) {
> + case AW_A10_PIT_TIMER_IRQ_EN:
> + return s->irq_enable;
> + case AW_A10_PIT_TIMER_IRQ_ST:
> + return s->irq_status;
> + case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE * 6 + AW_A10_PIT_TIMER_COUNT:
It's strange to me that AW_A10_PIT_TIMER_BASE is used as both an
offset and a stride. It's only co-incidence that 0x10 is both the
offset of the first timers' individual registers as well as the diff
between timer register offsets. I think you could just simplify by
putting it all in the header, something like:
#define AW_A10_PIT_TIMER_BASE_END (AW_A10_PIT_TIMER_BASE * 6 + 0x10).
> + index = offset & 0xf0;
> + index >>= 4;
> + index -= 1;
> + switch (offset & 0x0f) {
> + case AW_A10_PIT_TIMER_CONTROL:
> + return s->control[index];
> + case AW_A10_PIT_TIMER_INTERVAL:
> + return s->interval[index];
> + case AW_A10_PIT_TIMER_COUNT:
> + s->count[index] = ptimer_get_count(s->timer[index]);
> + return s->count[index];
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: Bad offset 0x%x\n", __func__, (int)offset);
> + break;
> + }
> + case AW_A10_PIT_WDOG_CONTROL:
> + break;
> + case AW_A10_PIT_WDOG_MODE:
> + break;
> + case AW_A10_PIT_COUNT_LO:
> + return s->count_lo;
> + case AW_A10_PIT_COUNT_HI:
> + return s->count_hi;
> + case AW_A10_PIT_COUNT_CTL:
> + return s->count_ctl;
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: Bad offset 0x%x\n", __func__, (int)offset);
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
> + unsigned size)
> +{
> + AwA10PITState *s = AW_A10_PIT(opaque);
> + uint8_t index;
> +
> + switch (offset) {
> + case AW_A10_PIT_TIMER_IRQ_EN:
> + s->irq_enable = value;
> + break;
> + case AW_A10_PIT_TIMER_IRQ_ST:
> + s->irq_status &= ~value;
> + break;
> + case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE * 6 + AW_A10_PIT_TIMER_COUNT:
> + index = offset & 0xf0;
> + index >>= 4;
> + index -= 1;
> + switch (offset & 0x0f) {
> + case AW_A10_PIT_TIMER_CONTROL:
> + s->control[index] = value;
> + if (s->control[index] & AW_A10_PIT_TIMER_RELOAD) {
> + ptimer_set_count(s->timer[index], s->interval[index]);
> + }
> + if (s->control[index] & AW_A10_PIT_TIMER_EN) {
> + int oneshot = 0;
> + if (s->control[index] & AW_A10_PIT_TIMER_MODE) {
> + oneshot = 1;
> + }
> + ptimer_run(s->timer[index], oneshot);
> + } else {
> + ptimer_stop(s->timer[index]);
> + }
> + break;
> + case AW_A10_PIT_TIMER_INTERVAL:
> + s->interval[index] = value;
> + ptimer_set_limit(s->timer[index], s->interval[index], 1);
> + break;
> + case AW_A10_PIT_TIMER_COUNT:
> + s->count[index] = value;
> + break;
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: Bad offset 0x%x\n", __func__, (int)offset);
> + }
> + break;
> + case AW_A10_PIT_WDOG_CONTROL:
> + s->watch_dog_control = value;
> + break;
> + case AW_A10_PIT_WDOG_MODE:
> + s->watch_dog_mode = value;
> + break;
> + case AW_A10_PIT_COUNT_LO:
> + s->count_lo = value;
> + break;
> + case AW_A10_PIT_COUNT_HI:
> + s->count_hi = value;
> + break;
> + case AW_A10_PIT_COUNT_CTL:
> + s->count_ctl = value;
> + if (s->count_ctl & AW_A10_PIT_COUNT_RL_EN) {
> + s->count_lo = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> + s->count_hi = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 32;
Sorry for not spotting this one earlier (i'm going full line by line
now), but you should just do the one call to qemu_clock_get_ns
(capture to local variable).
Whats probably cleanest is to implement s->count as uint64_t and just
use deposit64/extract64 in MMIO read/write fns. Saves about 5 LOC and
is a little more self documenting.
You counter is also implicitly 1GHz right? that's probably worth a comment.
Regards,
Peter
PS. You are still re-spinning very fast. Can I suggest 24hr as a
minimum wait to give other reviewers a chance? That gives all the
global timezones a chance to participate. I did a high level review of
one of your new patches last night at home, but I haven't had a chance
to look at this properly till this morning (at work) yet you have
already respun on me. Persoanally, I'm going for 48h respins atm.
> + s->count_ctl &= ~AW_A10_PIT_COUNT_RL_EN;
> + }
> + if (s->count_ctl & AW_A10_PIT_COUNT_CLR_EN) {
> + s->count_lo = 0;
> + s->count_hi = 0;
> + s->count_ctl &= ~AW_A10_PIT_COUNT_CLR_EN;
> + }
> + break;
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: Bad offset 0x%x\n", __func__, (int)offset);
> + break;
> + }
> +}
> +
> +static const MemoryRegionOps a10_pit_ops = {
> + .read = a10_pit_read,
> + .write = a10_pit_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static const VMStateDescription vmstate_a10_pit = {
> + .name = "a10.pit",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .minimum_version_id_old = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT32(irq_enable, AwA10PITState),
> + VMSTATE_UINT32(irq_status, AwA10PITState),
> + VMSTATE_UINT32_ARRAY(control, AwA10PITState, AW_A10_PIT_TIMER_NR),
> + VMSTATE_UINT32_ARRAY(interval, AwA10PITState, AW_A10_PIT_TIMER_NR),
> + VMSTATE_UINT32_ARRAY(count, AwA10PITState, AW_A10_PIT_TIMER_NR),
> + VMSTATE_UINT32(watch_dog_mode, AwA10PITState),
> + VMSTATE_UINT32(watch_dog_control, AwA10PITState),
> + VMSTATE_UINT32(count_lo, AwA10PITState),
> + VMSTATE_UINT32(count_hi, AwA10PITState),
> + VMSTATE_UINT32(count_ctl, AwA10PITState),
> + VMSTATE_PTIMER_ARRAY(timer, AwA10PITState, AW_A10_PIT_TIMER_NR),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static void a10_pit_reset(DeviceState *dev)
> +{
> + AwA10PITState *s = AW_A10_PIT(dev);
> + uint8_t i;
> +
> + s->irq_enable = 0;
> + s->irq_status = 0;
> + for (i = 0; i < 6; i++) {
> + s->control[i] = AW_A10_PIT_DEFAULT_CLOCK;
> + s->interval[i] = 0;
> + s->count[i] = 0;
> + ptimer_stop(s->timer[i]);
> + }
> + s->watch_dog_mode = 0;
> + s->watch_dog_control = 0;
> + s->count_lo = 0;
> + s->count_hi = 0;
> + s->count_ctl = 0;
> +}
> +
> +static void a10_pit_timer_cb(void *opaque)
> +{
> + AwA10PITState *s = AW_A10_PIT(opaque);
> + uint8_t i;
> +
> + for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
> + if (s->control[i] & AW_A10_PIT_TIMER_EN) {
> + s->irq_status |= 1 << i;
> + if (s->control[i] & AW_A10_PIT_TIMER_MODE) {
> + ptimer_stop(s->timer[i]);
> + s->control[i] &= ~AW_A10_PIT_TIMER_EN;
> + }
> + qemu_irq_pulse(s->irq[i]);
> + }
> + }
> +}
> +
> +static void a10_pit_realize(DeviceState *dev, Error **errp)
> +{
> + AwA10PITState *s = AW_A10_PIT(dev);
> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> + QEMUBH * bh[AW_A10_PIT_TIMER_NR];
> + uint8_t i;
> +
> + for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
> + sysbus_init_irq(sbd, &s->irq[i]);
> + }
> + memory_region_init_io(&s->iomem, OBJECT(s), &a10_pit_ops, s,
> + TYPE_AW_A10_PIT, 0x400);
> + sysbus_init_mmio(sbd, &s->iomem);
> +
> + for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
> + bh[i] = qemu_bh_new(a10_pit_timer_cb, s);
> + s->timer[i] = ptimer_init(bh[i]);
> + ptimer_set_freq(s->timer[i], 240000);
> + }
> +}
> +
> +static void a10_pit_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->realize = a10_pit_realize;
> + dc->reset = a10_pit_reset;
> + dc->desc = "allwinner a10 timer";
> + dc->vmsd = &vmstate_a10_pit;
> +}
> +
> +static const TypeInfo a10_pit_info = {
> + .name = TYPE_AW_A10_PIT,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(AwA10PITState),
> + .class_init = a10_pit_class_init,
> +};
> +
> +static void a10_register_types(void)
> +{
> + type_register_static(&a10_pit_info);
> +}
> +
> +type_init(a10_register_types);
> diff --git a/include/hw/timer/allwinner-a10-pit.h b/include/hw/timer/allwinner-a10-pit.h
> new file mode 100644
> index 0000000..329c05c
> --- /dev/null
> +++ b/include/hw/timer/allwinner-a10-pit.h
> @@ -0,0 +1,57 @@
> +#ifndef AW_A10_PIT_H
> +#define AW_A10_PIT_H
> +
> +#include "hw/ptimer.h"
> +
> +#define TYPE_AW_A10_PIT "Allwinner-A10-timer"
> +#define AW_A10_PIT(obj) OBJECT_CHECK(AwA10PITState, (obj), TYPE_AW_A10_PIT)
> +
> +#define AW_A10_PIT_TIMER_NR 6
> +#define AW_A10_PIT_TIMER_IRQ 0x1
> +#define AW_A10_PIT_WDOG_IRQ 0x100
> +
> +#define AW_A10_PIT_TIMER_IRQ_EN 0
> +#define AW_A10_PIT_TIMER_IRQ_ST 0x4
> +
> +#define AW_A10_PIT_TIMER_CONTROL 0x0
> +#define AW_A10_PIT_TIMER_EN 0x1
> +#define AW_A10_PIT_TIMER_RELOAD 0x2
> +#define AW_A10_PIT_TIMER_MODE 0x80
> +
> +#define AW_A10_PIT_TIMER_INTERVAL 0x4
> +#define AW_A10_PIT_TIMER_COUNT 0x8
> +#define AW_A10_PIT_WDOG_CONTROL 0x90
> +#define AW_A10_PIT_WDOG_MODE 0x94
> +
> +#define AW_A10_PIT_COUNT_CTL 0xa0
> +#define AW_A10_PIT_COUNT_RL_EN 0x2
> +#define AW_A10_PIT_COUNT_CLR_EN 0x1
> +#define AW_A10_PIT_COUNT_LO 0xa4
> +#define AW_A10_PIT_COUNT_HI 0xa8
> +
> +#define AW_A10_PIT_TIMER_BASE 0x10
> +
> +#define AW_A10_PIT_DEFAULT_CLOCK 0x4
> +
> +typedef struct AwA10PITState {
> + /*< private >*/
> + SysBusDevice parent_obj;
> + /*< public >*/
> + qemu_irq irq[AW_A10_PIT_TIMER_NR];
> + ptimer_state *timer[AW_A10_PIT_TIMER_NR];
> + MemoryRegion iomem;
> +
> + uint32_t irq_enable;
> + uint32_t irq_status;
> + uint32_t control[AW_A10_PIT_TIMER_NR];
> + uint32_t interval[AW_A10_PIT_TIMER_NR];
> + uint32_t count[AW_A10_PIT_TIMER_NR];
> + uint32_t watch_dog_mode;
> + uint32_t watch_dog_control;
> + uint32_t count_lo;
> + uint32_t count_hi;
> + uint32_t count_ctl;
> +} AwA10PITState;
> +
> +#endif
> +
> --
> 1.7.2.5
>
>
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [Qemu-devel] [PATCH v8 2/5] hw/timer: add allwinner a10 timer
2013-12-05 1:28 ` Peter Crosthwaite
@ 2013-12-05 1:51 ` Li Guang
0 siblings, 0 replies; 10+ messages in thread
From: Li Guang @ 2013-12-05 1:51 UTC (permalink / raw)
To: Peter Crosthwaite
Cc: Peter Maydell, qemu-devel@nongnu.org Developers,
Andreas Färber
Peter Crosthwaite wrote:
> On Wed, Dec 4, 2013 at 6:09 PM, liguang<lig.fnst@cn.fujitsu.com> wrote:
>
>> Signed-off-by: liguang<lig.fnst@cn.fujitsu.com>
>> ---
>> default-configs/arm-softmmu.mak | 2 +
>> hw/timer/Makefile.objs | 2 +
>> hw/timer/allwinner-a10-pit.c | 253 ++++++++++++++++++++++++++++++++++
>> include/hw/timer/allwinner-a10-pit.h | 57 ++++++++
>> 4 files changed, 314 insertions(+), 0 deletions(-)
>> create mode 100644 hw/timer/allwinner-a10-pit.c
>> create mode 100644 include/hw/timer/allwinner-a10-pit.h
>>
>> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
>> index a555eef..0029596 100644
>> --- a/default-configs/arm-softmmu.mak
>> +++ b/default-configs/arm-softmmu.mak
>> @@ -81,3 +81,5 @@ CONFIG_VERSATILE_I2C=y
>>
>> CONFIG_SDHCI=y
>> CONFIG_INTEGRATOR_DEBUG=y
>> +
>> +CONFIG_ALLWINNER_A10=y
>> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
>> index eca5905..3020388 100644
>> --- a/hw/timer/Makefile.objs
>> +++ b/hw/timer/Makefile.objs
>> @@ -27,3 +27,5 @@ obj-$(CONFIG_SH4) += sh_timer.o
>> obj-$(CONFIG_TUSB6010) += tusb6010.o
>>
>> obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
>> +
>> +obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10-pit.o
>> diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c
>> new file mode 100644
>> index 0000000..2305813
>> --- /dev/null
>> +++ b/hw/timer/allwinner-a10-pit.c
>> @@ -0,0 +1,253 @@
>> +/*
>> + * Allwinner A10 timer device emulation
>> + *
>> + * Copyright (C) 2013 Li Guang
>> + * Written by Li Guang<lig.fnst@cn.fujitsu.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License as published by the
>> + * Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
>> + * for more details.
>> + */
>> +
>> +#include "hw/sysbus.h"
>> +#include "sysemu/sysemu.h"
>> +#include "hw/timer/allwinner-a10-pit.h"
>> +
>> +
>>
> Not sure of the motivation for extra blank lines.
>
>
can strip
>> +static uint64_t a10_pit_read(void *opaque, hwaddr offset, unsigned size)
>> +{
>> + AwA10PITState *s = AW_A10_PIT(opaque);
>> + uint8_t index;
>> +
>> + switch (offset) {
>> + case AW_A10_PIT_TIMER_IRQ_EN:
>> + return s->irq_enable;
>> + case AW_A10_PIT_TIMER_IRQ_ST:
>> + return s->irq_status;
>> + case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE * 6 + AW_A10_PIT_TIMER_COUNT:
>>
> It's strange to me that AW_A10_PIT_TIMER_BASE is used as both an
> offset and a stride. It's only co-incidence that 0x10 is both the
> offset of the first timers' individual registers as well as the diff
> between timer register offsets. I think you could just simplify by
> putting it all in the header, something like:
>
> #define AW_A10_PIT_TIMER_BASE_END (AW_A10_PIT_TIMER_BASE * 6 + 0x10).
>
>
good suggestion!
>> + index = offset& 0xf0;
>> + index>>= 4;
>> + index -= 1;
>> + switch (offset& 0x0f) {
>> + case AW_A10_PIT_TIMER_CONTROL:
>> + return s->control[index];
>> + case AW_A10_PIT_TIMER_INTERVAL:
>> + return s->interval[index];
>> + case AW_A10_PIT_TIMER_COUNT:
>> + s->count[index] = ptimer_get_count(s->timer[index]);
>> + return s->count[index];
>> + default:
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "%s: Bad offset 0x%x\n", __func__, (int)offset);
>> + break;
>> + }
>> + case AW_A10_PIT_WDOG_CONTROL:
>> + break;
>> + case AW_A10_PIT_WDOG_MODE:
>> + break;
>> + case AW_A10_PIT_COUNT_LO:
>> + return s->count_lo;
>> + case AW_A10_PIT_COUNT_HI:
>> + return s->count_hi;
>> + case AW_A10_PIT_COUNT_CTL:
>> + return s->count_ctl;
>> + default:
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "%s: Bad offset 0x%x\n", __func__, (int)offset);
>> + break;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
>> + unsigned size)
>> +{
>> + AwA10PITState *s = AW_A10_PIT(opaque);
>> + uint8_t index;
>> +
>> + switch (offset) {
>> + case AW_A10_PIT_TIMER_IRQ_EN:
>> + s->irq_enable = value;
>> + break;
>> + case AW_A10_PIT_TIMER_IRQ_ST:
>> + s->irq_status&= ~value;
>> + break;
>> + case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE * 6 + AW_A10_PIT_TIMER_COUNT:
>> + index = offset& 0xf0;
>> + index>>= 4;
>> + index -= 1;
>> + switch (offset& 0x0f) {
>> + case AW_A10_PIT_TIMER_CONTROL:
>> + s->control[index] = value;
>> + if (s->control[index]& AW_A10_PIT_TIMER_RELOAD) {
>> + ptimer_set_count(s->timer[index], s->interval[index]);
>> + }
>> + if (s->control[index]& AW_A10_PIT_TIMER_EN) {
>> + int oneshot = 0;
>> + if (s->control[index]& AW_A10_PIT_TIMER_MODE) {
>> + oneshot = 1;
>> + }
>> + ptimer_run(s->timer[index], oneshot);
>> + } else {
>> + ptimer_stop(s->timer[index]);
>> + }
>> + break;
>> + case AW_A10_PIT_TIMER_INTERVAL:
>> + s->interval[index] = value;
>> + ptimer_set_limit(s->timer[index], s->interval[index], 1);
>> + break;
>> + case AW_A10_PIT_TIMER_COUNT:
>> + s->count[index] = value;
>> + break;
>> + default:
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "%s: Bad offset 0x%x\n", __func__, (int)offset);
>> + }
>> + break;
>> + case AW_A10_PIT_WDOG_CONTROL:
>> + s->watch_dog_control = value;
>> + break;
>> + case AW_A10_PIT_WDOG_MODE:
>> + s->watch_dog_mode = value;
>> + break;
>> + case AW_A10_PIT_COUNT_LO:
>> + s->count_lo = value;
>> + break;
>> + case AW_A10_PIT_COUNT_HI:
>> + s->count_hi = value;
>> + break;
>> + case AW_A10_PIT_COUNT_CTL:
>> + s->count_ctl = value;
>> + if (s->count_ctl& AW_A10_PIT_COUNT_RL_EN) {
>> + s->count_lo = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> + s->count_hi = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)>> 32;
>>
> Sorry for not spotting this one earlier (i'm going full line by line
> now), but you should just do the one call to qemu_clock_get_ns
> (capture to local variable).
>
>
OK
> Whats probably cleanest is to implement s->count as uint64_t and just
> use deposit64/extract64 in MMIO read/write fns. Saves about 5 LOC and
> is a little more self documenting.
>
> You counter is also implicitly 1GHz right? that's probably worth a comment.
>
>
currently it is fixed.
> Regards,
> Peter
>
> PS. You are still re-spinning very fast. Can I suggest 24hr as a
> minimum wait to give other reviewers a chance? That gives all the
> global timezones a chance to participate. I did a high level review of
> one of your new patches last night at home, but I haven't had a chance
> to look at this properly till this morning (at work) yet you have
> already respun on me. Persoanally, I'm going for 48h respins atm.
>
>
OK.
Thanks!
Li Guang
>> + s->count_ctl&= ~AW_A10_PIT_COUNT_RL_EN;
>> + }
>> + if (s->count_ctl& AW_A10_PIT_COUNT_CLR_EN) {
>> + s->count_lo = 0;
>> + s->count_hi = 0;
>> + s->count_ctl&= ~AW_A10_PIT_COUNT_CLR_EN;
>> + }
>> + break;
>> + default:
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "%s: Bad offset 0x%x\n", __func__, (int)offset);
>> + break;
>> + }
>> +}
>> +
>> +static const MemoryRegionOps a10_pit_ops = {
>> + .read = a10_pit_read,
>> + .write = a10_pit_write,
>> + .endianness = DEVICE_NATIVE_ENDIAN,
>> +};
>> +
>> +static const VMStateDescription vmstate_a10_pit = {
>> + .name = "a10.pit",
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .minimum_version_id_old = 1,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_UINT32(irq_enable, AwA10PITState),
>> + VMSTATE_UINT32(irq_status, AwA10PITState),
>> + VMSTATE_UINT32_ARRAY(control, AwA10PITState, AW_A10_PIT_TIMER_NR),
>> + VMSTATE_UINT32_ARRAY(interval, AwA10PITState, AW_A10_PIT_TIMER_NR),
>> + VMSTATE_UINT32_ARRAY(count, AwA10PITState, AW_A10_PIT_TIMER_NR),
>> + VMSTATE_UINT32(watch_dog_mode, AwA10PITState),
>> + VMSTATE_UINT32(watch_dog_control, AwA10PITState),
>> + VMSTATE_UINT32(count_lo, AwA10PITState),
>> + VMSTATE_UINT32(count_hi, AwA10PITState),
>> + VMSTATE_UINT32(count_ctl, AwA10PITState),
>> + VMSTATE_PTIMER_ARRAY(timer, AwA10PITState, AW_A10_PIT_TIMER_NR),
>> + VMSTATE_END_OF_LIST()
>> + }
>> +};
>> +
>> +static void a10_pit_reset(DeviceState *dev)
>> +{
>> + AwA10PITState *s = AW_A10_PIT(dev);
>> + uint8_t i;
>> +
>> + s->irq_enable = 0;
>> + s->irq_status = 0;
>> + for (i = 0; i< 6; i++) {
>> + s->control[i] = AW_A10_PIT_DEFAULT_CLOCK;
>> + s->interval[i] = 0;
>> + s->count[i] = 0;
>> + ptimer_stop(s->timer[i]);
>> + }
>> + s->watch_dog_mode = 0;
>> + s->watch_dog_control = 0;
>> + s->count_lo = 0;
>> + s->count_hi = 0;
>> + s->count_ctl = 0;
>> +}
>> +
>> +static void a10_pit_timer_cb(void *opaque)
>> +{
>> + AwA10PITState *s = AW_A10_PIT(opaque);
>> + uint8_t i;
>> +
>> + for (i = 0; i< AW_A10_PIT_TIMER_NR; i++) {
>> + if (s->control[i]& AW_A10_PIT_TIMER_EN) {
>> + s->irq_status |= 1<< i;
>> + if (s->control[i]& AW_A10_PIT_TIMER_MODE) {
>> + ptimer_stop(s->timer[i]);
>> + s->control[i]&= ~AW_A10_PIT_TIMER_EN;
>> + }
>> + qemu_irq_pulse(s->irq[i]);
>> + }
>> + }
>> +}
>> +
>> +static void a10_pit_realize(DeviceState *dev, Error **errp)
>> +{
>> + AwA10PITState *s = AW_A10_PIT(dev);
>> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>> + QEMUBH * bh[AW_A10_PIT_TIMER_NR];
>> + uint8_t i;
>> +
>> + for (i = 0; i< AW_A10_PIT_TIMER_NR; i++) {
>> + sysbus_init_irq(sbd,&s->irq[i]);
>> + }
>> + memory_region_init_io(&s->iomem, OBJECT(s),&a10_pit_ops, s,
>> + TYPE_AW_A10_PIT, 0x400);
>> + sysbus_init_mmio(sbd,&s->iomem);
>> +
>> + for (i = 0; i< AW_A10_PIT_TIMER_NR; i++) {
>> + bh[i] = qemu_bh_new(a10_pit_timer_cb, s);
>> + s->timer[i] = ptimer_init(bh[i]);
>> + ptimer_set_freq(s->timer[i], 240000);
>> + }
>> +}
>> +
>> +static void a10_pit_class_init(ObjectClass *klass, void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> + dc->realize = a10_pit_realize;
>> + dc->reset = a10_pit_reset;
>> + dc->desc = "allwinner a10 timer";
>> + dc->vmsd =&vmstate_a10_pit;
>> +}
>> +
>> +static const TypeInfo a10_pit_info = {
>> + .name = TYPE_AW_A10_PIT,
>> + .parent = TYPE_SYS_BUS_DEVICE,
>> + .instance_size = sizeof(AwA10PITState),
>> + .class_init = a10_pit_class_init,
>> +};
>> +
>> +static void a10_register_types(void)
>> +{
>> + type_register_static(&a10_pit_info);
>> +}
>> +
>> +type_init(a10_register_types);
>> diff --git a/include/hw/timer/allwinner-a10-pit.h b/include/hw/timer/allwinner-a10-pit.h
>> new file mode 100644
>> index 0000000..329c05c
>> --- /dev/null
>> +++ b/include/hw/timer/allwinner-a10-pit.h
>> @@ -0,0 +1,57 @@
>> +#ifndef AW_A10_PIT_H
>> +#define AW_A10_PIT_H
>> +
>> +#include "hw/ptimer.h"
>> +
>> +#define TYPE_AW_A10_PIT "Allwinner-A10-timer"
>> +#define AW_A10_PIT(obj) OBJECT_CHECK(AwA10PITState, (obj), TYPE_AW_A10_PIT)
>> +
>> +#define AW_A10_PIT_TIMER_NR 6
>> +#define AW_A10_PIT_TIMER_IRQ 0x1
>> +#define AW_A10_PIT_WDOG_IRQ 0x100
>> +
>> +#define AW_A10_PIT_TIMER_IRQ_EN 0
>> +#define AW_A10_PIT_TIMER_IRQ_ST 0x4
>> +
>> +#define AW_A10_PIT_TIMER_CONTROL 0x0
>> +#define AW_A10_PIT_TIMER_EN 0x1
>> +#define AW_A10_PIT_TIMER_RELOAD 0x2
>> +#define AW_A10_PIT_TIMER_MODE 0x80
>> +
>> +#define AW_A10_PIT_TIMER_INTERVAL 0x4
>> +#define AW_A10_PIT_TIMER_COUNT 0x8
>> +#define AW_A10_PIT_WDOG_CONTROL 0x90
>> +#define AW_A10_PIT_WDOG_MODE 0x94
>> +
>> +#define AW_A10_PIT_COUNT_CTL 0xa0
>> +#define AW_A10_PIT_COUNT_RL_EN 0x2
>> +#define AW_A10_PIT_COUNT_CLR_EN 0x1
>> +#define AW_A10_PIT_COUNT_LO 0xa4
>> +#define AW_A10_PIT_COUNT_HI 0xa8
>> +
>> +#define AW_A10_PIT_TIMER_BASE 0x10
>> +
>> +#define AW_A10_PIT_DEFAULT_CLOCK 0x4
>> +
>> +typedef struct AwA10PITState {
>> + /*< private>*/
>> + SysBusDevice parent_obj;
>> + /*< public>*/
>> + qemu_irq irq[AW_A10_PIT_TIMER_NR];
>> + ptimer_state *timer[AW_A10_PIT_TIMER_NR];
>> + MemoryRegion iomem;
>> +
>> + uint32_t irq_enable;
>> + uint32_t irq_status;
>> + uint32_t control[AW_A10_PIT_TIMER_NR];
>> + uint32_t interval[AW_A10_PIT_TIMER_NR];
>> + uint32_t count[AW_A10_PIT_TIMER_NR];
>> + uint32_t watch_dog_mode;
>> + uint32_t watch_dog_control;
>> + uint32_t count_lo;
>> + uint32_t count_hi;
>> + uint32_t count_ctl;
>> +} AwA10PITState;
>> +
>> +#endif
>> +
>> --
>> 1.7.2.5
>>
>>
>>
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH v8 3/5] hw/intc: add allwinner A10 interrupt controller
2013-12-04 8:09 [Qemu-devel] [PATCH v8 0/5] add allwinner A10 SoC support liguang
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 1/5] vmstate: add VMSTATE_PTIMER_ARRAY liguang
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 2/5] hw/timer: add allwinner a10 timer liguang
@ 2013-12-04 8:09 ` liguang
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 4/5] hw/arm: add allwinner a10 SoC support liguang
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 5/5] hw/arm: add cubieboard support liguang
4 siblings, 0 replies; 10+ messages in thread
From: liguang @ 2013-12-04 8:09 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Peter Crosthwaite, Andreas Färber, liguang
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
---
hw/intc/Makefile.objs | 1 +
hw/intc/allwinner-a10-pic.c | 218 +++++++++++++++++++++++++++++++++++
include/hw/intc/allwinner-a10-pic.h | 40 +++++++
3 files changed, 259 insertions(+), 0 deletions(-)
create mode 100644 hw/intc/allwinner-a10-pic.c
create mode 100644 include/hw/intc/allwinner-a10-pic.h
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 47ac442..ec977c4 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -24,3 +24,4 @@ obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o
obj-$(CONFIG_SH4) += sh_intc.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
+obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10-pic.o
diff --git a/hw/intc/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c
new file mode 100644
index 0000000..fdc9e4e
--- /dev/null
+++ b/hw/intc/allwinner-a10-pic.c
@@ -0,0 +1,218 @@
+/*
+ * Allwinner A10 interrupt controller device emulation
+ *
+ * Copyright (C) 2013 Li Guang
+ * Written by Li Guang <lig.fnst@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "sysemu/sysemu.h"
+#include "hw/intc/allwinner-a10-pic.h"
+
+
+static void aw_a10_pic_update(AwA10PICState *s)
+{
+ uint8_t i, j;
+ bool irq = false, fiq = false;
+
+ for (i = 0, j = 0; i < AW_A10_PIC_REG_NUM; i++) {
+ if (s->irq_pending[i] == 0 && s->fiq_pending[i] == 0) {
+ continue;
+ }
+ for (j = 0; j < 32; j++) {
+ if (test_bit(j, (void *)&s->mask[i])) {
+ continue;
+ }
+ if (test_bit(j, (void *)&s->irq_pending[i])) {
+ irq = true;
+ }
+ if (test_bit(j, (void *)&s->fiq_pending[i]) &&
+ test_bit(j, (void *)&s->select[i])) {
+ fiq = true;
+ }
+ if (irq && fiq) {
+ goto out;
+ }
+ }
+ }
+
+out:
+ qemu_set_irq(s->parent_irq, irq);
+ qemu_set_irq(s->parent_fiq, fiq);
+}
+
+static void aw_a10_pic_set_irq(void *opaque, int irq, int level)
+{
+ AwA10PICState *s = opaque;
+
+ if (level) {
+ set_bit(irq%32, (void *)&s->irq_pending[irq/32]);
+ }
+ aw_a10_pic_update(s);
+}
+
+static uint64_t aw_a10_pic_read(void *opaque, hwaddr offset, unsigned size)
+{
+ AwA10PICState *s = opaque;
+ uint8_t index = (offset & 0xc)/4;
+
+ switch (offset) {
+ case AW_A10_PIC_VECTOR:
+ return s->vector;
+ case AW_A10_PIC_BASE_ADDR:
+ return s->base_addr;
+ case AW_A10_PIC_PROTECT:
+ return s->protect;
+ case AW_A10_PIC_NMI:
+ return s->nmi;
+ case AW_A10_PIC_IRQ_PENDING ... AW_A10_PIC_IRQ_PENDING + 8:
+ return s->irq_pending[index];
+ case AW_A10_PIC_FIQ_PENDING ... AW_A10_PIC_FIQ_PENDING + 8:
+ return s->fiq_pending[index];
+ case AW_A10_PIC_SELECT ... AW_A10_PIC_SELECT + 8:
+ return s->select[index];
+ case AW_A10_PIC_ENABLE ... AW_A10_PIC_ENABLE + 8:
+ return s->enable[index];
+ case AW_A10_PIC_MASK ... AW_A10_PIC_MASK + 8:
+ return s->mask[index];
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ break;
+ }
+
+ return 0;
+}
+
+static void aw_a10_pic_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ AwA10PICState *s = opaque;
+ uint8_t index = (offset & 0xc)/4;
+
+ switch (offset) {
+ case AW_A10_PIC_VECTOR:
+ s->vector = value & ~0x3;
+ break;
+ case AW_A10_PIC_BASE_ADDR:
+ s->base_addr = value & ~0x3;
+ case AW_A10_PIC_PROTECT:
+ s->protect = value;
+ break;
+ case AW_A10_PIC_NMI:
+ s->nmi = value;
+ break;
+ case AW_A10_PIC_IRQ_PENDING ... AW_A10_PIC_IRQ_PENDING + 8:
+ s->irq_pending[index] &= ~value;
+ break;
+ case AW_A10_PIC_FIQ_PENDING ... AW_A10_PIC_FIQ_PENDING + 8:
+ s->fiq_pending[index] &= ~value;
+ break;
+ case AW_A10_PIC_SELECT ... AW_A10_PIC_SELECT + 8:
+ s->select[index] = value;
+ break;
+ case AW_A10_PIC_ENABLE ... AW_A10_PIC_ENABLE + 8:
+ s->enable[index] = value;
+ break;
+ case AW_A10_PIC_MASK ... AW_A10_PIC_MASK + 8:
+ s->mask[index] = value;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ break;
+ }
+
+ aw_a10_pic_update(s);
+}
+
+static const MemoryRegionOps aw_a10_pic_ops = {
+ .read = aw_a10_pic_read,
+ .write = aw_a10_pic_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_aw_a10_pic = {
+ .name = "a10.pic",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(vector, AwA10PICState),
+ VMSTATE_UINT32(base_addr, AwA10PICState),
+ VMSTATE_UINT32(protect, AwA10PICState),
+ VMSTATE_UINT32(nmi, AwA10PICState),
+ VMSTATE_UINT32_ARRAY(irq_pending, AwA10PICState, AW_A10_PIC_REG_NUM),
+ VMSTATE_UINT32_ARRAY(fiq_pending, AwA10PICState, AW_A10_PIC_REG_NUM),
+ VMSTATE_UINT32_ARRAY(enable, AwA10PICState, AW_A10_PIC_REG_NUM),
+ VMSTATE_UINT32_ARRAY(select, AwA10PICState, AW_A10_PIC_REG_NUM),
+ VMSTATE_UINT32_ARRAY(mask, AwA10PICState, AW_A10_PIC_REG_NUM),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void aw_a10_pic_realize(DeviceState *ds, Error **errp)
+{
+ AwA10PICState *s = AW_A10_PIC(ds);
+ SysBusDevice *dev = SYS_BUS_DEVICE(ds);
+
+ qdev_init_gpio_in(DEVICE(dev), aw_a10_pic_set_irq, AW_A10_PIC_INT_NR);
+ sysbus_init_irq(dev, &s->parent_irq);
+ sysbus_init_irq(dev, &s->parent_fiq);
+ memory_region_init_io(&s->iomem, OBJECT(s), &aw_a10_pic_ops, s,
+ "a10-pic", 0x400);
+ sysbus_init_mmio(dev, &s->iomem);
+}
+
+static void aw_a10_pic_reset(DeviceState *d)
+{
+ AwA10PICState *s = AW_A10_PIC(d);
+ uint8_t i;
+
+ s->base_addr = 0;
+ s->protect = 0;
+ s->nmi = 0;
+ s->vector = 0;
+ for (i = 0; i < AW_A10_PIC_REG_NUM; i++) {
+ s->irq_pending[i] = 0;
+ s->fiq_pending[i] = 0;
+ s->select[i] = 0;
+ s->enable[i] = 0;
+ s->mask[i] = 0;
+ }
+}
+
+static void aw_a10_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = aw_a10_pic_realize;
+ dc->reset = aw_a10_pic_reset;
+ dc->desc = "A10 pic";
+ dc->vmsd = &vmstate_aw_a10_pic;
+ }
+
+static const TypeInfo aw_a10_pic_info = {
+ .name = TYPE_AW_A10_PIC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AwA10PICState),
+ .class_init = aw_a10_pic_class_init,
+};
+
+static void aw_a10_register_types(void)
+{
+ type_register_static(&aw_a10_pic_info);
+}
+
+type_init(aw_a10_register_types);
diff --git a/include/hw/intc/allwinner-a10-pic.h b/include/hw/intc/allwinner-a10-pic.h
new file mode 100644
index 0000000..b5d1c05
--- /dev/null
+++ b/include/hw/intc/allwinner-a10-pic.h
@@ -0,0 +1,40 @@
+#ifndef AW_A10_PIC_H
+#define AW_A10_PIC_H
+
+#define TYPE_AW_A10_PIC "a10-pic"
+#define AW_A10_PIC(obj) OBJECT_CHECK(AwA10PICState, (obj), TYPE_AW_A10_PIC)
+
+#define AW_A10_PIC_VECTOR 0
+#define AW_A10_PIC_BASE_ADDR 4
+#define AW_A10_PIC_PROTECT 8
+#define AW_A10_PIC_NMI 0xc
+#define AW_A10_PIC_IRQ_PENDING 0x10
+#define AW_A10_PIC_FIQ_PENDING 0x20
+#define AW_A10_PIC_SELECT 0x30
+#define AW_A10_PIC_ENABLE 0x40
+#define AW_A10_PIC_MASK 0x50
+
+#define AW_A10_PIC_INT_NR 95
+#define AW_A10_PIC_REG_NUM DIV_ROUND_UP(AW_A10_PIC_INT_NR, 32)
+
+typedef struct AwA10PICState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+ MemoryRegion iomem;
+ qemu_irq parent_fiq;
+ qemu_irq parent_irq;
+
+ uint32_t vector;
+ uint32_t base_addr;
+ uint32_t protect;
+ uint32_t nmi;
+ uint32_t irq_pending[AW_A10_PIC_REG_NUM];
+ uint32_t fiq_pending[AW_A10_PIC_REG_NUM];
+ uint32_t select[AW_A10_PIC_REG_NUM];
+ uint32_t enable[AW_A10_PIC_REG_NUM];
+ uint32_t mask[AW_A10_PIC_REG_NUM];
+ /*priority setting here*/
+} AwA10PICState;
+
+#endif
--
1.7.2.5
^ permalink raw reply related [flat|nested] 10+ messages in thread* [Qemu-devel] [PATCH v8 4/5] hw/arm: add allwinner a10 SoC support
2013-12-04 8:09 [Qemu-devel] [PATCH v8 0/5] add allwinner A10 SoC support liguang
` (2 preceding siblings ...)
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 3/5] hw/intc: add allwinner A10 interrupt controller liguang
@ 2013-12-04 8:09 ` liguang
2013-12-04 11:32 ` Peter Crosthwaite
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 5/5] hw/arm: add cubieboard support liguang
4 siblings, 1 reply; 10+ messages in thread
From: liguang @ 2013-12-04 8:09 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Peter Crosthwaite, Andreas Färber, liguang
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
---
hw/arm/Makefile.objs | 2 +-
hw/arm/allwinner-a10.c | 77 ++++++++++++++++++++++++++++++++++++++++
include/hw/arm/allwinner-a10.h | 36 ++++++++++++++++++
3 files changed, 114 insertions(+), 1 deletions(-)
create mode 100644 hw/arm/allwinner-a10.c
create mode 100644 include/hw/arm/allwinner-a10.h
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 3671b42..b9e5983 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -4,4 +4,4 @@ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
-obj-y += omap1.o omap2.o strongarm.o
+obj-y += omap1.o omap2.o strongarm.o allwinner-a10.o
diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
new file mode 100644
index 0000000..c4699b7
--- /dev/null
+++ b/hw/arm/allwinner-a10.c
@@ -0,0 +1,77 @@
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "hw/arm/allwinner-a10.h"
+
+
+static void aw_a10_init(Object *obj)
+{
+ AwA10State *s = AW_A10(obj);
+ DeviceState *dev;
+
+ object_initialize(&s->cpu, sizeof(s->cpu), "cortex-a8-" TYPE_ARM_CPU);
+ object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
+
+ object_initialize(&s->intc, sizeof(s->timer), TYPE_AW_A10_PIC);
+ dev = DEVICE(&s->intc);
+ qdev_set_parent_bus(dev, sysbus_get_default());
+
+ object_initialize(&s->timer, sizeof(s->timer), TYPE_AW_A10_PIT);
+ dev = DEVICE(&s->timer);
+ qdev_set_parent_bus(dev, sysbus_get_default());
+}
+
+static void aw_a10_realize(DeviceState *dev, Error **errp)
+{
+ AwA10State *s = AW_A10(dev);
+ SysBusDevice *sysbusdev;
+ uint8_t i;
+ Error *err = NULL;
+
+ object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
+ s->cpu_irq[0] = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ);
+ s->cpu_irq[1] = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ);
+
+ object_property_set_bool(OBJECT(&s->intc), true, "realized", &err);
+ sysbusdev = SYS_BUS_DEVICE(&s->intc);
+ sysbus_mmio_map(sysbusdev, 0, AW_A10_PIC_REG_BASE);
+ sysbus_connect_irq(sysbusdev, 0, s->cpu_irq[0]);
+ sysbus_connect_irq(sysbusdev, 1, s->cpu_irq[1]);
+ for (i = 0; i < AW_A10_PIC_INT_NR; i++) {
+ s->irq[i] = qdev_get_gpio_in(DEVICE(&s->intc), i);
+ }
+
+ object_property_set_bool(OBJECT(&s->timer), true, "realized", &err);
+ sysbusdev = SYS_BUS_DEVICE(&s->timer);
+ sysbus_mmio_map(sysbusdev, 0, AW_A10_PIT_REG_BASE);
+ sysbus_connect_irq(sysbusdev, 0, s->irq[22]);
+ sysbus_connect_irq(sysbusdev, 1, s->irq[23]);
+ sysbus_connect_irq(sysbusdev, 2, s->irq[24]);
+ sysbus_connect_irq(sysbusdev, 3, s->irq[25]);
+ sysbus_connect_irq(sysbusdev, 4, s->irq[67]);
+ sysbus_connect_irq(sysbusdev, 5, s->irq[68]);
+
+ serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1],
+ 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
+}
+
+static void aw_a10_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = aw_a10_realize;
+}
+
+static const TypeInfo aw_a10_type_info = {
+ .name = TYPE_AW_A10,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(AwA10State),
+ .instance_init = aw_a10_init,
+ .class_init = aw_a10_class_init,
+};
+
+static void aw_a10_register_types(void)
+{
+ type_register_static(&aw_a10_type_info);
+}
+
+type_init(aw_a10_register_types)
diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h
new file mode 100644
index 0000000..a3e7b77
--- /dev/null
+++ b/include/hw/arm/allwinner-a10.h
@@ -0,0 +1,36 @@
+#ifndef ALLWINNER_H_
+
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "hw/char/serial.h"
+#include "hw/arm/arm.h"
+#include "hw/timer/allwinner-a10-pit.h"
+#include "hw/intc/allwinner-a10-pic.h"
+
+#include "sysemu/sysemu.h"
+#include "exec/address-spaces.h"
+
+
+#define AW_A10_PIC_REG_BASE 0x01c20400
+#define AW_A10_PIT_REG_BASE 0x01c20c00
+#define AW_A10_UART0_REG_BASE 0x01c28000
+
+#define AW_A10_SDRAM_BASE 0x40000000
+
+#define TYPE_AW_A10 "allwiner-a10"
+#define AW_A10(obj) OBJECT_CHECK(AwA10State, (obj), TYPE_AW_A10)
+
+typedef struct AwA10State {
+ /*< private >*/
+ DeviceState parent_obj;
+ /*< public >*/
+
+ ARMCPU cpu;
+ qemu_irq irq[AW_A10_PIC_INT_NR];
+ qemu_irq cpu_irq[2];
+ AwA10PITState timer;
+ AwA10PICState intc;
+} AwA10State;
+
+#define ALLWINNER_H_
+#endif
--
1.7.2.5
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [Qemu-devel] [PATCH v8 4/5] hw/arm: add allwinner a10 SoC support
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 4/5] hw/arm: add allwinner a10 SoC support liguang
@ 2013-12-04 11:32 ` Peter Crosthwaite
2013-12-05 0:21 ` Li Guang
0 siblings, 1 reply; 10+ messages in thread
From: Peter Crosthwaite @ 2013-12-04 11:32 UTC (permalink / raw)
To: liguang
Cc: Peter Maydell, qemu-devel@nongnu.org Developers,
Andreas Färber
On Wed, Dec 4, 2013 at 6:09 PM, liguang <lig.fnst@cn.fujitsu.com> wrote:
> Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
> ---
> hw/arm/Makefile.objs | 2 +-
> hw/arm/allwinner-a10.c | 77 ++++++++++++++++++++++++++++++++++++++++
> include/hw/arm/allwinner-a10.h | 36 ++++++++++++++++++
> 3 files changed, 114 insertions(+), 1 deletions(-)
> create mode 100644 hw/arm/allwinner-a10.c
> create mode 100644 include/hw/arm/allwinner-a10.h
>
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index 3671b42..b9e5983 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -4,4 +4,4 @@ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
> obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
>
> obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
> -obj-y += omap1.o omap2.o strongarm.o
> +obj-y += omap1.o omap2.o strongarm.o allwinner-a10.o
> diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
> new file mode 100644
> index 0000000..c4699b7
> --- /dev/null
> +++ b/hw/arm/allwinner-a10.c
> @@ -0,0 +1,77 @@
> +#include "hw/sysbus.h"
> +#include "hw/devices.h"
> +#include "hw/arm/allwinner-a10.h"
> +
> +
> +static void aw_a10_init(Object *obj)
> +{
> + AwA10State *s = AW_A10(obj);
> + DeviceState *dev;
> +
> + object_initialize(&s->cpu, sizeof(s->cpu), "cortex-a8-" TYPE_ARM_CPU);
> + object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
> +
> + object_initialize(&s->intc, sizeof(s->timer), TYPE_AW_A10_PIC);
> + dev = DEVICE(&s->intc);
You could just use DEVICE(foo) inline here and below and drop the dev
variable to reduce verbosity.
> + qdev_set_parent_bus(dev, sysbus_get_default());
> +
> + object_initialize(&s->timer, sizeof(s->timer), TYPE_AW_A10_PIT);
> + dev = DEVICE(&s->timer);
> + qdev_set_parent_bus(dev, sysbus_get_default());
> +}
> +
> +static void aw_a10_realize(DeviceState *dev, Error **errp)
> +{
> + AwA10State *s = AW_A10(dev);
> + SysBusDevice *sysbusdev;
> + uint8_t i;
> + Error *err = NULL;
> +
> + object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
> + s->cpu_irq[0] = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ);
> + s->cpu_irq[1] = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ);
> +
> + object_property_set_bool(OBJECT(&s->intc), true, "realized", &err);
You neither assert nor propagate the error. So the repeated usage
below will cause a delayed (and somewhat obscure) assertion below if
both happen to error for some reason.
> + sysbusdev = SYS_BUS_DEVICE(&s->intc);
> + sysbus_mmio_map(sysbusdev, 0, AW_A10_PIC_REG_BASE);
> + sysbus_connect_irq(sysbusdev, 0, s->cpu_irq[0]);
> + sysbus_connect_irq(sysbusdev, 1, s->cpu_irq[1]);
> + for (i = 0; i < AW_A10_PIC_INT_NR; i++) {
> + s->irq[i] = qdev_get_gpio_in(DEVICE(&s->intc), i);
> + }
> +
> + object_property_set_bool(OBJECT(&s->timer), true, "realized", &err);
> + sysbusdev = SYS_BUS_DEVICE(&s->timer);
> + sysbus_mmio_map(sysbusdev, 0, AW_A10_PIT_REG_BASE);
> + sysbus_connect_irq(sysbusdev, 0, s->irq[22]);
> + sysbus_connect_irq(sysbusdev, 1, s->irq[23]);
> + sysbus_connect_irq(sysbusdev, 2, s->irq[24]);
> + sysbus_connect_irq(sysbusdev, 3, s->irq[25]);
> + sysbus_connect_irq(sysbusdev, 4, s->irq[67]);
> + sysbus_connect_irq(sysbusdev, 5, s->irq[68]);
> +
> + serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1],
> + 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
> +}
> +
> +static void aw_a10_class_init(ObjectClass *oc, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(oc);
> +
> + dc->realize = aw_a10_realize;
> +}
> +
> +static const TypeInfo aw_a10_type_info = {
> + .name = TYPE_AW_A10,
> + .parent = TYPE_DEVICE,
> + .instance_size = sizeof(AwA10State),
> + .instance_init = aw_a10_init,
> + .class_init = aw_a10_class_init,
> +};
> +
> +static void aw_a10_register_types(void)
> +{
> + type_register_static(&aw_a10_type_info);
> +}
> +
> +type_init(aw_a10_register_types)
> diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h
> new file mode 100644
> index 0000000..a3e7b77
> --- /dev/null
> +++ b/include/hw/arm/allwinner-a10.h
> @@ -0,0 +1,36 @@
> +#ifndef ALLWINNER_H_
> +
> +#include "qemu-common.h"
> +#include "qemu/error-report.h"
> +#include "hw/char/serial.h"
> +#include "hw/arm/arm.h"
> +#include "hw/timer/allwinner-a10-pit.h"
> +#include "hw/intc/allwinner-a10-pic.h"
> +
> +#include "sysemu/sysemu.h"
> +#include "exec/address-spaces.h"
> +
> +
> +#define AW_A10_PIC_REG_BASE 0x01c20400
> +#define AW_A10_PIT_REG_BASE 0x01c20c00
> +#define AW_A10_UART0_REG_BASE 0x01c28000
> +
> +#define AW_A10_SDRAM_BASE 0x40000000
> +
> +#define TYPE_AW_A10 "allwiner-a10"
"allwinner"
> +#define AW_A10(obj) OBJECT_CHECK(AwA10State, (obj), TYPE_AW_A10)
> +
> +typedef struct AwA10State {
> + /*< private >*/
> + DeviceState parent_obj;
> + /*< public >*/
> +
> + ARMCPU cpu;
> + qemu_irq irq[AW_A10_PIC_INT_NR];
> + qemu_irq cpu_irq[2];
I dont see the need to keep these as device state. They appear to be
just local variables to realize().
> + AwA10PITState timer;
> + AwA10PICState intc;
> +} AwA10State;
> +
> +#define ALLWINNER_H_
> +#endif
> --
> 1.7.2.5
>
>
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [Qemu-devel] [PATCH v8 4/5] hw/arm: add allwinner a10 SoC support
2013-12-04 11:32 ` Peter Crosthwaite
@ 2013-12-05 0:21 ` Li Guang
0 siblings, 0 replies; 10+ messages in thread
From: Li Guang @ 2013-12-05 0:21 UTC (permalink / raw)
To: Peter Crosthwaite
Cc: Peter Maydell, qemu-devel@nongnu.org Developers,
Andreas Färber
Peter Crosthwaite wrote:
> On Wed, Dec 4, 2013 at 6:09 PM, liguang<lig.fnst@cn.fujitsu.com> wrote:
>
>> Signed-off-by: liguang<lig.fnst@cn.fujitsu.com>
>> ---
>> hw/arm/Makefile.objs | 2 +-
>> hw/arm/allwinner-a10.c | 77 ++++++++++++++++++++++++++++++++++++++++
>> include/hw/arm/allwinner-a10.h | 36 ++++++++++++++++++
>> 3 files changed, 114 insertions(+), 1 deletions(-)
>> create mode 100644 hw/arm/allwinner-a10.c
>> create mode 100644 include/hw/arm/allwinner-a10.h
>>
>> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
>> index 3671b42..b9e5983 100644
>> --- a/hw/arm/Makefile.objs
>> +++ b/hw/arm/Makefile.objs
>> @@ -4,4 +4,4 @@ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
>> obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
>>
>> obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
>> -obj-y += omap1.o omap2.o strongarm.o
>> +obj-y += omap1.o omap2.o strongarm.o allwinner-a10.o
>> diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
>> new file mode 100644
>> index 0000000..c4699b7
>> --- /dev/null
>> +++ b/hw/arm/allwinner-a10.c
>> @@ -0,0 +1,77 @@
>> +#include "hw/sysbus.h"
>> +#include "hw/devices.h"
>> +#include "hw/arm/allwinner-a10.h"
>> +
>> +
>> +static void aw_a10_init(Object *obj)
>> +{
>> + AwA10State *s = AW_A10(obj);
>> + DeviceState *dev;
>> +
>> + object_initialize(&s->cpu, sizeof(s->cpu), "cortex-a8-" TYPE_ARM_CPU);
>> + object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
>> +
>> + object_initialize(&s->intc, sizeof(s->timer), TYPE_AW_A10_PIC);
>> + dev = DEVICE(&s->intc);
>>
> You could just use DEVICE(foo) inline here and below and drop the dev
> variable to reduce verbosity.
>
>
>> + qdev_set_parent_bus(dev, sysbus_get_default());
>> +
>> + object_initialize(&s->timer, sizeof(s->timer), TYPE_AW_A10_PIT);
>> + dev = DEVICE(&s->timer);
>> + qdev_set_parent_bus(dev, sysbus_get_default());
>> +}
>> +
>> +static void aw_a10_realize(DeviceState *dev, Error **errp)
>> +{
>> + AwA10State *s = AW_A10(dev);
>> + SysBusDevice *sysbusdev;
>> + uint8_t i;
>> + Error *err = NULL;
>> +
>> + object_property_set_bool(OBJECT(&s->cpu), true, "realized",&err);
>> + s->cpu_irq[0] = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ);
>> + s->cpu_irq[1] = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ);
>> +
>> + object_property_set_bool(OBJECT(&s->intc), true, "realized",&err);
>>
> You neither assert nor propagate the error. So the repeated usage
> below will cause a delayed (and somewhat obscure) assertion below if
> both happen to error for some reason.
>
>
>> + sysbusdev = SYS_BUS_DEVICE(&s->intc);
>> + sysbus_mmio_map(sysbusdev, 0, AW_A10_PIC_REG_BASE);
>> + sysbus_connect_irq(sysbusdev, 0, s->cpu_irq[0]);
>> + sysbus_connect_irq(sysbusdev, 1, s->cpu_irq[1]);
>> + for (i = 0; i< AW_A10_PIC_INT_NR; i++) {
>> + s->irq[i] = qdev_get_gpio_in(DEVICE(&s->intc), i);
>> + }
>> +
>> + object_property_set_bool(OBJECT(&s->timer), true, "realized",&err);
>> + sysbusdev = SYS_BUS_DEVICE(&s->timer);
>> + sysbus_mmio_map(sysbusdev, 0, AW_A10_PIT_REG_BASE);
>> + sysbus_connect_irq(sysbusdev, 0, s->irq[22]);
>> + sysbus_connect_irq(sysbusdev, 1, s->irq[23]);
>> + sysbus_connect_irq(sysbusdev, 2, s->irq[24]);
>> + sysbus_connect_irq(sysbusdev, 3, s->irq[25]);
>> + sysbus_connect_irq(sysbusdev, 4, s->irq[67]);
>> + sysbus_connect_irq(sysbusdev, 5, s->irq[68]);
>> +
>> + serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1],
>> + 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
>> +}
>> +
>> +static void aw_a10_class_init(ObjectClass *oc, void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(oc);
>> +
>> + dc->realize = aw_a10_realize;
>> +}
>> +
>> +static const TypeInfo aw_a10_type_info = {
>> + .name = TYPE_AW_A10,
>> + .parent = TYPE_DEVICE,
>> + .instance_size = sizeof(AwA10State),
>> + .instance_init = aw_a10_init,
>> + .class_init = aw_a10_class_init,
>> +};
>> +
>> +static void aw_a10_register_types(void)
>> +{
>> + type_register_static(&aw_a10_type_info);
>> +}
>> +
>> +type_init(aw_a10_register_types)
>> diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h
>> new file mode 100644
>> index 0000000..a3e7b77
>> --- /dev/null
>> +++ b/include/hw/arm/allwinner-a10.h
>> @@ -0,0 +1,36 @@
>> +#ifndef ALLWINNER_H_
>> +
>> +#include "qemu-common.h"
>> +#include "qemu/error-report.h"
>> +#include "hw/char/serial.h"
>> +#include "hw/arm/arm.h"
>> +#include "hw/timer/allwinner-a10-pit.h"
>> +#include "hw/intc/allwinner-a10-pic.h"
>> +
>> +#include "sysemu/sysemu.h"
>> +#include "exec/address-spaces.h"
>> +
>> +
>> +#define AW_A10_PIC_REG_BASE 0x01c20400
>> +#define AW_A10_PIT_REG_BASE 0x01c20c00
>> +#define AW_A10_UART0_REG_BASE 0x01c28000
>> +
>> +#define AW_A10_SDRAM_BASE 0x40000000
>> +
>> +#define TYPE_AW_A10 "allwiner-a10"
>>
> "allwinner"
>
>
>> +#define AW_A10(obj) OBJECT_CHECK(AwA10State, (obj), TYPE_AW_A10)
>> +
>> +typedef struct AwA10State {
>> + /*< private>*/
>> + DeviceState parent_obj;
>> + /*< public>*/
>> +
>> + ARMCPU cpu;
>> + qemu_irq irq[AW_A10_PIC_INT_NR];
>> + qemu_irq cpu_irq[2];
>>
> I dont see the need to keep these as device state. They appear to be
> just local variables to realize().
>
>
>> + AwA10PITState timer;
>> + AwA10PICState intc;
>> +} AwA10State;
>> +
>> +#define ALLWINNER_H_
>> +#endif
>> --
>> 1.7.2.5
>>
>>
>>
>
OK, will fix.
Thanks!
Li Guang
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH v8 5/5] hw/arm: add cubieboard support
2013-12-04 8:09 [Qemu-devel] [PATCH v8 0/5] add allwinner A10 SoC support liguang
` (3 preceding siblings ...)
2013-12-04 8:09 ` [Qemu-devel] [PATCH v8 4/5] hw/arm: add allwinner a10 SoC support liguang
@ 2013-12-04 8:09 ` liguang
4 siblings, 0 replies; 10+ messages in thread
From: liguang @ 2013-12-04 8:09 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Peter Crosthwaite, Andreas Färber, liguang
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
---
hw/arm/Makefile.objs | 2 +-
hw/arm/cubieboard.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+), 1 deletions(-)
create mode 100644 hw/arm/cubieboard.c
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index b9e5983..8be8d8e 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -4,4 +4,4 @@ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
-obj-y += omap1.o omap2.o strongarm.o allwinner-a10.o
+obj-y += omap1.o omap2.o strongarm.o allwinner-a10.o cubieboard.o
diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c
new file mode 100644
index 0000000..0599061
--- /dev/null
+++ b/hw/arm/cubieboard.c
@@ -0,0 +1,52 @@
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "hw/boards.h"
+#include "hw/arm/allwinner-a10.h"
+
+
+static struct arm_boot_info cubieboard_binfo = {
+ .loader_start = AW_A10_SDRAM_BASE,
+ .board_id = 0x1008,
+};
+
+typedef struct CubieBoardState {
+ AwA10State *a10;
+ MemoryRegion sdram;
+} CubieBoardState;
+
+static void cubieboard_init(QEMUMachineInitArgs *args)
+{
+ CubieBoardState *s = g_new(CubieBoardState, 1);
+ Error *err = NULL;
+
+ s->a10 = AW_A10(object_new(TYPE_AW_A10));
+ object_property_set_bool(OBJECT(s->a10), true, "realized", &err);
+ if (err != NULL) {
+ error_report("Couldn't realize Allwinner A10: %s\n",
+ error_get_pretty(err));
+ exit(1);
+ }
+
+ memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram", args->ram_size);
+ vmstate_register_ram_global(&s->sdram);
+ memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE,
+ &s->sdram);
+ cubieboard_binfo.ram_size = args->ram_size;
+ cubieboard_binfo.kernel_filename = args->kernel_filename;
+ cubieboard_binfo.kernel_cmdline = args->kernel_cmdline;
+ arm_load_kernel(&s->a10->cpu, &cubieboard_binfo);
+}
+
+static QEMUMachine cubieboard_machine = {
+ .name = "cubieboard",
+ .desc = "cubietec cubieboard emulation",
+ .init = cubieboard_init,
+};
+
+
+static void cubieboard_machine_init(void)
+{
+ qemu_register_machine(&cubieboard_machine);
+}
+
+machine_init(cubieboard_machine_init)
--
1.7.2.5
^ permalink raw reply related [flat|nested] 10+ messages in thread