* [Qemu-devel] [PATCH v3 1/4] hw/timer: add sunxi timer device
2013-11-25 7:41 [Qemu-devel] [PATCH v3 0/4] add sunxi machine type liguang
@ 2013-11-25 7:41 ` liguang
2013-11-25 10:15 ` Peter Crosthwaite
2013-11-25 7:41 ` [Qemu-devel] [PATCH v3 2/4] hw/intc: add sunxi interrupt controller device liguang
` (2 subsequent siblings)
3 siblings, 1 reply; 11+ messages in thread
From: liguang @ 2013-11-25 7:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, liguang
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
---
default-configs/arm-softmmu.mak | 2 +
hw/timer/Makefile.objs | 1 +
hw/timer/sunxi-pit.c | 260 +++++++++++++++++++++++++++++++++++++++
include/hw/timer/sunxi-pit.h | 26 ++++
4 files changed, 289 insertions(+), 0 deletions(-)
create mode 100644 hw/timer/sunxi-pit.c
create mode 100644 include/hw/timer/sunxi-pit.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index a555eef..7bf5ad0 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_SUNXI_PIT=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index eca5905..f7888e9 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -27,3 +27,4 @@ obj-$(CONFIG_SH4) += sh_timer.o
obj-$(CONFIG_TUSB6010) += tusb6010.o
obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
+obj-$(CONFIG_SUNXI_PIT) += sunxi-pit.o
diff --git a/hw/timer/sunxi-pit.c b/hw/timer/sunxi-pit.c
new file mode 100644
index 0000000..6220b60
--- /dev/null
+++ b/hw/timer/sunxi-pit.c
@@ -0,0 +1,260 @@
+/*
+ * Allwinner sunxi 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 "hw/ptimer.h"
+#include "sysemu/sysemu.h"
+#include "hw/timer/sunxi-pit.h"
+
+
+typedef struct SunxiPITState {
+ SysBusDevice busdev;
+ qemu_irq irq[SUNXI_TIMER_NR];
+ ptimer_state *timer[6];
+ ptimer_state *counter;
+ MemoryRegion iomem;
+ uint32_t irq_enable;
+ uint32_t irq_status;
+ uint32_t control[6];
+ uint32_t interval[6];
+ uint32_t count[6];
+ uint32_t watch_dog_mode;
+ uint32_t watch_dog_control;
+ uint32_t count_lo;
+ uint32_t count_hi;
+ uint32_t count_ctl;
+} SunxiPITState;
+
+static uint64_t sunxi_pit_read(void *opaque, hwaddr offset, unsigned size)
+{
+ SunxiPITState *s = SUNXI_PIT(opaque);
+ uint8_t index = 0;
+
+ switch (offset) {
+ case SUNXI_TIMER_IRQ_EN:
+ return s->irq_enable;
+ break;
+ case SUNXI_TIMER_IRQ_ST:
+ return s->irq_status;
+ break;
+ case SUNXI_TIMER_BASE ... SUNXI_TIMER_BASE * 6 + SUNXI_TIMER_COUNT:
+ index = offset & 0xf0;
+ index >>= 4;
+ index -= 1;
+ switch (offset & 0x0f) {
+ case SUNXI_TIMER_CONTROL:
+ return s->control[index];
+ break;
+ case SUNXI_TIMER_INTERVAL:
+ return s->interval[index];
+ break;
+ case SUNXI_TIMER_COUNT:
+ s->count[index] = ptimer_get_count(s->timer[index]);
+ return s->count[index];
+ default:
+ break;
+ }
+ break;
+ case SUNXI_WDOG_CONTROL:
+ break;
+ case SUNXI_WDOG_MODE:
+ break;
+ case SUNXI_COUNT_LO:
+ return s->count_lo;
+ break;
+ case SUNXI_COUNT_HI:
+ return s->count_hi;
+ break;
+ case SUNXI_COUNT_CTL:
+ return s->count_ctl;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void sunxi_pit_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ SunxiPITState *s = SUNXI_PIT(opaque);
+ uint8_t index = 0;
+
+ switch (offset) {
+ case SUNXI_TIMER_IRQ_EN:
+ s->irq_enable = value;
+ break;
+ case SUNXI_TIMER_IRQ_ST:
+ for (index = 0; index < 32; index++) {
+ if (test_bit(index, (void *)&value)) {
+ clear_bit(index, (void *)&s->irq_status);
+ }
+ }
+ break;
+ case SUNXI_TIMER_BASE ... SUNXI_TIMER_BASE * 6 + SUNXI_TIMER_COUNT:
+ index = offset & 0xf0;
+ index >>= 4;
+ index -= 1;
+ switch (offset & 0x0f) {
+ case SUNXI_TIMER_CONTROL:
+ s->control[index] = value;
+ if (s->control[index] & 0x2) {
+ ptimer_set_count(s->timer[index], s->interval[index]);
+ }
+ if (s->control[index] & 0x1) {
+ ptimer_run(s->timer[index], 1);
+ } else {
+ ptimer_stop(s->timer[index]);
+ }
+ break;
+ case SUNXI_TIMER_INTERVAL:
+ s->interval[index] = value;
+ ptimer_set_count(s->timer[index], s->interval[index]);
+ break;
+ case SUNXI_TIMER_COUNT:
+ s->count[index] = value;
+ default:
+ break;
+ }
+ break;
+ case SUNXI_WDOG_CONTROL:
+ s->watch_dog_control = value;
+ break;
+ case SUNXI_WDOG_MODE:
+ s->watch_dog_mode = value;
+ break;
+ case SUNXI_COUNT_LO:
+ s->count_lo = value;
+ break;
+ case SUNXI_COUNT_HI:
+ s->count_hi = value;
+ break;
+ case SUNXI_COUNT_CTL:
+ s->count_ctl = value;
+ if (s->count_ctl & 0x2) {
+ s->count_lo = ptimer_get_count(s->counter) ;
+ s->count_hi = ptimer_get_count(s->counter) >> 32;
+ s->count_ctl &= ~0x2;
+ }
+ if (s->count_ctl & 0x1) {
+ s->count_lo =0;
+ s->count_hi =0;
+ s->count_ctl &= ~0x1;
+ }
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps sunxi_pit_ops = {
+ .read = sunxi_pit_read,
+ .write = sunxi_pit_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void sunxi_pit_reset(DeviceState *dev)
+{
+ SunxiPITState *s = SUNXI_PIT(dev);
+ uint8_t i = 0;
+
+ s->irq_enable = 0;
+ s->irq_status = 0;
+ for (i = 0; i < 6; i++) {
+ s->control[i] = 0x4;
+ 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 sunxi_pit_timer_cb(void *opaque)
+{
+ SunxiPITState *s = SUNXI_PIT(opaque);
+ uint8_t i = 0;
+
+ for (i = 0; i < SUNXI_TIMER_NR; i++) {
+ if (!(s->control[i] & 0x80) && s->control[i] & 0x1) {
+ s->irq_status |= 1 << i;
+ ptimer_set_count(s->timer[i], s->interval[i]);
+ ptimer_run(s->timer[i], 1);
+ }
+ if (s->irq_status & s->irq_enable & (1 << i)) {
+ qemu_irq_raise(s->irq[i]);
+ } else {
+ qemu_irq_lower(s->irq[i]);
+ }
+ }
+}
+
+static void sunxi_pit_counter_cb(void *opaque)
+{
+}
+
+static void sunxi_pit_realize(DeviceState *dev, Error **errp)
+{
+ SunxiPITState *s = SUNXI_PIT(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ QEMUBH *bh[SUNXI_TIMER_NR];
+ QEMUBH *cbh;
+ uint8_t i = 0;
+
+ for (i = 0; i < SUNXI_TIMER_NR; i++) {
+ sysbus_init_irq(sbd, &s->irq[i]);
+ }
+ memory_region_init_io(&s->iomem, OBJECT(s), &sunxi_pit_ops, s,
+ TYPE_SUNXI_PIT, 0x400);
+ sysbus_init_mmio(sbd, &s->iomem);
+
+ for (i = 0; i < SUNXI_TIMER_NR; i++) {
+ bh[i] = qemu_bh_new(sunxi_pit_timer_cb, s);
+ s->timer[i] = ptimer_init(bh[i]);
+ ptimer_set_freq(s->timer[i], 240000);
+ }
+ cbh = qemu_bh_new(sunxi_pit_counter_cb, s);
+ s->counter = ptimer_init(cbh);
+ ptimer_set_freq(s->counter, 100);
+ ptimer_set_count(s->counter, 0xffffffff);
+ ptimer_run(s->counter, 0);
+}
+
+static void sunxi_pit_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = sunxi_pit_realize;
+ dc->reset = sunxi_pit_reset;
+ dc->desc = "sunxi timer";
+}
+
+static const TypeInfo sunxi_pit_info = {
+ .name = TYPE_SUNXI_PIT,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SunxiPITState),
+ .class_init = sunxi_pit_class_init,
+};
+
+static void sunxi_register_types(void)
+{
+ type_register_static(&sunxi_pit_info);
+}
+
+type_init(sunxi_register_types);
diff --git a/include/hw/timer/sunxi-pit.h b/include/hw/timer/sunxi-pit.h
new file mode 100644
index 0000000..38f1b4d
--- /dev/null
+++ b/include/hw/timer/sunxi-pit.h
@@ -0,0 +1,26 @@
+#ifndef SUNXI_PIT_H
+#define SUNXI_PIT_H
+
+
+#define TYPE_SUNXI_PIT "sunix-timer"
+#define SUNXI_PIT(obj) OBJECT_CHECK(SunxiPITState, (obj), TYPE_SUNXI_PIT)
+
+#define SUNXI_TIMER_NR 6
+#define SUNXI_TIMER_IRQ 0x1
+#define SUNXI_WDOG_IRQ 0x100
+
+#define SUNXI_TIMER_IRQ_EN 0
+#define SUNXI_TIMER_IRQ_ST 0x4
+#define SUNXI_TIMER_CONTROL 0x0
+#define SUNXI_TIMER_INTERVAL 0x4
+#define SUNXI_TIMER_COUNT 0x8
+#define SUNXI_WDOG_CONTROL 0x90
+#define SUNXI_WDOG_MODE 0x94
+#define SUNXI_COUNT_CTL 0xa0
+#define SUNXI_COUNT_LO 0xa4
+#define SUNXI_COUNT_HI 0xa8
+#define SUNXI_TIMER_BASE 0x10
+
+
+#endif
+
--
1.7.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v3 1/4] hw/timer: add sunxi timer device
2013-11-25 7:41 ` [Qemu-devel] [PATCH v3 1/4] hw/timer: add sunxi timer device liguang
@ 2013-11-25 10:15 ` Peter Crosthwaite
2013-11-25 10:52 ` Peter Maydell
2013-11-26 1:06 ` Li Guang
0 siblings, 2 replies; 11+ messages in thread
From: Peter Crosthwaite @ 2013-11-25 10:15 UTC (permalink / raw)
To: liguang; +Cc: Peter Maydell, qemu-devel@nongnu.org Developers
Hi,
On Mon, Nov 25, 2013 at 5:41 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 | 1 +
> hw/timer/sunxi-pit.c | 260 +++++++++++++++++++++++++++++++++++++++
> include/hw/timer/sunxi-pit.h | 26 ++++
> 4 files changed, 289 insertions(+), 0 deletions(-)
> create mode 100644 hw/timer/sunxi-pit.c
> create mode 100644 include/hw/timer/sunxi-pit.h
>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index a555eef..7bf5ad0 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_SUNXI_PIT=y
> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
> index eca5905..f7888e9 100644
> --- a/hw/timer/Makefile.objs
> +++ b/hw/timer/Makefile.objs
> @@ -27,3 +27,4 @@ obj-$(CONFIG_SH4) += sh_timer.o
> obj-$(CONFIG_TUSB6010) += tusb6010.o
>
> obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
> +obj-$(CONFIG_SUNXI_PIT) += sunxi-pit.o
> diff --git a/hw/timer/sunxi-pit.c b/hw/timer/sunxi-pit.c
> new file mode 100644
> index 0000000..6220b60
> --- /dev/null
> +++ b/hw/timer/sunxi-pit.c
> @@ -0,0 +1,260 @@
> +/*
> + * Allwinner sunxi 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 "hw/ptimer.h"
> +#include "sysemu/sysemu.h"
> +#include "hw/timer/sunxi-pit.h"
> +
> +
> +typedef struct SunxiPITState {
> + SysBusDevice busdev;
parent_obj
> + qemu_irq irq[SUNXI_TIMER_NR];
> + ptimer_state *timer[6];
> + ptimer_state *counter;
> + MemoryRegion iomem;
blank line here (to demarcate start of registers) would improve readability.
> + uint32_t irq_enable;
> + uint32_t irq_status;
> + uint32_t control[6];
> + uint32_t interval[6];
> + uint32_t count[6];
> + uint32_t watch_dog_mode;
> + uint32_t watch_dog_control;
> + uint32_t count_lo;
> + uint32_t count_hi;
> + uint32_t count_ctl;
> +} SunxiPITState;
> +
> +static uint64_t sunxi_pit_read(void *opaque, hwaddr offset, unsigned size)
> +{
> + SunxiPITState *s = SUNXI_PIT(opaque);
> + uint8_t index = 0;
> +
> + switch (offset) {
> + case SUNXI_TIMER_IRQ_EN:
> + return s->irq_enable;
> + break;
> + case SUNXI_TIMER_IRQ_ST:
> + return s->irq_status;
> + break;
> + case SUNXI_TIMER_BASE ... SUNXI_TIMER_BASE * 6 + SUNXI_TIMER_COUNT:
> + index = offset & 0xf0;
> + index >>= 4;
> + index -= 1;
> + switch (offset & 0x0f) {
> + case SUNXI_TIMER_CONTROL:
> + return s->control[index];
> + break;
> + case SUNXI_TIMER_INTERVAL:
> + return s->interval[index];
> + break;
> + case SUNXI_TIMER_COUNT:
> + s->count[index] = ptimer_get_count(s->timer[index]);
> + return s->count[index];
> + default:
> + break;
> + }
> + break;
> + case SUNXI_WDOG_CONTROL:
> + break;
> + case SUNXI_WDOG_MODE:
> + break;
> + case SUNXI_COUNT_LO:
> + return s->count_lo;
> + break;
> + case SUNXI_COUNT_HI:
> + return s->count_hi;
> + break;
> + case SUNXI_COUNT_CTL:
> + return s->count_ctl;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static void sunxi_pit_write(void *opaque, hwaddr offset, uint64_t value,
> + unsigned size)
> +{
> + SunxiPITState *s = SUNXI_PIT(opaque);
> + uint8_t index = 0;
> +
> + switch (offset) {
> + case SUNXI_TIMER_IRQ_EN:
> + s->irq_enable = value;
> + break;
> + case SUNXI_TIMER_IRQ_ST:
> + for (index = 0; index < 32; index++) {
> + if (test_bit(index, (void *)&value)) {
> + clear_bit(index, (void *)&s->irq_status);
> + }
> + }
s->irq_status &= ~value;
Is probably a simpler and more common way to implement write-to-clear semantic.
> + break;
> + case SUNXI_TIMER_BASE ... SUNXI_TIMER_BASE * 6 + SUNXI_TIMER_COUNT:
> + index = offset & 0xf0;
> + index >>= 4;
> + index -= 1;
> + switch (offset & 0x0f) {
> + case SUNXI_TIMER_CONTROL:
> + s->control[index] = value;
> + if (s->control[index] & 0x2) {
> + ptimer_set_count(s->timer[index], s->interval[index]);
> + }
> + if (s->control[index] & 0x1) {
> + ptimer_run(s->timer[index], 1);
> + } else {
> + ptimer_stop(s->timer[index]);
> + }
> + break;
> + case SUNXI_TIMER_INTERVAL:
> + s->interval[index] = value;
> + ptimer_set_count(s->timer[index], s->interval[index]);
> + break;
> + case SUNXI_TIMER_COUNT:
> + s->count[index] = value;
> + default:
> + break;
> + }
> + break;
> + case SUNXI_WDOG_CONTROL:
> + s->watch_dog_control = value;
> + break;
> + case SUNXI_WDOG_MODE:
> + s->watch_dog_mode = value;
> + break;
> + case SUNXI_COUNT_LO:
> + s->count_lo = value;
> + break;
> + case SUNXI_COUNT_HI:
> + s->count_hi = value;
> + break;
> + case SUNXI_COUNT_CTL:
> + s->count_ctl = value;
> + if (s->count_ctl & 0x2) {
best to define macros for the bitmasks.
> + s->count_lo = ptimer_get_count(s->counter) ;
> + s->count_hi = ptimer_get_count(s->counter) >> 32;
> + s->count_ctl &= ~0x2;
But this does seem strange. The counter register value only updates to
the free running counter value when you write this magic bit?
> + }
> + if (s->count_ctl & 0x1) {
> + s->count_lo =0;
> + s->count_hi =0;
> + s->count_ctl &= ~0x1;
> + }
> + default:
> + break;
> + }
> +}
> +
> +static const MemoryRegionOps sunxi_pit_ops = {
> + .read = sunxi_pit_read,
> + .write = sunxi_pit_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static void sunxi_pit_reset(DeviceState *dev)
> +{
> + SunxiPITState *s = SUNXI_PIT(dev);
> + uint8_t i = 0;
> +
> + s->irq_enable = 0;
> + s->irq_status = 0;
> + for (i = 0; i < 6; i++) {
> + s->control[i] = 0x4;
define magic number 0x4.
> + 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 sunxi_pit_timer_cb(void *opaque)
> +{
> + SunxiPITState *s = SUNXI_PIT(opaque);
> + uint8_t i = 0;
> +
> + for (i = 0; i < SUNXI_TIMER_NR; i++) {
> + if (!(s->control[i] & 0x80) && s->control[i] & 0x1) {
> + s->irq_status |= 1 << i;
> + ptimer_set_count(s->timer[i], s->interval[i]);
> + ptimer_run(s->timer[i], 1);
> + }
> + if (s->irq_status & s->irq_enable & (1 << i)) {
> + qemu_irq_raise(s->irq[i]);
> + } else {
> + qemu_irq_lower(s->irq[i]);
> + }
qemu_irq_set can make shorter work of this.
> + }
but this loop seems strange. It doesnt seem to identify which timer
actually hit, yet its potenitally raising interrupts for all 6 in a
loop. Will this cause spurious interrupts when multiple timers are
running?
> +}
> +
> +static void sunxi_pit_counter_cb(void *opaque)
> +{
> +}
> +
> +static void sunxi_pit_realize(DeviceState *dev, Error **errp)
> +{
> + SunxiPITState *s = SUNXI_PIT(dev);
> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> + QEMUBH *bh[SUNXI_TIMER_NR];
> + QEMUBH *cbh;
> + uint8_t i = 0;
> +
> + for (i = 0; i < SUNXI_TIMER_NR; i++) {
> + sysbus_init_irq(sbd, &s->irq[i]);
> + }
> + memory_region_init_io(&s->iomem, OBJECT(s), &sunxi_pit_ops, s,
> + TYPE_SUNXI_PIT, 0x400);
> + sysbus_init_mmio(sbd, &s->iomem);
> +
> + for (i = 0; i < SUNXI_TIMER_NR; i++) {
> + bh[i] = qemu_bh_new(sunxi_pit_timer_cb, s);
> + s->timer[i] = ptimer_init(bh[i]);
> + ptimer_set_freq(s->timer[i], 240000);
> + }
> + cbh = qemu_bh_new(sunxi_pit_counter_cb, s);
> + s->counter = ptimer_init(cbh);
use of a ptimer for a free running counter seems strange to me.
Ptimers are intend to wrap the lower level QEMU timer for periodic
timing applications. This doesn't really fit that. Its perhaps just
simpler to use qemu_get_clock_ns.
> + ptimer_set_freq(s->counter, 100);
> + ptimer_set_count(s->counter, 0xffffffff);
> + ptimer_run(s->counter, 0);
This is strange for a realize function. You are starting a timer as a
machine creation step. Shouldn't this be in reset (along with a reset
of the timer value itself)?
> +}
> +
> +static void sunxi_pit_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->realize = sunxi_pit_realize;
> + dc->reset = sunxi_pit_reset;
> + dc->desc = "sunxi timer";
You should add VMSD support.
> +}
> +
> +static const TypeInfo sunxi_pit_info = {
> + .name = TYPE_SUNXI_PIT,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(SunxiPITState),
> + .class_init = sunxi_pit_class_init,
> +};
> +
> +static void sunxi_register_types(void)
> +{
> + type_register_static(&sunxi_pit_info);
> +}
> +
> +type_init(sunxi_register_types);
> diff --git a/include/hw/timer/sunxi-pit.h b/include/hw/timer/sunxi-pit.h
> new file mode 100644
> index 0000000..38f1b4d
> --- /dev/null
> +++ b/include/hw/timer/sunxi-pit.h
> @@ -0,0 +1,26 @@
> +#ifndef SUNXI_PIT_H
> +#define SUNXI_PIT_H
> +
> +
> +#define TYPE_SUNXI_PIT "sunix-timer"
"sunxi-timer"
> +#define SUNXI_PIT(obj) OBJECT_CHECK(SunxiPITState, (obj), TYPE_SUNXI_PIT)
> +
> +#define SUNXI_TIMER_NR 6
> +#define SUNXI_TIMER_IRQ 0x1
> +#define SUNXI_WDOG_IRQ 0x100
> +
> +#define SUNXI_TIMER_IRQ_EN 0
> +#define SUNXI_TIMER_IRQ_ST 0x4
> +#define SUNXI_TIMER_CONTROL 0x0
> +#define SUNXI_TIMER_INTERVAL 0x4
> +#define SUNXI_TIMER_COUNT 0x8
> +#define SUNXI_WDOG_CONTROL 0x90
> +#define SUNXI_WDOG_MODE 0x94
> +#define SUNXI_COUNT_CTL 0xa0
> +#define SUNXI_COUNT_LO 0xa4
> +#define SUNXI_COUNT_HI 0xa8
> +#define SUNXI_TIMER_BASE 0x10
> +
You could tab out the numbers to a consistent tab-stop for easier reading.
Regards,
Peter
> +
> +#endif
> +
> --
> 1.7.2.5
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v3 1/4] hw/timer: add sunxi timer device
2013-11-25 10:15 ` Peter Crosthwaite
@ 2013-11-25 10:52 ` Peter Maydell
2013-11-26 1:06 ` Li Guang
1 sibling, 0 replies; 11+ messages in thread
From: Peter Maydell @ 2013-11-25 10:52 UTC (permalink / raw)
To: Peter Crosthwaite; +Cc: qemu-devel@nongnu.org Developers, liguang
On 25 November 2013 10:15, Peter Crosthwaite
<peter.crosthwaite@xilinx.com> wrote:
> Hi,
>
> On Mon, Nov 25, 2013 at 5:41 PM, liguang <lig.fnst@cn.fujitsu.com> wrote:
>> +#define SUNXI_TIMER_IRQ_EN 0
>> +#define SUNXI_TIMER_IRQ_ST 0x4
>> +#define SUNXI_TIMER_CONTROL 0x0
>> +#define SUNXI_TIMER_INTERVAL 0x4
>> +#define SUNXI_TIMER_COUNT 0x8
>> +#define SUNXI_WDOG_CONTROL 0x90
>> +#define SUNXI_WDOG_MODE 0x94
>> +#define SUNXI_COUNT_CTL 0xa0
>> +#define SUNXI_COUNT_LO 0xa4
>> +#define SUNXI_COUNT_HI 0xa8
>> +#define SUNXI_TIMER_BASE 0x10
>> +
>
> You could tab out the numbers to a consistent tab-stop for easier reading.
...but use spaces, not tab characters, please.
thanks
-- PMM
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v3 1/4] hw/timer: add sunxi timer device
2013-11-25 10:15 ` Peter Crosthwaite
2013-11-25 10:52 ` Peter Maydell
@ 2013-11-26 1:06 ` Li Guang
1 sibling, 0 replies; 11+ messages in thread
From: Li Guang @ 2013-11-26 1:06 UTC (permalink / raw)
To: Peter Crosthwaite; +Cc: Peter Maydell, qemu-devel@nongnu.org Developers
Peter Crosthwaite wrote:
> Hi,
>
> On Mon, Nov 25, 2013 at 5:41 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 | 1 +
>> hw/timer/sunxi-pit.c | 260 +++++++++++++++++++++++++++++++++++++++
>> include/hw/timer/sunxi-pit.h | 26 ++++
>> 4 files changed, 289 insertions(+), 0 deletions(-)
>> create mode 100644 hw/timer/sunxi-pit.c
>> create mode 100644 include/hw/timer/sunxi-pit.h
>>
>> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
>> index a555eef..7bf5ad0 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_SUNXI_PIT=y
>> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
>> index eca5905..f7888e9 100644
>> --- a/hw/timer/Makefile.objs
>> +++ b/hw/timer/Makefile.objs
>> @@ -27,3 +27,4 @@ obj-$(CONFIG_SH4) += sh_timer.o
>> obj-$(CONFIG_TUSB6010) += tusb6010.o
>>
>> obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
>> +obj-$(CONFIG_SUNXI_PIT) += sunxi-pit.o
>> diff --git a/hw/timer/sunxi-pit.c b/hw/timer/sunxi-pit.c
>> new file mode 100644
>> index 0000000..6220b60
>> --- /dev/null
>> +++ b/hw/timer/sunxi-pit.c
>> @@ -0,0 +1,260 @@
>> +/*
>> + * Allwinner sunxi 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 "hw/ptimer.h"
>> +#include "sysemu/sysemu.h"
>> +#include "hw/timer/sunxi-pit.h"
>> +
>> +
>> +typedef struct SunxiPITState {
>> + SysBusDevice busdev;
>>
> parent_obj
>
>
>> + qemu_irq irq[SUNXI_TIMER_NR];
>> + ptimer_state *timer[6];
>> + ptimer_state *counter;
>> + MemoryRegion iomem;
>>
> blank line here (to demarcate start of registers) would improve readability.
>
>
>> + uint32_t irq_enable;
>> + uint32_t irq_status;
>> + uint32_t control[6];
>> + uint32_t interval[6];
>> + uint32_t count[6];
>> + uint32_t watch_dog_mode;
>> + uint32_t watch_dog_control;
>> + uint32_t count_lo;
>> + uint32_t count_hi;
>> + uint32_t count_ctl;
>> +} SunxiPITState;
>> +
>> +static uint64_t sunxi_pit_read(void *opaque, hwaddr offset, unsigned size)
>> +{
>> + SunxiPITState *s = SUNXI_PIT(opaque);
>> + uint8_t index = 0;
>> +
>> + switch (offset) {
>> + case SUNXI_TIMER_IRQ_EN:
>> + return s->irq_enable;
>> + break;
>> + case SUNXI_TIMER_IRQ_ST:
>> + return s->irq_status;
>> + break;
>> + case SUNXI_TIMER_BASE ... SUNXI_TIMER_BASE * 6 + SUNXI_TIMER_COUNT:
>> + index = offset& 0xf0;
>> + index>>= 4;
>> + index -= 1;
>> + switch (offset& 0x0f) {
>> + case SUNXI_TIMER_CONTROL:
>> + return s->control[index];
>> + break;
>> + case SUNXI_TIMER_INTERVAL:
>> + return s->interval[index];
>> + break;
>> + case SUNXI_TIMER_COUNT:
>> + s->count[index] = ptimer_get_count(s->timer[index]);
>> + return s->count[index];
>> + default:
>> + break;
>> + }
>> + break;
>> + case SUNXI_WDOG_CONTROL:
>> + break;
>> + case SUNXI_WDOG_MODE:
>> + break;
>> + case SUNXI_COUNT_LO:
>> + return s->count_lo;
>> + break;
>> + case SUNXI_COUNT_HI:
>> + return s->count_hi;
>> + break;
>> + case SUNXI_COUNT_CTL:
>> + return s->count_ctl;
>> + default:
>> + break;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void sunxi_pit_write(void *opaque, hwaddr offset, uint64_t value,
>> + unsigned size)
>> +{
>> + SunxiPITState *s = SUNXI_PIT(opaque);
>> + uint8_t index = 0;
>> +
>> + switch (offset) {
>> + case SUNXI_TIMER_IRQ_EN:
>> + s->irq_enable = value;
>> + break;
>> + case SUNXI_TIMER_IRQ_ST:
>> + for (index = 0; index< 32; index++) {
>> + if (test_bit(index, (void *)&value)) {
>> + clear_bit(index, (void *)&s->irq_status);
>> + }
>> + }
>>
> s->irq_status&= ~value;
>
> Is probably a simpler and more common way to implement write-to-clear semantic.
>
>
>> + break;
>> + case SUNXI_TIMER_BASE ... SUNXI_TIMER_BASE * 6 + SUNXI_TIMER_COUNT:
>> + index = offset& 0xf0;
>> + index>>= 4;
>> + index -= 1;
>> + switch (offset& 0x0f) {
>> + case SUNXI_TIMER_CONTROL:
>> + s->control[index] = value;
>> + if (s->control[index]& 0x2) {
>> + ptimer_set_count(s->timer[index], s->interval[index]);
>> + }
>> + if (s->control[index]& 0x1) {
>> + ptimer_run(s->timer[index], 1);
>> + } else {
>> + ptimer_stop(s->timer[index]);
>> + }
>> + break;
>> + case SUNXI_TIMER_INTERVAL:
>> + s->interval[index] = value;
>> + ptimer_set_count(s->timer[index], s->interval[index]);
>> + break;
>> + case SUNXI_TIMER_COUNT:
>> + s->count[index] = value;
>> + default:
>> + break;
>> + }
>> + break;
>> + case SUNXI_WDOG_CONTROL:
>> + s->watch_dog_control = value;
>> + break;
>> + case SUNXI_WDOG_MODE:
>> + s->watch_dog_mode = value;
>> + break;
>> + case SUNXI_COUNT_LO:
>> + s->count_lo = value;
>> + break;
>> + case SUNXI_COUNT_HI:
>> + s->count_hi = value;
>> + break;
>> + case SUNXI_COUNT_CTL:
>> + s->count_ctl = value;
>> + if (s->count_ctl& 0x2) {
>>
> best to define macros for the bitmasks.
>
>
all above are reasonable, will fix
>> + s->count_lo = ptimer_get_count(s->counter) ;
>> + s->count_hi = ptimer_get_count(s->counter)>> 32;
>> + s->count_ctl&= ~0x2;
>>
> But this does seem strange. The counter register value only updates to
> the free running counter value when you write this magic bit?
>
Yes, SPEC says,
" to latch the 64-bit Counter to the Low/Hi registers and it
will change to zero after the registers are latched"
>
>> + }
>> + if (s->count_ctl& 0x1) {
>> + s->count_lo =0;
>> + s->count_hi =0;
>> + s->count_ctl&= ~0x1;
>> + }
>> + default:
>> + break;
>> + }
>> +}
>> +
>> +static const MemoryRegionOps sunxi_pit_ops = {
>> + .read = sunxi_pit_read,
>> + .write = sunxi_pit_write,
>> + .endianness = DEVICE_NATIVE_ENDIAN,
>> +};
>> +
>> +static void sunxi_pit_reset(DeviceState *dev)
>> +{
>> + SunxiPITState *s = SUNXI_PIT(dev);
>> + uint8_t i = 0;
>> +
>> + s->irq_enable = 0;
>> + s->irq_status = 0;
>> + for (i = 0; i< 6; i++) {
>> + s->control[i] = 0x4;
>>
> define magic number 0x4.
>
>
>> + 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 sunxi_pit_timer_cb(void *opaque)
>> +{
>> + SunxiPITState *s = SUNXI_PIT(opaque);
>> + uint8_t i = 0;
>> +
>> + for (i = 0; i< SUNXI_TIMER_NR; i++) {
>> + if (!(s->control[i]& 0x80)&& s->control[i]& 0x1) {
>> + s->irq_status |= 1<< i;
>> + ptimer_set_count(s->timer[i], s->interval[i]);
>> + ptimer_run(s->timer[i], 1);
>> + }
>> + if (s->irq_status& s->irq_enable& (1<< i)) {
>> + qemu_irq_raise(s->irq[i]);
>> + } else {
>> + qemu_irq_lower(s->irq[i]);
>> + }
>>
> qemu_irq_set can make shorter work of this.
>
>
>> + }
>>
> but this loop seems strange. It doesnt seem to identify which timer
> actually hit, yet its potenitally raising interrupts for all 6 in a
> loop. Will this cause spurious interrupts when multiple timers are
> running?
>
>
my poor implementation
>> +}
>> +
>> +static void sunxi_pit_counter_cb(void *opaque)
>> +{
>> +}
>> +
>> +static void sunxi_pit_realize(DeviceState *dev, Error **errp)
>> +{
>> + SunxiPITState *s = SUNXI_PIT(dev);
>> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>> + QEMUBH *bh[SUNXI_TIMER_NR];
>> + QEMUBH *cbh;
>> + uint8_t i = 0;
>> +
>> + for (i = 0; i< SUNXI_TIMER_NR; i++) {
>> + sysbus_init_irq(sbd,&s->irq[i]);
>> + }
>> + memory_region_init_io(&s->iomem, OBJECT(s),&sunxi_pit_ops, s,
>> + TYPE_SUNXI_PIT, 0x400);
>> + sysbus_init_mmio(sbd,&s->iomem);
>> +
>> + for (i = 0; i< SUNXI_TIMER_NR; i++) {
>> + bh[i] = qemu_bh_new(sunxi_pit_timer_cb, s);
>> + s->timer[i] = ptimer_init(bh[i]);
>> + ptimer_set_freq(s->timer[i], 240000);
>> + }
>> + cbh = qemu_bh_new(sunxi_pit_counter_cb, s);
>> + s->counter = ptimer_init(cbh);
>>
> use of a ptimer for a free running counter seems strange to me.
> Ptimers are intend to wrap the lower level QEMU timer for periodic
> timing applications. This doesn't really fit that. Its perhaps just
> simpler to use qemu_get_clock_ns.
good suggestion!
>
>> + ptimer_set_freq(s->counter, 100);
>> + ptimer_set_count(s->counter, 0xffffffff);
>> + ptimer_run(s->counter, 0);
>>
> This is strange for a realize function. You are starting a timer as a
> machine creation step. Shouldn't this be in reset (along with a reset
> of the timer value itself)?
>
>
>> +}
>> +
>> +static void sunxi_pit_class_init(ObjectClass *klass, void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> + dc->realize = sunxi_pit_realize;
>> + dc->reset = sunxi_pit_reset;
>> + dc->desc = "sunxi timer";
>>
> You should add VMSD support.
>
>
>> +}
>> +
>> +static const TypeInfo sunxi_pit_info = {
>> + .name = TYPE_SUNXI_PIT,
>> + .parent = TYPE_SYS_BUS_DEVICE,
>> + .instance_size = sizeof(SunxiPITState),
>> + .class_init = sunxi_pit_class_init,
>> +};
>> +
>> +static void sunxi_register_types(void)
>> +{
>> + type_register_static(&sunxi_pit_info);
>> +}
>> +
>> +type_init(sunxi_register_types);
>> diff --git a/include/hw/timer/sunxi-pit.h b/include/hw/timer/sunxi-pit.h
>> new file mode 100644
>> index 0000000..38f1b4d
>> --- /dev/null
>> +++ b/include/hw/timer/sunxi-pit.h
>> @@ -0,0 +1,26 @@
>> +#ifndef SUNXI_PIT_H
>> +#define SUNXI_PIT_H
>> +
>> +
>> +#define TYPE_SUNXI_PIT "sunix-timer"
>>
> "sunxi-timer"
>
>
>> +#define SUNXI_PIT(obj) OBJECT_CHECK(SunxiPITState, (obj), TYPE_SUNXI_PIT)
>> +
>> +#define SUNXI_TIMER_NR 6
>> +#define SUNXI_TIMER_IRQ 0x1
>> +#define SUNXI_WDOG_IRQ 0x100
>> +
>> +#define SUNXI_TIMER_IRQ_EN 0
>> +#define SUNXI_TIMER_IRQ_ST 0x4
>> +#define SUNXI_TIMER_CONTROL 0x0
>> +#define SUNXI_TIMER_INTERVAL 0x4
>> +#define SUNXI_TIMER_COUNT 0x8
>> +#define SUNXI_WDOG_CONTROL 0x90
>> +#define SUNXI_WDOG_MODE 0x94
>> +#define SUNXI_COUNT_CTL 0xa0
>> +#define SUNXI_COUNT_LO 0xa4
>> +#define SUNXI_COUNT_HI 0xa8
>> +#define SUNXI_TIMER_BASE 0x10
>> +
>>
> You could tab out the numbers to a consistent tab-stop for easier reading.
>
>
reasonable, will fix.
Thanks a lot!
>> +
>> +#endif
>> +
>> --
>> 1.7.2.5
>>
>>
>>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v3 2/4] hw/intc: add sunxi interrupt controller device
2013-11-25 7:41 [Qemu-devel] [PATCH v3 0/4] add sunxi machine type liguang
2013-11-25 7:41 ` [Qemu-devel] [PATCH v3 1/4] hw/timer: add sunxi timer device liguang
@ 2013-11-25 7:41 ` liguang
2013-11-25 10:42 ` Peter Crosthwaite
2013-11-25 7:41 ` [Qemu-devel] [PATCH v3 3/4] hw/arm: add sunxi machine type liguang
2013-11-25 7:41 ` [Qemu-devel] [PATCH v3 4/4] MAINTAINERS: add myself to maintain sunxi machine liguang
3 siblings, 1 reply; 11+ messages in thread
From: liguang @ 2013-11-25 7:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, liguang
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
---
default-configs/arm-softmmu.mak | 1 +
hw/intc/Makefile.objs | 1 +
hw/intc/sunxi-pic.c | 301 +++++++++++++++++++++++++++++++++++++++
include/hw/intc/sunxi-pic.h | 27 ++++
4 files changed, 330 insertions(+), 0 deletions(-)
create mode 100644 hw/intc/sunxi-pic.c
create mode 100644 include/hw/intc/sunxi-pic.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 7bf5ad0..bbe00e4 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -83,3 +83,4 @@ CONFIG_SDHCI=y
CONFIG_INTEGRATOR_DEBUG=y
CONFIG_SUNXI_PIT=y
+CONFIG_SUNXI_PIC=y
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 47ac442..dad8c43 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -12,6 +12,7 @@ common-obj-$(CONFIG_IOAPIC) += ioapic_common.o
common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
common-obj-$(CONFIG_OPENPIC) += openpic.o
+common-obj-$(CONFIG_SUNXI_PIC) += sunxi-pic.o
obj-$(CONFIG_APIC) += apic.o apic_common.o
obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
diff --git a/hw/intc/sunxi-pic.c b/hw/intc/sunxi-pic.c
new file mode 100644
index 0000000..09a3d09
--- /dev/null
+++ b/hw/intc/sunxi-pic.c
@@ -0,0 +1,301 @@
+/*
+ * Allwinner sunxi 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/sunxi-pic.h"
+
+
+typedef struct SunxiPICState {
+ /*< 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_pending0;
+ uint32_t irq_pending1;
+ uint32_t irq_pending2;
+ uint32_t select0;
+ uint32_t select1;
+ uint32_t select2;
+ uint32_t enable0;
+ uint32_t enable1;
+ uint32_t enable2;
+ uint32_t mask0;
+ uint32_t mask1;
+ uint32_t mask2;
+ /*priority setting here*/
+} SunxiPICState;
+
+static void sunxi_pic_update(SunxiPICState *s)
+{
+ uint32_t flags = 0;
+
+ flags = s->irq_pending0 | s->irq_pending1 | s->irq_pending0;
+ qemu_set_irq(s->parent_irq, flags != 0);
+ flags &= s->select0 | s->select1 | s->select2;
+ qemu_set_irq(s->parent_fiq, flags != 0);
+}
+
+static void sunxi_pic_set_irq(void *opaque, int irq, int level)
+{
+ SunxiPICState *s = opaque;
+ bool allow_irq = false;
+
+ if (level) {
+ if (irq < 32) {
+ set_bit(irq, (void *)&s->irq_pending0);
+ if (test_bit(irq, (void *)&s->enable0) &&
+ !test_bit(irq, (void *)&s->mask0)) {
+ allow_irq = true;
+ }
+ } else if (irq < 64) {
+ irq -= 32;
+ set_bit(irq, (void *)&s->irq_pending1);
+ if (test_bit(irq, (void *)&s->enable1) &&
+ !test_bit(irq, (void *)&s->mask1)) {
+ allow_irq = true;
+ }
+ } else if (irq < 95) {
+ irq -= 64;
+ set_bit(irq, (void *)&s->irq_pending2);
+ if (test_bit(irq, (void *)&s->enable2) &&
+ !test_bit(irq, (void *)&s->mask2)) {
+ allow_irq = true;
+ }
+ }
+ } else {
+ if (irq < 32) {
+ clear_bit(irq, (void *)&s->irq_pending0);
+ } else if (irq < 64) {
+ irq -= 32;
+ clear_bit(irq, (void *)&s->irq_pending1);
+ } else if (irq < 95) {
+ irq -= 64;
+ clear_bit(irq, (void *)&s->irq_pending2);
+ }
+ }
+ if (allow_irq) {
+ sunxi_pic_update(s);
+ }
+}
+
+static uint64_t sunxi_pic_read(void *opaque, hwaddr offset, unsigned size)
+{
+ SunxiPICState *s = opaque;
+
+ switch (offset) {
+ case PIC_VECTOR:
+ return s->vector;
+ break;
+ case PIC_BASE_ADDR:
+ return s->base_addr;
+ break;
+ case PIC_PROTECT:
+ return s->protect;
+ break;
+ case PIC_NMI:
+ return s->nmi;
+ break;
+ case PIC_IRQ_PENDING0:
+ case PIC_FIQ_PENDING0:
+ return s->irq_pending0;
+ break;
+ case PIC_IRQ_PENDING1:
+ case PIC_FIQ_PENDING1:
+ return s->irq_pending1;
+ break;
+ case PIC_IRQ_PENDING2:
+ case PIC_FIQ_PENDING2:
+ return s->irq_pending2;
+ break;
+ case PIC_SELECT0:
+ return s->select0;
+ break;
+ case PIC_SELECT1:
+ return s->select1;
+ break;
+ case PIC_SELECT2:
+ return s->select2;
+ break;
+ case PIC_ENABLE0:
+ return s->enable0;
+ break;
+ case PIC_ENABLE1:
+ return s->enable1;
+ break;
+ case PIC_ENABLE2:
+ return s->enable2;
+ break;
+ case PIC_MASK0:
+ return s->mask0;
+ break;
+ case PIC_MASK1:
+ return s->mask1;
+ break;
+ case PIC_MASK2:
+ return s->mask2;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void sunxi_pic_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ SunxiPICState *s = opaque;
+ uint8_t index = 0;
+
+ switch (offset) {
+ case PIC_VECTOR:
+ s->vector = value & ~0x3;
+ break;
+ case PIC_BASE_ADDR:
+ s->base_addr = value & ~0x3;
+ case PIC_PROTECT:
+ case PIC_NMI:
+ break;
+ case PIC_IRQ_PENDING0:
+ case PIC_FIQ_PENDING0:
+ for (index = 0; index < 32; index++) {
+ if (test_bit(index, (void *)&value)) {
+ clear_bit(index, (void *)&s->irq_pending0);
+ }
+ }
+ break;
+ case PIC_IRQ_PENDING1:
+ case PIC_FIQ_PENDING1:
+ for (index = 0; index < 32; index++) {
+ if (test_bit(index, (void *)&value)) {
+ clear_bit(index, (void *)&s->irq_pending1);
+ }
+ }
+ break;
+ case PIC_IRQ_PENDING2:
+ case PIC_FIQ_PENDING2:
+ for (index = 0; index < 32; index++) {
+ if (test_bit(index, (void *)&value)) {
+ clear_bit(index, (void *)&s->irq_pending2);
+ }
+ }
+ break;
+ case PIC_SELECT0:
+ s->select0 = value;
+ break;
+ case PIC_SELECT1:
+ s->select1 = value;
+ break;
+ case PIC_SELECT2:
+ s->select2 = value;
+ break;
+ case PIC_ENABLE0:
+ s->enable0 = value;
+ break;
+ case PIC_ENABLE1:
+ s->enable1 = value;
+ break;
+ case PIC_ENABLE2:
+ s->enable2 = value;
+ break;
+ case PIC_MASK0:
+ s->mask0 = value;
+ break;
+ case PIC_MASK1:
+ s->mask1 = value;
+ break;
+ case PIC_MASK2:
+ s->mask2 = value;
+ default:
+ break;
+ }
+
+ sunxi_pic_update(s);
+}
+
+static const MemoryRegionOps sunxi_pic_ops = {
+ .read = sunxi_pic_read,
+ .write = sunxi_pic_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int sunxi_pic_init(SysBusDevice *dev)
+{
+ SunxiPICState *s = SUNXI_PIC(dev);
+
+ qdev_init_gpio_in(DEVICE(dev), sunxi_pic_set_irq, 95);
+ sysbus_init_irq(dev, &s->parent_irq);
+ sysbus_init_irq(dev, &s->parent_fiq);
+ memory_region_init_io(&s->iomem, OBJECT(s), &sunxi_pic_ops, s,
+ "sunxi-pic", 0x400);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void sunxi_pic_reset(DeviceState *d)
+{
+ SunxiPICState *s = SUNXI_PIC(d);
+
+ s->base_addr = 0;
+ s->protect = 0;
+ s->nmi = 0;
+ s->vector = 0;
+ s->irq_pending0 = 0;
+ s->irq_pending1 = 0;
+ s->irq_pending2 = 0;
+ s->select0 = 0;
+ s->select1 = 0;
+ s->select2 = 0;
+ s->enable0 = 0;
+ s->enable1 = 0;
+ s->enable2 = 0;
+ s->mask0 = 0;
+ s->mask1 = 0;
+ s->mask2 = 0;
+}
+
+static void sunxi_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sunxi_pic_init;
+ dc->reset = sunxi_pic_reset;
+ }
+
+static const TypeInfo sunxi_pic_info = {
+ .name = TYPE_SUNXI_PIC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SunxiPICState),
+ .class_init = sunxi_pic_class_init,
+};
+
+static void sunxi_register_types(void)
+{
+ type_register_static(&sunxi_pic_info);
+}
+
+type_init(sunxi_register_types);
diff --git a/include/hw/intc/sunxi-pic.h b/include/hw/intc/sunxi-pic.h
new file mode 100644
index 0000000..fd07b33
--- /dev/null
+++ b/include/hw/intc/sunxi-pic.h
@@ -0,0 +1,27 @@
+#ifndef SUNXI_PIC_H
+#define SUNXI_PIC_H
+
+#define TYPE_SUNXI_PIC "sunxi_PIC"
+#define SUNXI_PIC(obj) OBJECT_CHECK(SunxiPICState, (obj), TYPE_SUNXI_PIC)
+
+#define PIC_VECTOR 0
+#define PIC_BASE_ADDR 4
+#define PIC_PROTECT 8
+#define PIC_NMI 0xc
+#define PIC_IRQ_PENDING0 0x10
+#define PIC_IRQ_PENDING1 0x14
+#define PIC_IRQ_PENDING2 0x18
+#define PIC_FIQ_PENDING0 0x20
+#define PIC_FIQ_PENDING1 0x24
+#define PIC_FIQ_PENDING2 0x28
+#define PIC_SELECT0 0x30
+#define PIC_SELECT1 0x34
+#define PIC_SELECT2 0x38
+#define PIC_ENABLE0 0x40
+#define PIC_ENABLE1 0x44
+#define PIC_ENABLE2 0x48
+#define PIC_MASK0 0x50
+#define PIC_MASK1 0x54
+#define PIC_MASK2 0x58
+
+#endif
--
1.7.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v3 2/4] hw/intc: add sunxi interrupt controller device
2013-11-25 7:41 ` [Qemu-devel] [PATCH v3 2/4] hw/intc: add sunxi interrupt controller device liguang
@ 2013-11-25 10:42 ` Peter Crosthwaite
2013-11-26 0:45 ` Li Guang
0 siblings, 1 reply; 11+ messages in thread
From: Peter Crosthwaite @ 2013-11-25 10:42 UTC (permalink / raw)
To: liguang; +Cc: Peter Maydell, qemu-devel@nongnu.org Developers
On Mon, Nov 25, 2013 at 5:41 PM, liguang <lig.fnst@cn.fujitsu.com> wrote:
> Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
> ---
> default-configs/arm-softmmu.mak | 1 +
> hw/intc/Makefile.objs | 1 +
> hw/intc/sunxi-pic.c | 301 +++++++++++++++++++++++++++++++++++++++
> include/hw/intc/sunxi-pic.h | 27 ++++
> 4 files changed, 330 insertions(+), 0 deletions(-)
> create mode 100644 hw/intc/sunxi-pic.c
> create mode 100644 include/hw/intc/sunxi-pic.h
>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index 7bf5ad0..bbe00e4 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -83,3 +83,4 @@ CONFIG_SDHCI=y
> CONFIG_INTEGRATOR_DEBUG=y
>
> CONFIG_SUNXI_PIT=y
> +CONFIG_SUNXI_PIC=y
> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
> index 47ac442..dad8c43 100644
> --- a/hw/intc/Makefile.objs
> +++ b/hw/intc/Makefile.objs
> @@ -12,6 +12,7 @@ common-obj-$(CONFIG_IOAPIC) += ioapic_common.o
> common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
> common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
> common-obj-$(CONFIG_OPENPIC) += openpic.o
> +common-obj-$(CONFIG_SUNXI_PIC) += sunxi-pic.o
>
> obj-$(CONFIG_APIC) += apic.o apic_common.o
> obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
> diff --git a/hw/intc/sunxi-pic.c b/hw/intc/sunxi-pic.c
> new file mode 100644
> index 0000000..09a3d09
> --- /dev/null
> +++ b/hw/intc/sunxi-pic.c
> @@ -0,0 +1,301 @@
> +/*
> + * Allwinner sunxi 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/sunxi-pic.h"
> +
> +
> +typedef struct SunxiPICState {
> + /*< 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_pending0;
> + uint32_t irq_pending1;
> + uint32_t irq_pending2;
> + uint32_t select0;
> + uint32_t select1;
> + uint32_t select2;
> + uint32_t enable0;
> + uint32_t enable1;
> + uint32_t enable2;
> + uint32_t mask0;
> + uint32_t mask1;
> + uint32_t mask2;
> + /*priority setting here*/
> +} SunxiPICState;
> +
> +static void sunxi_pic_update(SunxiPICState *s)
> +{
> + uint32_t flags = 0;
initializer to 0 not needed.
> +
> + flags = s->irq_pending0 | s->irq_pending1 | s->irq_pending0;
> + qemu_set_irq(s->parent_irq, flags != 0);
> + flags &= s->select0 | s->select1 | s->select2;
> + qemu_set_irq(s->parent_fiq, flags != 0);
This logic seems strange to me, in that that behavior of individual
interrupts is not self contained.
e.g. if interrupt 0 (bit 0 of irq_pending0) is pending and interrupt
32 is selected (bit 0 of select1) then flags is non-zero regardless of
state of bit 0 of s->select0). Whats the intended behavior of the
select bits?
If an interrupt is "selected" it will also route to both IRQ and FIQ it seems.
> +}
> +
> +static void sunxi_pic_set_irq(void *opaque, int irq, int level)
> +{
> + SunxiPICState *s = opaque;
> + bool allow_irq = false;
> +
> + if (level) {
> + if (irq < 32) {
> + set_bit(irq, (void *)&s->irq_pending0);
> + if (test_bit(irq, (void *)&s->enable0) &&
> + !test_bit(irq, (void *)&s->mask0)) {
> + allow_irq = true;
this check inhibits immediate interrupt generation of masked intr, but
it doesnt stop a future event from triggering the IRQ. Should the
enable and mask checks be in the interrupt generation code?
For example, your bus write handler calls sunxi_pic_update() which
means these pending-but-masked interrupts will potentially cause the
irq to raise at bus write time.
> + }
> + } else if (irq < 64) {
> + irq -= 32;
> + set_bit(irq, (void *)&s->irq_pending1);
> + if (test_bit(irq, (void *)&s->enable1) &&
> + !test_bit(irq, (void *)&s->mask1)) {
> + allow_irq = true;
> + }
> + } else if (irq < 95) {
> + irq -= 64;
> + set_bit(irq, (void *)&s->irq_pending2);
> + if (test_bit(irq, (void *)&s->enable2) &&
> + !test_bit(irq, (void *)&s->mask2)) {
> + allow_irq = true;
> + }
> + }
> + } else {
> + if (irq < 32) {
> + clear_bit(irq, (void *)&s->irq_pending0);
> + } else if (irq < 64) {
> + irq -= 32;
> + clear_bit(irq, (void *)&s->irq_pending1);
> + } else if (irq < 95) {
> + irq -= 64;
> + clear_bit(irq, (void *)&s->irq_pending2);
> + }
> + }
> + if (allow_irq) {
> + sunxi_pic_update(s);
> + }
> +}
> +
> +static uint64_t sunxi_pic_read(void *opaque, hwaddr offset, unsigned size)
> +{
> + SunxiPICState *s = opaque;
> +
> + switch (offset) {
> + case PIC_VECTOR:
> + return s->vector;
> + break;
> + case PIC_BASE_ADDR:
> + return s->base_addr;
> + break;
> + case PIC_PROTECT:
> + return s->protect;
> + break;
> + case PIC_NMI:
> + return s->nmi;
> + break;
> + case PIC_IRQ_PENDING0:
> + case PIC_FIQ_PENDING0:
> + return s->irq_pending0;
> + break;
> + case PIC_IRQ_PENDING1:
> + case PIC_FIQ_PENDING1:
> + return s->irq_pending1;
> + break;
> + case PIC_IRQ_PENDING2:
> + case PIC_FIQ_PENDING2:
> + return s->irq_pending2;
> + break;
> + case PIC_SELECT0:
> + return s->select0;
> + break;
> + case PIC_SELECT1:
> + return s->select1;
> + break;
> + case PIC_SELECT2:
> + return s->select2;
> + break;
> + case PIC_ENABLE0:
> + return s->enable0;
> + break;
> + case PIC_ENABLE1:
> + return s->enable1;
> + break;
> + case PIC_ENABLE2:
> + return s->enable2;
> + break;
> + case PIC_MASK0:
> + return s->mask0;
> + break;
> + case PIC_MASK1:
> + return s->mask1;
> + break;
> + case PIC_MASK2:
> + return s->mask2;
> + break;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static void sunxi_pic_write(void *opaque, hwaddr offset, uint64_t value,
> + unsigned size)
> +{
> + SunxiPICState *s = opaque;
> + uint8_t index = 0;
> +
> + switch (offset) {
> + case PIC_VECTOR:
> + s->vector = value & ~0x3;
> + break;
> + case PIC_BASE_ADDR:
> + s->base_addr = value & ~0x3;
> + case PIC_PROTECT:
> + case PIC_NMI:
> + break;
> + case PIC_IRQ_PENDING0:
> + case PIC_FIQ_PENDING0:
> + for (index = 0; index < 32; index++) {
> + if (test_bit(index, (void *)&value)) {
> + clear_bit(index, (void *)&s->irq_pending0);
> + }
&= ~foo to implement write to clear.
> + }
> + break;
> + case PIC_IRQ_PENDING1:
> + case PIC_FIQ_PENDING1:
> + for (index = 0; index < 32; index++) {
> + if (test_bit(index, (void *)&value)) {
> + clear_bit(index, (void *)&s->irq_pending1);
> + }
> + }
> + break;
> + case PIC_IRQ_PENDING2:
> + case PIC_FIQ_PENDING2:
> + for (index = 0; index < 32; index++) {
> + if (test_bit(index, (void *)&value)) {
> + clear_bit(index, (void *)&s->irq_pending2);
> + }
> + }
> + break;
> + case PIC_SELECT0:
> + s->select0 = value;
> + break;
> + case PIC_SELECT1:
> + s->select1 = value;
> + break;
> + case PIC_SELECT2:
> + s->select2 = value;
> + break;
> + case PIC_ENABLE0:
> + s->enable0 = value;
> + break;
> + case PIC_ENABLE1:
> + s->enable1 = value;
> + break;
> + case PIC_ENABLE2:
> + s->enable2 = value;
> + break;
> + case PIC_MASK0:
> + s->mask0 = value;
> + break;
> + case PIC_MASK1:
> + s->mask1 = value;
> + break;
> + case PIC_MASK2:
> + s->mask2 = value;
You can make this much shorter by making the reigsters an array, and
indexing into it using offset for the default case.
> + default:
> + break;
> + }
> +
> + sunxi_pic_update(s);
> +}
> +
> +static const MemoryRegionOps sunxi_pic_ops = {
> + .read = sunxi_pic_read,
> + .write = sunxi_pic_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static int sunxi_pic_init(SysBusDevice *dev)
> +{
> + SunxiPICState *s = SUNXI_PIC(dev);
> +
> + qdev_init_gpio_in(DEVICE(dev), sunxi_pic_set_irq, 95);
> + sysbus_init_irq(dev, &s->parent_irq);
> + sysbus_init_irq(dev, &s->parent_fiq);
> + memory_region_init_io(&s->iomem, OBJECT(s), &sunxi_pic_ops, s,
> + "sunxi-pic", 0x400);
> + sysbus_init_mmio(dev, &s->iomem);
> +
> + return 0;
> +}
> +
> +static void sunxi_pic_reset(DeviceState *d)
> +{
> + SunxiPICState *s = SUNXI_PIC(d);
> +
> + s->base_addr = 0;
> + s->protect = 0;
> + s->nmi = 0;
> + s->vector = 0;
> + s->irq_pending0 = 0;
> + s->irq_pending1 = 0;
> + s->irq_pending2 = 0;
> + s->select0 = 0;
> + s->select1 = 0;
> + s->select2 = 0;
> + s->enable0 = 0;
> + s->enable1 = 0;
> + s->enable2 = 0;
> + s->mask0 = 0;
> + s->mask1 = 0;
> + s->mask2 = 0;
> +}
> +
> +static void sunxi_pic_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> +
> + k->init = sunxi_pic_init;
Use of SysBusDevice::init is depracated. Please use Device::realize or
the object init instead. With no properties deps, I think the latter
is more correct.
> + dc->reset = sunxi_pic_reset;
missing VMSD support.
> + }
> +
> +static const TypeInfo sunxi_pic_info = {
> + .name = TYPE_SUNXI_PIC,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(SunxiPICState),
> + .class_init = sunxi_pic_class_init,
> +};
> +
> +static void sunxi_register_types(void)
> +{
> + type_register_static(&sunxi_pic_info);
> +}
> +
> +type_init(sunxi_register_types);
> diff --git a/include/hw/intc/sunxi-pic.h b/include/hw/intc/sunxi-pic.h
> new file mode 100644
> index 0000000..fd07b33
> --- /dev/null
> +++ b/include/hw/intc/sunxi-pic.h
> @@ -0,0 +1,27 @@
> +#ifndef SUNXI_PIC_H
> +#define SUNXI_PIC_H
> +
> +#define TYPE_SUNXI_PIC "sunxi_PIC"
I think -'s are encouraged over _'s. The casing should be made
consistent as well.
Regards,
Peter
> +#define SUNXI_PIC(obj) OBJECT_CHECK(SunxiPICState, (obj), TYPE_SUNXI_PIC)
> +
> +#define PIC_VECTOR 0
> +#define PIC_BASE_ADDR 4
> +#define PIC_PROTECT 8
> +#define PIC_NMI 0xc
> +#define PIC_IRQ_PENDING0 0x10
> +#define PIC_IRQ_PENDING1 0x14
> +#define PIC_IRQ_PENDING2 0x18
> +#define PIC_FIQ_PENDING0 0x20
> +#define PIC_FIQ_PENDING1 0x24
> +#define PIC_FIQ_PENDING2 0x28
> +#define PIC_SELECT0 0x30
> +#define PIC_SELECT1 0x34
> +#define PIC_SELECT2 0x38
> +#define PIC_ENABLE0 0x40
> +#define PIC_ENABLE1 0x44
> +#define PIC_ENABLE2 0x48
> +#define PIC_MASK0 0x50
> +#define PIC_MASK1 0x54
> +#define PIC_MASK2 0x58
> +
> +#endif
> --
> 1.7.2.5
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v3 2/4] hw/intc: add sunxi interrupt controller device
2013-11-25 10:42 ` Peter Crosthwaite
@ 2013-11-26 0:45 ` Li Guang
0 siblings, 0 replies; 11+ messages in thread
From: Li Guang @ 2013-11-26 0:45 UTC (permalink / raw)
To: Peter Crosthwaite; +Cc: Peter Maydell, qemu-devel@nongnu.org Developers
Peter Crosthwaite wrote:
> On Mon, Nov 25, 2013 at 5:41 PM, liguang<lig.fnst@cn.fujitsu.com> wrote:
>
>> Signed-off-by: liguang<lig.fnst@cn.fujitsu.com>
>> ---
>> default-configs/arm-softmmu.mak | 1 +
>> hw/intc/Makefile.objs | 1 +
>> hw/intc/sunxi-pic.c | 301 +++++++++++++++++++++++++++++++++++++++
>> include/hw/intc/sunxi-pic.h | 27 ++++
>> 4 files changed, 330 insertions(+), 0 deletions(-)
>> create mode 100644 hw/intc/sunxi-pic.c
>> create mode 100644 include/hw/intc/sunxi-pic.h
>>
>> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
>> index 7bf5ad0..bbe00e4 100644
>> --- a/default-configs/arm-softmmu.mak
>> +++ b/default-configs/arm-softmmu.mak
>> @@ -83,3 +83,4 @@ CONFIG_SDHCI=y
>> CONFIG_INTEGRATOR_DEBUG=y
>>
>> CONFIG_SUNXI_PIT=y
>> +CONFIG_SUNXI_PIC=y
>> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
>> index 47ac442..dad8c43 100644
>> --- a/hw/intc/Makefile.objs
>> +++ b/hw/intc/Makefile.objs
>> @@ -12,6 +12,7 @@ common-obj-$(CONFIG_IOAPIC) += ioapic_common.o
>> common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
>> common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
>> common-obj-$(CONFIG_OPENPIC) += openpic.o
>> +common-obj-$(CONFIG_SUNXI_PIC) += sunxi-pic.o
>>
>> obj-$(CONFIG_APIC) += apic.o apic_common.o
>> obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
>> diff --git a/hw/intc/sunxi-pic.c b/hw/intc/sunxi-pic.c
>> new file mode 100644
>> index 0000000..09a3d09
>> --- /dev/null
>> +++ b/hw/intc/sunxi-pic.c
>> @@ -0,0 +1,301 @@
>> +/*
>> + * Allwinner sunxi 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/sunxi-pic.h"
>> +
>> +
>> +typedef struct SunxiPICState {
>> + /*< 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_pending0;
>> + uint32_t irq_pending1;
>> + uint32_t irq_pending2;
>> + uint32_t select0;
>> + uint32_t select1;
>> + uint32_t select2;
>> + uint32_t enable0;
>> + uint32_t enable1;
>> + uint32_t enable2;
>> + uint32_t mask0;
>> + uint32_t mask1;
>> + uint32_t mask2;
>> + /*priority setting here*/
>> +} SunxiPICState;
>> +
>> +static void sunxi_pic_update(SunxiPICState *s)
>> +{
>> + uint32_t flags = 0;
>>
> initializer to 0 not needed.
>
>
>> +
>> + flags = s->irq_pending0 | s->irq_pending1 | s->irq_pending0;
>> + qemu_set_irq(s->parent_irq, flags != 0);
>> + flags&= s->select0 | s->select1 | s->select2;
>> + qemu_set_irq(s->parent_fiq, flags != 0);
>>
> This logic seems strange to me, in that that behavior of individual
> interrupts is not self contained.
>
> e.g. if interrupt 0 (bit 0 of irq_pending0) is pending and interrupt
> 32 is selected (bit 0 of select1) then flags is non-zero regardless of
> state of bit 0 of s->select0). Whats the intended behavior of the
> select bits?
>
> If an interrupt is "selected" it will also route to both IRQ and FIQ it seems.
>
>
>> +}
>> +
>> +static void sunxi_pic_set_irq(void *opaque, int irq, int level)
>> +{
>> + SunxiPICState *s = opaque;
>> + bool allow_irq = false;
>> +
>> + if (level) {
>> + if (irq< 32) {
>> + set_bit(irq, (void *)&s->irq_pending0);
>> + if (test_bit(irq, (void *)&s->enable0)&&
>> + !test_bit(irq, (void *)&s->mask0)) {
>> + allow_irq = true;
>>
> this check inhibits immediate interrupt generation of masked intr, but
> it doesnt stop a future event from triggering the IRQ. Should the
> enable and mask checks be in the interrupt generation code?
>
> For example, your bus write handler calls sunxi_pic_update() which
> means these pending-but-masked interrupts will potentially cause the
> irq to raise at bus write time.
>
>
>> + }
>> + } else if (irq< 64) {
>> + irq -= 32;
>> + set_bit(irq, (void *)&s->irq_pending1);
>> + if (test_bit(irq, (void *)&s->enable1)&&
>> + !test_bit(irq, (void *)&s->mask1)) {
>> + allow_irq = true;
>> + }
>> + } else if (irq< 95) {
>> + irq -= 64;
>> + set_bit(irq, (void *)&s->irq_pending2);
>> + if (test_bit(irq, (void *)&s->enable2)&&
>> + !test_bit(irq, (void *)&s->mask2)) {
>> + allow_irq = true;
>> + }
>> + }
>> + } else {
>> + if (irq< 32) {
>> + clear_bit(irq, (void *)&s->irq_pending0);
>> + } else if (irq< 64) {
>> + irq -= 32;
>> + clear_bit(irq, (void *)&s->irq_pending1);
>> + } else if (irq< 95) {
>> + irq -= 64;
>> + clear_bit(irq, (void *)&s->irq_pending2);
>> + }
>> + }
>> + if (allow_irq) {
>> + sunxi_pic_update(s);
>> + }
>> +}
>> +
>> +static uint64_t sunxi_pic_read(void *opaque, hwaddr offset, unsigned size)
>> +{
>> + SunxiPICState *s = opaque;
>> +
>> + switch (offset) {
>> + case PIC_VECTOR:
>> + return s->vector;
>> + break;
>> + case PIC_BASE_ADDR:
>> + return s->base_addr;
>> + break;
>> + case PIC_PROTECT:
>> + return s->protect;
>> + break;
>> + case PIC_NMI:
>> + return s->nmi;
>> + break;
>> + case PIC_IRQ_PENDING0:
>> + case PIC_FIQ_PENDING0:
>> + return s->irq_pending0;
>> + break;
>> + case PIC_IRQ_PENDING1:
>> + case PIC_FIQ_PENDING1:
>> + return s->irq_pending1;
>> + break;
>> + case PIC_IRQ_PENDING2:
>> + case PIC_FIQ_PENDING2:
>> + return s->irq_pending2;
>> + break;
>> + case PIC_SELECT0:
>> + return s->select0;
>> + break;
>> + case PIC_SELECT1:
>> + return s->select1;
>> + break;
>> + case PIC_SELECT2:
>> + return s->select2;
>> + break;
>> + case PIC_ENABLE0:
>> + return s->enable0;
>> + break;
>> + case PIC_ENABLE1:
>> + return s->enable1;
>> + break;
>> + case PIC_ENABLE2:
>> + return s->enable2;
>> + break;
>> + case PIC_MASK0:
>> + return s->mask0;
>> + break;
>> + case PIC_MASK1:
>> + return s->mask1;
>> + break;
>> + case PIC_MASK2:
>> + return s->mask2;
>> + break;
>> + default:
>> + break;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void sunxi_pic_write(void *opaque, hwaddr offset, uint64_t value,
>> + unsigned size)
>> +{
>> + SunxiPICState *s = opaque;
>> + uint8_t index = 0;
>> +
>> + switch (offset) {
>> + case PIC_VECTOR:
>> + s->vector = value& ~0x3;
>> + break;
>> + case PIC_BASE_ADDR:
>> + s->base_addr = value& ~0x3;
>> + case PIC_PROTECT:
>> + case PIC_NMI:
>> + break;
>> + case PIC_IRQ_PENDING0:
>> + case PIC_FIQ_PENDING0:
>> + for (index = 0; index< 32; index++) {
>> + if (test_bit(index, (void *)&value)) {
>> + clear_bit(index, (void *)&s->irq_pending0);
>> + }
>>
> &= ~foo to implement write to clear.
>
>
>> + }
>> + break;
>> + case PIC_IRQ_PENDING1:
>> + case PIC_FIQ_PENDING1:
>> + for (index = 0; index< 32; index++) {
>> + if (test_bit(index, (void *)&value)) {
>> + clear_bit(index, (void *)&s->irq_pending1);
>> + }
>> + }
>> + break;
>> + case PIC_IRQ_PENDING2:
>> + case PIC_FIQ_PENDING2:
>> + for (index = 0; index< 32; index++) {
>> + if (test_bit(index, (void *)&value)) {
>> + clear_bit(index, (void *)&s->irq_pending2);
>> + }
>> + }
>> + break;
>> + case PIC_SELECT0:
>> + s->select0 = value;
>> + break;
>> + case PIC_SELECT1:
>> + s->select1 = value;
>> + break;
>> + case PIC_SELECT2:
>> + s->select2 = value;
>> + break;
>> + case PIC_ENABLE0:
>> + s->enable0 = value;
>> + break;
>> + case PIC_ENABLE1:
>> + s->enable1 = value;
>> + break;
>> + case PIC_ENABLE2:
>> + s->enable2 = value;
>> + break;
>> + case PIC_MASK0:
>> + s->mask0 = value;
>> + break;
>> + case PIC_MASK1:
>> + s->mask1 = value;
>> + break;
>> + case PIC_MASK2:
>> + s->mask2 = value;
>>
> You can make this much shorter by making the reigsters an array, and
> indexing into it using offset for the default case.
>
>
>> + default:
>> + break;
>> + }
>> +
>> + sunxi_pic_update(s);
>> +}
>> +
>> +static const MemoryRegionOps sunxi_pic_ops = {
>> + .read = sunxi_pic_read,
>> + .write = sunxi_pic_write,
>> + .endianness = DEVICE_NATIVE_ENDIAN,
>> +};
>> +
>> +static int sunxi_pic_init(SysBusDevice *dev)
>> +{
>> + SunxiPICState *s = SUNXI_PIC(dev);
>> +
>> + qdev_init_gpio_in(DEVICE(dev), sunxi_pic_set_irq, 95);
>> + sysbus_init_irq(dev,&s->parent_irq);
>> + sysbus_init_irq(dev,&s->parent_fiq);
>> + memory_region_init_io(&s->iomem, OBJECT(s),&sunxi_pic_ops, s,
>> + "sunxi-pic", 0x400);
>> + sysbus_init_mmio(dev,&s->iomem);
>> +
>> + return 0;
>> +}
>> +
>> +static void sunxi_pic_reset(DeviceState *d)
>> +{
>> + SunxiPICState *s = SUNXI_PIC(d);
>> +
>> + s->base_addr = 0;
>> + s->protect = 0;
>> + s->nmi = 0;
>> + s->vector = 0;
>> + s->irq_pending0 = 0;
>> + s->irq_pending1 = 0;
>> + s->irq_pending2 = 0;
>> + s->select0 = 0;
>> + s->select1 = 0;
>> + s->select2 = 0;
>> + s->enable0 = 0;
>> + s->enable1 = 0;
>> + s->enable2 = 0;
>> + s->mask0 = 0;
>> + s->mask1 = 0;
>> + s->mask2 = 0;
>> +}
>> +
>> +static void sunxi_pic_class_init(ObjectClass *klass, void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
>> +
>> + k->init = sunxi_pic_init;
>>
> Use of SysBusDevice::init is depracated. Please use Device::realize or
> the object init instead. With no properties deps, I think the latter
> is more correct.
>
>
>> + dc->reset = sunxi_pic_reset;
>>
> missing VMSD support.
>
>
>> + }
>> +
>> +static const TypeInfo sunxi_pic_info = {
>> + .name = TYPE_SUNXI_PIC,
>> + .parent = TYPE_SYS_BUS_DEVICE,
>> + .instance_size = sizeof(SunxiPICState),
>> + .class_init = sunxi_pic_class_init,
>> +};
>> +
>> +static void sunxi_register_types(void)
>> +{
>> + type_register_static(&sunxi_pic_info);
>> +}
>> +
>> +type_init(sunxi_register_types);
>> diff --git a/include/hw/intc/sunxi-pic.h b/include/hw/intc/sunxi-pic.h
>> new file mode 100644
>> index 0000000..fd07b33
>> --- /dev/null
>> +++ b/include/hw/intc/sunxi-pic.h
>> @@ -0,0 +1,27 @@
>> +#ifndef SUNXI_PIC_H
>> +#define SUNXI_PIC_H
>> +
>> +#define TYPE_SUNXI_PIC "sunxi_PIC"
>>
> I think -'s are encouraged over _'s. The casing should be made
> consistent as well.
>
>
All are reasonable, will fix.
Thanks a lot!
>
>> +#define SUNXI_PIC(obj) OBJECT_CHECK(SunxiPICState, (obj), TYPE_SUNXI_PIC)
>> +
>> +#define PIC_VECTOR 0
>> +#define PIC_BASE_ADDR 4
>> +#define PIC_PROTECT 8
>> +#define PIC_NMI 0xc
>> +#define PIC_IRQ_PENDING0 0x10
>> +#define PIC_IRQ_PENDING1 0x14
>> +#define PIC_IRQ_PENDING2 0x18
>> +#define PIC_FIQ_PENDING0 0x20
>> +#define PIC_FIQ_PENDING1 0x24
>> +#define PIC_FIQ_PENDING2 0x28
>> +#define PIC_SELECT0 0x30
>> +#define PIC_SELECT1 0x34
>> +#define PIC_SELECT2 0x38
>> +#define PIC_ENABLE0 0x40
>> +#define PIC_ENABLE1 0x44
>> +#define PIC_ENABLE2 0x48
>> +#define PIC_MASK0 0x50
>> +#define PIC_MASK1 0x54
>> +#define PIC_MASK2 0x58
>> +
>> +#endif
>> --
>> 1.7.2.5
>>
>>
>>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v3 3/4] hw/arm: add sunxi machine type
2013-11-25 7:41 [Qemu-devel] [PATCH v3 0/4] add sunxi machine type liguang
2013-11-25 7:41 ` [Qemu-devel] [PATCH v3 1/4] hw/timer: add sunxi timer device liguang
2013-11-25 7:41 ` [Qemu-devel] [PATCH v3 2/4] hw/intc: add sunxi interrupt controller device liguang
@ 2013-11-25 7:41 ` liguang
2013-11-25 10:45 ` Peter Crosthwaite
2013-11-25 7:41 ` [Qemu-devel] [PATCH v3 4/4] MAINTAINERS: add myself to maintain sunxi machine liguang
3 siblings, 1 reply; 11+ messages in thread
From: liguang @ 2013-11-25 7:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, liguang
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
---
hw/arm/Makefile.objs | 1 +
hw/arm/sunxi-soc.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 114 insertions(+), 0 deletions(-)
create mode 100644 hw/arm/sunxi-soc.c
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 3671b42..f9f3071 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -5,3 +5,4 @@ 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 += sunxi-soc.o
diff --git a/hw/arm/sunxi-soc.c b/hw/arm/sunxi-soc.c
new file mode 100644
index 0000000..857b0ab
--- /dev/null
+++ b/hw/arm/sunxi-soc.c
@@ -0,0 +1,113 @@
+/*
+ * Allwinner sunxi series SoC 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 "hw/boards.h"
+#include "hw/arm/arm.h"
+#include "hw/ptimer.h"
+#include "hw/char/serial.h"
+#include "hw/timer/sunxi-pit.h"
+#include "hw/intc/sunxi-pic.h"
+
+#include "sysemu/sysemu.h"
+#include "exec/address-spaces.h"
+
+
+#define SUNXI_PIC_REG_BASE 0x01c20400
+#define SUNXI_PIT_REG_BASE 0x01c20c00
+#define SUNXI_UART0_REG_BASE 0x01c28000
+
+static struct arm_boot_info sunxi_binfo = {
+ .loader_start = 0x40000000,
+ .board_id = 0x1008,
+};
+
+static void sunxi_init(QEMUMachineInitArgs *args)
+{
+ ram_addr_t ram_size = args->ram_size;
+ const char *cpu_model = args->cpu_model;
+ const char *kernel_filename = args->kernel_filename;
+ const char *kernel_cmdline = args->kernel_cmdline;
+ ARMCPU *cpu;
+ MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *ram = g_new(MemoryRegion, 1);
+ MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
+ qemu_irq pic[95];
+ DeviceState *dev;
+ uint8_t i;
+
+ /*here we currently support sunxi-4i*/
+ cpu_model = "cortex-a8";
+ cpu = cpu_arm_init(cpu_model);
+ if (!cpu) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+
+ memory_region_init_ram(ram, NULL, "sunxi-soc.ram", ram_size);
+ memory_region_add_subregion(address_space_mem, 0, ram);
+ memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
+ memory_region_add_subregion(address_space_mem, 0x40000000, ram_alias);
+
+ dev = sysbus_create_varargs(TYPE_SUNXI_PIC, SUNXI_PIC_REG_BASE,
+ qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
+ qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
+ NULL);
+ for (i = 0; i < 95; i++) {
+ pic[i] = qdev_get_gpio_in(dev, i);
+ }
+
+ sysbus_create_varargs(TYPE_SUNXI_PIT, SUNXI_PIT_REG_BASE, pic[22], pic[23],
+ pic[24], pic[25], pic[67], pic[68], NULL);
+
+ serial_mm_init(address_space_mem, SUNXI_UART0_REG_BASE, 2, pic[1], 115200,
+ serial_hds[0], DEVICE_NATIVE_ENDIAN);
+/*
+ serial_mm_init(address_space_mem, SUNXI_UART1_REG_BASE, 2, pic[2], 115200,
+ serial_hds[0], DEVICE_NATIVE_ENDIAN);
+ serial_mm_init(address_space_mem, SUNXI_UART2_REG_BASE, 2, pic[3], 115200,
+ serial_hds[0], DEVICE_NATIVE_ENDIAN);
+ serial_mm_init(address_space_mem, SUNXI_UART3_REG_BASE, 2, pic[4], 115200,
+ serial_hds[0], DEVICE_NATIVE_ENDIAN);
+ serial_mm_init(address_space_mem, SUNXI_UART4_REG_BASE, 2, pic[17], 115200,
+ serial_hds[0], DEVICE_NATIVE_ENDIAN);
+ serial_mm_init(address_space_mem, SUNXI_UART5_REG_BASE, 2, pic[18], 115200,
+ serial_hds[0], DEVICE_NATIVE_ENDIAN);
+ serial_mm_init(address_space_mem, SUNXI_UART6_REG_BASE, 2, pic[19], 115200,
+ serial_hds[0], DEVICE_NATIVE_ENDIAN);
+ serial_mm_init(address_space_mem, SUNXI_UART7_REG_BASE, 2, pic[20], 115200,
+ serial_hds[0], DEVICE_NATIVE_ENDIAN);
+*/
+ sunxi_binfo.ram_size = ram_size;
+ sunxi_binfo.kernel_filename = kernel_filename;
+ sunxi_binfo.kernel_cmdline = kernel_cmdline;
+ arm_load_kernel(cpu, &sunxi_binfo);
+}
+
+static QEMUMachine sunxi_machine = {
+ .name = "sunxi",
+ .desc = "Allwinner's SoC (sunxi series)",
+ .init = sunxi_init,
+};
+
+static void sunxi_machine_init(void)
+{
+ qemu_register_machine(&sunxi_machine);
+}
+
+machine_init(sunxi_machine_init);
--
1.7.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/4] hw/arm: add sunxi machine type
2013-11-25 7:41 ` [Qemu-devel] [PATCH v3 3/4] hw/arm: add sunxi machine type liguang
@ 2013-11-25 10:45 ` Peter Crosthwaite
0 siblings, 0 replies; 11+ messages in thread
From: Peter Crosthwaite @ 2013-11-25 10:45 UTC (permalink / raw)
To: liguang; +Cc: Peter Maydell, qemu-devel@nongnu.org Developers
On Mon, Nov 25, 2013 at 5:41 PM, liguang <lig.fnst@cn.fujitsu.com> wrote:
> Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
> ---
> hw/arm/Makefile.objs | 1 +
> hw/arm/sunxi-soc.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 114 insertions(+), 0 deletions(-)
> create mode 100644 hw/arm/sunxi-soc.c
>
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index 3671b42..f9f3071 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -5,3 +5,4 @@ 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 += sunxi-soc.o
> diff --git a/hw/arm/sunxi-soc.c b/hw/arm/sunxi-soc.c
> new file mode 100644
> index 0000000..857b0ab
> --- /dev/null
> +++ b/hw/arm/sunxi-soc.c
> @@ -0,0 +1,113 @@
> +/*
> + * Allwinner sunxi series SoC 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 "hw/boards.h"
> +#include "hw/arm/arm.h"
> +#include "hw/ptimer.h"
> +#include "hw/char/serial.h"
> +#include "hw/timer/sunxi-pit.h"
> +#include "hw/intc/sunxi-pic.h"
> +
> +#include "sysemu/sysemu.h"
> +#include "exec/address-spaces.h"
> +
> +
> +#define SUNXI_PIC_REG_BASE 0x01c20400
> +#define SUNXI_PIT_REG_BASE 0x01c20c00
> +#define SUNXI_UART0_REG_BASE 0x01c28000
> +
> +static struct arm_boot_info sunxi_binfo = {
> + .loader_start = 0x40000000,
> + .board_id = 0x1008,
> +};
> +
> +static void sunxi_init(QEMUMachineInitArgs *args)
> +{
> + ram_addr_t ram_size = args->ram_size;
> + const char *cpu_model = args->cpu_model;
> + const char *kernel_filename = args->kernel_filename;
> + const char *kernel_cmdline = args->kernel_cmdline;
> + ARMCPU *cpu;
> + MemoryRegion *address_space_mem = get_system_memory();
> + MemoryRegion *ram = g_new(MemoryRegion, 1);
> + MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
> + qemu_irq pic[95];
> + DeviceState *dev;
> + uint8_t i;
> +
> + /*here we currently support sunxi-4i*/
> + cpu_model = "cortex-a8";
> + cpu = cpu_arm_init(cpu_model);
> + if (!cpu) {
> + fprintf(stderr, "Unable to find CPU definition\n");
> + exit(1);
> + }
> +
> + memory_region_init_ram(ram, NULL, "sunxi-soc.ram", ram_size);
> + memory_region_add_subregion(address_space_mem, 0, ram);
> + memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
> + memory_region_add_subregion(address_space_mem, 0x40000000, ram_alias);
> +
> + dev = sysbus_create_varargs(TYPE_SUNXI_PIC, SUNXI_PIC_REG_BASE,
> + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
> + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
> + NULL);
> + for (i = 0; i < 95; i++) {
> + pic[i] = qdev_get_gpio_in(dev, i);
> + }
> +
> + sysbus_create_varargs(TYPE_SUNXI_PIT, SUNXI_PIT_REG_BASE, pic[22], pic[23],
> + pic[24], pic[25], pic[67], pic[68], NULL);
> +
> + serial_mm_init(address_space_mem, SUNXI_UART0_REG_BASE, 2, pic[1], 115200,
> + serial_hds[0], DEVICE_NATIVE_ENDIAN);
> +/*
> + serial_mm_init(address_space_mem, SUNXI_UART1_REG_BASE, 2, pic[2], 115200,
> + serial_hds[0], DEVICE_NATIVE_ENDIAN);
> + serial_mm_init(address_space_mem, SUNXI_UART2_REG_BASE, 2, pic[3], 115200,
> + serial_hds[0], DEVICE_NATIVE_ENDIAN);
> + serial_mm_init(address_space_mem, SUNXI_UART3_REG_BASE, 2, pic[4], 115200,
> + serial_hds[0], DEVICE_NATIVE_ENDIAN);
> + serial_mm_init(address_space_mem, SUNXI_UART4_REG_BASE, 2, pic[17], 115200,
> + serial_hds[0], DEVICE_NATIVE_ENDIAN);
> + serial_mm_init(address_space_mem, SUNXI_UART5_REG_BASE, 2, pic[18], 115200,
> + serial_hds[0], DEVICE_NATIVE_ENDIAN);
> + serial_mm_init(address_space_mem, SUNXI_UART6_REG_BASE, 2, pic[19], 115200,
> + serial_hds[0], DEVICE_NATIVE_ENDIAN);
> + serial_mm_init(address_space_mem, SUNXI_UART7_REG_BASE, 2, pic[20], 115200,
> + serial_hds[0], DEVICE_NATIVE_ENDIAN);
> +*/
Why the commented out serial ports?
Regards,
Peter
> + sunxi_binfo.ram_size = ram_size;
> + sunxi_binfo.kernel_filename = kernel_filename;
> + sunxi_binfo.kernel_cmdline = kernel_cmdline;
> + arm_load_kernel(cpu, &sunxi_binfo);
> +}
> +
> +static QEMUMachine sunxi_machine = {
> + .name = "sunxi",
> + .desc = "Allwinner's SoC (sunxi series)",
> + .init = sunxi_init,
> +};
> +
> +static void sunxi_machine_init(void)
> +{
> + qemu_register_machine(&sunxi_machine);
> +}
> +
> +machine_init(sunxi_machine_init);
> --
> 1.7.2.5
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v3 4/4] MAINTAINERS: add myself to maintain sunxi machine
2013-11-25 7:41 [Qemu-devel] [PATCH v3 0/4] add sunxi machine type liguang
` (2 preceding siblings ...)
2013-11-25 7:41 ` [Qemu-devel] [PATCH v3 3/4] hw/arm: add sunxi machine type liguang
@ 2013-11-25 7:41 ` liguang
3 siblings, 0 replies; 11+ messages in thread
From: liguang @ 2013-11-25 7:41 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, liguang
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
---
MAINTAINERS | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 77edacf..232e1a1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -284,6 +284,15 @@ M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: hw/*/stellaris*
+Sunxi
+M: Li Guang <lig.fnst@cn.fujitsu.com>
+S: Maintained
+F: hw/arm/sunxi-soc.c
+F: hw/intc/sunxi-pic.c
+F: hw/timer/sunxi-pit.c
+F: include/hw/intc/sunxi-pic.h
+F: include/hw/timer/sunxi-pit.h
+
Versatile PB
M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
--
1.7.2.5
^ permalink raw reply related [flat|nested] 11+ messages in thread