[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 03/14] ARM: s5pc210: IRQ subsystem support.
From: |
Evgeny Voevodin |
Subject: |
[Qemu-devel] [PATCH 03/14] ARM: s5pc210: IRQ subsystem support. |
Date: |
Wed, 07 Dec 2011 13:46:54 +0400 |
Signed-off-by: Evgeny Voevodin <address@hidden>
---
Makefile.target | 3 +-
hw/s5pc210.c | 163 +++++++++++++++++++-
hw/s5pc210.h | 39 +++++
hw/s5pc210_combiner.c | 381 +++++++++++++++++++++++++++++++++++++++++++++
hw/s5pc210_gic.c | 411 +++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 995 insertions(+), 2 deletions(-)
create mode 100644 hw/s5pc210_combiner.c
create mode 100644 hw/s5pc210_gic.c
diff --git a/Makefile.target b/Makefile.target
index 38fc364..ed338a8 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -344,7 +344,8 @@ obj-arm-y = integratorcp.o versatilepb.o arm_pic.o
arm_timer.o
obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
obj-arm-y += versatile_pci.o
obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
-obj-arm-y += s5pc210.o s5pc210_cmu.o s5pc210_uart.o
+obj-arm-y += s5pc210.o s5pc210_cmu.o s5pc210_uart.o s5pc210_gic.o \
+ s5pc210_combiner.o
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
obj-arm-y += pl061.o
obj-arm-y += arm-semi.o
diff --git a/hw/s5pc210.c b/hw/s5pc210.c
index d20ac95..99e9b1b 100644
--- a/hw/s5pc210.c
+++ b/hw/s5pc210.c
@@ -61,6 +61,8 @@
#define S5PC210_SFR_BASE_ADDR 0x10000000
+#define S5PC210_SMP_PRIVATE_BASE_ADDR 0x10500000
+
/* SFR Base Address for CMUs */
#define S5PC210_CMU_BASE_ADDR 0x10030000
@@ -76,6 +78,16 @@
#define S5PC210_UART2_FIFO_SIZE 16
#define S5PC210_UART3_FIFO_SIZE 16
#define S5PC210_UART4_FIFO_SIZE 64
+/* Interrupt Group of External Interrupt Combiner for UART */
+#define S5PC210_UART_INTG 26
+
+/* External GIC */
+#define S5PC210_EXT_GIC_CPU_BASE_ADDR 0x10480000
+#define S5PC210_EXT_GIC_DIST_BASE_ADDR 0x10490000
+
+/* Combiner */
+#define S5PC210_EXT_COMBINER_BASE_ADDR 0x10440000
+#define S5PC210_INT_COMBINER_BASE_ADDR 0x10448000
#define S5PC210_BASE_BOOT_ADDR S5PC210_DRAM0_BASE_ADDR
@@ -96,6 +108,88 @@ enum s5pc210_mach_id {
MACH_SMDKC210_ID = 0xB16,
};
+static void s5pc210_combiner_get_gpioin(S5pc210Irq *irqs,
+ DeviceState *dev,
+ int ext)
+{
+ int n;
+ int bit;
+ int max;
+ qemu_irq *irq;
+
+ max = ext ? S5PC210_MAX_EXT_COMBINER_IN_IRQ :
+ S5PC210_MAX_INT_COMBINER_IN_IRQ;
+ irq = ext ? irqs->ext_combiner_irq : irqs->int_combiner_irq;
+
+ /*
+ * Some IRQs of Int/External Combiner are going to two Combiners groups,
+ * so let split them.
+ */
+ for (n = 0; n < max; n++) {
+
+ bit = S5PC210_COMBINER_GET_BIT_NUM(n);
+
+ switch (n) {
+ /* MDNIE_LCD1 INTG1*/
+ case S5PC210_COMBINER_GET_IRQ_NUM(1, 0) ...
+ S5PC210_COMBINER_GET_IRQ_NUM(1, 3):
+ irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+ irq[S5PC210_COMBINER_GET_IRQ_NUM(0, bit + 4)]);
+ continue;
+ break;
+
+ /* TMU INTG3*/
+ case S5PC210_COMBINER_GET_IRQ_NUM(3, 4):
+ irq[n] =
+ qemu_irq_split(qdev_get_gpio_in(dev, n),
+ irq[S5PC210_COMBINER_GET_IRQ_NUM(2, bit)]);
+ continue;
+ break;
+
+ /* LCD1 INTG12*/
+ case S5PC210_COMBINER_GET_IRQ_NUM(12, 0) ...
+ S5PC210_COMBINER_GET_IRQ_NUM(12, 3):
+ irq[n] =
+ qemu_irq_split(qdev_get_gpio_in(dev, n),
+ irq[S5PC210_COMBINER_GET_IRQ_NUM(11, bit +
4)]);
+ continue;
+
+ /* Multi-Core Timer INTG12*/
+ case S5PC210_COMBINER_GET_IRQ_NUM(12, 4) ...
+ S5PC210_COMBINER_GET_IRQ_NUM(12, 8):
+ irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+ irq[S5PC210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+ continue;
+ break;
+
+ /* Multi-Core Timer INTG35*/
+ case S5PC210_COMBINER_GET_IRQ_NUM(35, 4) ...
+ S5PC210_COMBINER_GET_IRQ_NUM(35, 8):
+ irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+ irq[S5PC210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+ continue;
+ break;
+
+ /* Multi-Core Timer INTG51*/
+ case S5PC210_COMBINER_GET_IRQ_NUM(51, 4) ...
+ S5PC210_COMBINER_GET_IRQ_NUM(51, 8):
+ irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+ irq[S5PC210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+ continue;
+ break;
+
+ /* Multi-Core Timer INTG53*/
+ case S5PC210_COMBINER_GET_IRQ_NUM(53, 4) ...
+ S5PC210_COMBINER_GET_IRQ_NUM(53, 8):
+ irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+ irq[S5PC210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+ continue;
+ break;
+ }
+
+ irq[n] = qdev_get_gpio_in(dev, n);
+ }
+}
static void s5pc210_init(ram_addr_t ram_size,
const char *boot_device,
@@ -113,8 +207,12 @@ static void s5pc210_init(ram_addr_t ram_size,
MemoryRegion *irom_alias_mem = g_new(MemoryRegion, 1);
MemoryRegion *dram0_mem = g_new(MemoryRegion, 1);
MemoryRegion *dram1_mem = NULL;
+ S5pc210Irq *irqs;
+ qemu_irq *irq_table;
qemu_irq *irqp;
qemu_irq cpu_irq[4];
+ DeviceState *dev;
+ SysBusDevice *busdev;
ram_addr_t mem_size;
int n;
@@ -132,6 +230,12 @@ static void s5pc210_init(ram_addr_t ram_size,
cpu_model = "cortex-a9";
}
+ irqs = g_malloc0(sizeof(S5pc210Irq));
+ if (!irqs) {
+ fprintf(stderr, "Can't allocate IRQs\n");
+ exit(1);
+ }
+
for (n = 0; n < smp_cpus; n++) {
env = cpu_init(cpu_model);
if (!env) {
@@ -148,6 +252,63 @@ static void s5pc210_init(ram_addr_t ram_size,
cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
}
+ irq_table = s5pc210_init_irq(irqs);
+
+ /*** SMP ***/
+
+ /* Private memory region and Internal GIC */
+ dev = qdev_create(NULL, "a9mpcore_priv");
+ qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_mmio_map(busdev, 0, S5PC210_SMP_PRIVATE_BASE_ADDR);
+ for (n = 0; n < smp_cpus; n++) {
+ sysbus_connect_irq(busdev, n, cpu_irq[n]);
+ }
+ for (n = 0; n < S5PC210_INT_GIC_NIRQ; n++) {
+ irqs->int_gic_irq[n] = qdev_get_gpio_in(dev, n);
+ }
+
+ /* External GIC */
+ dev = qdev_create(NULL, "s5pc210_gic");
+ qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ /* Map CPU interface */
+ sysbus_mmio_map(busdev, 0, S5PC210_EXT_GIC_CPU_BASE_ADDR);
+ /* Map Distributer interface */
+ sysbus_mmio_map(busdev, 1, S5PC210_EXT_GIC_DIST_BASE_ADDR);
+ for (n = 0; n < smp_cpus; n++) {
+ sysbus_connect_irq(busdev, n, cpu_irq[n]);
+ }
+ for (n = 0; n < S5PC210_EXT_GIC_NIRQ; n++) {
+ irqs->ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
+ }
+
+ /* Internal Interrupt Combiner */
+ dev = qdev_create(NULL, "s5pc210.combiner");
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ for (n = 0; n < S5PC210_MAX_INT_COMBINER_OUT_IRQ; n++) {
+ sysbus_connect_irq(busdev, n, irqs->int_gic_irq[n]);
+ }
+ s5pc210_combiner_get_gpioin(irqs, dev, 0);
+ sysbus_mmio_map(busdev, 0, S5PC210_INT_COMBINER_BASE_ADDR);
+
+ /* External Interrupt Combiner */
+ dev = qdev_create(NULL, "s5pc210.combiner");
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ for (n = 0; n < S5PC210_MAX_INT_COMBINER_OUT_IRQ; n++) {
+ sysbus_connect_irq(busdev, n, irqs->ext_gic_irq[n]);
+ }
+ s5pc210_combiner_get_gpioin(irqs, dev, 1);
+ sysbus_mmio_map(busdev, 0, S5PC210_EXT_COMBINER_BASE_ADDR);
+ qdev_prop_set_uint32(dev, "external", 1);
+
+ /* Initialize board IRQs. */
+ s5pc210_init_board_irqs(irqs);
+
/*** Memory ***/
/* Chip-ID and OMR */
@@ -225,7 +386,7 @@ static void s5pc210_init(ram_addr_t ram_size,
continue;
}
- uart_irq = NULL;
+ uart_irq = irq_table[s5pc210_get_irq(S5PC210_UART_INTG, channel)];
s5pc210_uart_create(addr, fifo_size, channel, NULL, uart_irq);
}
diff --git a/hw/s5pc210.h b/hw/s5pc210.h
index bbf927c..412d004 100644
--- a/hw/s5pc210.h
+++ b/hw/s5pc210.h
@@ -32,6 +32,45 @@
#define S5PC210_MAX_CPUS 2
/*
+ * s5pc210 IRQ subsystem stub definitions.
+ */
+
+#define S5PC210_MAX_INT_COMBINER_OUT_IRQ 64
+#define S5PC210_MAX_EXT_COMBINER_OUT_IRQ 16
+#define S5PC210_MAX_INT_COMBINER_IN_IRQ (S5PC210_MAX_INT_COMBINER_OUT_IRQ *
8)
+#define S5PC210_MAX_EXT_COMBINER_IN_IRQ (S5PC210_MAX_EXT_COMBINER_OUT_IRQ *
8)
+
+#define S5PC210_COMBINER_GET_IRQ_NUM(grp, bit) ((grp)*8 + (bit))
+#define S5PC210_COMBINER_GET_GRP_NUM(irq) ((irq) / 8)
+#define S5PC210_COMBINER_GET_BIT_NUM(irq) \
+ ((irq) - 8 * S5PC210_COMBINER_GET_GRP_NUM(irq))
+
+/* IRQs number for external and internal GIC */
+#define S5PC210_EXT_GIC_NIRQ (160-32)
+#define S5PC210_INT_GIC_NIRQ 64
+
+typedef struct S5pc210Irq {
+ qemu_irq int_combiner_irq[S5PC210_MAX_INT_COMBINER_IN_IRQ];
+ qemu_irq ext_combiner_irq[S5PC210_MAX_EXT_COMBINER_IN_IRQ];
+ qemu_irq int_gic_irq[S5PC210_INT_GIC_NIRQ];
+ qemu_irq ext_gic_irq[S5PC210_EXT_GIC_NIRQ];
+ qemu_irq board_irqs[S5PC210_MAX_INT_COMBINER_IN_IRQ];
+} S5pc210Irq;
+
+/* Initialize s5pc210 IRQ subsystem stub */
+qemu_irq *s5pc210_init_irq(S5pc210Irq *env);
+
+/* Initialize board IRQs.
+ * These IRQs contain splitted Int/External Combiner and External Gic IRQs */
+void s5pc210_init_board_irqs(S5pc210Irq *s);
+
+/* Get IRQ number from s5pc210 IRQ subsystem stub.
+ * To identify IRQ source use internal combiner group and bit number
+ * grp - group number
+ * bit - bit number inside group */
+uint32_t s5pc210_get_irq(uint32_t grp, uint32_t bit);
+
+/*
* Interface for s5pc210 Clock Management Units (CMUs)
*/
diff --git a/hw/s5pc210_combiner.c b/hw/s5pc210_combiner.c
new file mode 100644
index 0000000..04ae024
--- /dev/null
+++ b/hw/s5pc210_combiner.c
@@ -0,0 +1,381 @@
+/*
+ * Samsung s5pc210 Interrupt Combiner
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <address@hidden>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sysbus.h"
+
+#include "s5pc210.h"
+
+//#define DEBUG_COMBINER
+
+#ifdef DEBUG_COMBINER
+#define DPRINTF(fmt, ...) \
+ do { fprintf(stdout, "COMBINER: [%s:%d] " fmt, __func__ , __LINE__, \
+ ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define IIC_NGRP 64 /* Internal Interrupt Combiner
+ Groups number */
+#define IIC_NIRQ (IIC_NGRP*8) /* Internal Interrupt Combiner
+ Interrupts number */
+#define IIC_REGION_SIZE 0x108 /* Size of memory mapped region */
+#define IIC_REGSET_SIZE 0x41
+
+/*
+ * Combiner registers
+ */
+struct CombinerReg {
+ uint32_t iiesr; /* Internal Interrupt Enable Set register */
+ uint32_t iiecr; /* Internal Interrupt Enable Clear register */
+ uint32_t iistr; /* Internal Interrupt Status register.
+ * Shows status of interrupt pending BEFORE masking
+ */
+ uint32_t iimsr; /* Internal Interrupt Mask Status register.
+ * Shows status of interrupt pending AFTER masking
+ */
+};
+
+/*
+ * State for each output signal of internal combiner
+ */
+typedef struct CombinerGroupState {
+ uint8_t src_mask; /* 1 - source enabled, 0 - disabled */
+ uint8_t src_pending; /* Pending source interrupts before masking */
+} CombinerGroupState;
+
+typedef struct S5pc210CombinerState {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+
+ struct CombinerGroupState group[IIC_NGRP];
+ uint32_t reg_set[IIC_REGSET_SIZE];
+ uint32_t icipsr[2];
+ uint32_t external; /* 1 means that this combiner is external */
+
+ qemu_irq output_irq[IIC_NGRP];
+} S5pc210CombinerState;
+
+static const VMStateDescription VMState_S5pc210CombinerGroupState = {
+ .name = "s5pc210.combiner.groupstate",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(src_mask, CombinerGroupState),
+ VMSTATE_UINT8(src_pending, CombinerGroupState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription VMState_S5pc210Combiner = {
+ .name = "s5pc210.combiner",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_ARRAY(group, S5pc210CombinerState, IIC_NGRP, 0,
+ VMState_S5pc210CombinerGroupState, CombinerGroupState),
+ VMSTATE_UINT32_ARRAY(reg_set, S5pc210CombinerState,
+ IIC_REGSET_SIZE),
+ VMSTATE_UINT32_ARRAY(icipsr, S5pc210CombinerState, 2),
+ VMSTATE_UINT32(external, S5pc210CombinerState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static uint64_t s5pc210_combiner_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ struct S5pc210CombinerState *s = (struct S5pc210CombinerState *)opaque;
+ uint32_t req_quad_base_n; /* Base of registers quad. Multiply it by 4
and
+ get a start of corresponding group quad */
+ uint32_t grp_quad_base_n; /* Base of group quad */
+ uint32_t reg_n; /* Register number inside the quad */
+ uint32_t val;
+
+ if (s->external && (offset > 0x3c && offset != 0x100)) {
+ hw_error("s5pc210.combiner: unallowed read access at offset 0x"
+ TARGET_FMT_plx "\n", offset);
+ }
+
+ req_quad_base_n = offset >> 4;
+ grp_quad_base_n = req_quad_base_n << 2;
+ reg_n = (offset - (req_quad_base_n << 4)) >> 2;
+
+ if (req_quad_base_n >= IIC_NGRP) {
+ /* Read of ICIPSR register */
+ return s->icipsr[reg_n];
+ }
+
+ val = 0;
+
+ switch (reg_n) {
+ /* IISTR */
+ case 2:
+ val |= s->group[grp_quad_base_n].src_pending;
+ val |= s->group[grp_quad_base_n+1].src_pending << 8;
+ val |= s->group[grp_quad_base_n+2].src_pending << 16;
+ val |= s->group[grp_quad_base_n+3].src_pending << 24;
+ break;
+ /* IIMSR */
+ case 3:
+ val |= s->group[grp_quad_base_n].src_mask &
+ s->group[grp_quad_base_n].src_pending;
+ val |= (s->group[grp_quad_base_n+1].src_mask &
+ s->group[grp_quad_base_n+1].src_pending) << 8;
+ val |= (s->group[grp_quad_base_n+2].src_mask &
+ s->group[grp_quad_base_n+2].src_pending) << 16;
+ val |= (s->group[grp_quad_base_n+3].src_mask &
+ s->group[grp_quad_base_n+3].src_pending) << 24;
+ break;
+ default:
+ if (offset >> 2 >= IIC_REGSET_SIZE) {
+ hw_error("s5pc210.combiner: overflow of reg_set by 0x"
+ TARGET_FMT_plx "offset\n", offset);
+ }
+ val = s->reg_set[offset >> 2];
+ return 0;
+ }
+ return val;
+}
+
+static void s5pc210_combiner_update(void *opaque, uint8_t group_n)
+{
+ struct S5pc210CombinerState *s = (struct S5pc210CombinerState *)opaque;
+
+ /* Send interrupt if needed */
+ if (s->group[group_n].src_mask & s->group[group_n].src_pending) {
+#ifdef DEBUG_COMBINER
+ if (group_n != 26) {
+ /* skip uart */
+ DPRINTF("%s raise IRQ[%d]\n", s->external ? "EXT" : "INT",
group_n);
+ }
+#endif
+
+ /* Set Combiner interrupt pending status after masking */
+ if (group_n >= 32) {
+ s->icipsr[1] |= 1 << (group_n-32);
+ } else {
+ s->icipsr[0] |= 1 << group_n;
+ }
+
+ qemu_irq_raise(s->output_irq[group_n]);
+ } else {
+#ifdef DEBUG_COMBINER
+ if (group_n != 26) {
+ /* skip uart */
+ DPRINTF("%s lower IRQ[%d]\n", s->external ? "EXT" : "INT",
group_n);
+ }
+#endif
+
+ /* Set Combiner interrupt pending status after masking */
+ if (group_n >= 32) {
+ s->icipsr[1] &= ~(1 << (group_n-32));
+ } else {
+ s->icipsr[0] &= ~(1 << group_n);
+ }
+
+ qemu_irq_lower(s->output_irq[group_n]);
+ }
+}
+
+static void s5pc210_combiner_write(void *opaque, target_phys_addr_t offset,
+ uint64_t val, unsigned size)
+{
+ struct S5pc210CombinerState *s = (struct S5pc210CombinerState *)opaque;
+ uint32_t req_quad_base_n; /* Base of registers quad. Multiply it by 4
and
+ get a start of corresponding group quad */
+ uint32_t grp_quad_base_n; /* Base of group quad */
+ uint32_t reg_n; /* Register number inside the quad */
+
+ if (s->external && (offset > 0x3c && offset != 0x100)) {
+ hw_error("s5pc210.combiner: unallowed write access at offset 0x"
+ TARGET_FMT_plx "\n", offset);
+ }
+
+ req_quad_base_n = offset >> 4;
+ grp_quad_base_n = req_quad_base_n << 2;
+ reg_n = (offset - (req_quad_base_n << 4)) >> 2;
+
+ if (req_quad_base_n >= IIC_NGRP) {
+ hw_error("s5pc210.combiner: unallowed write access at offset 0x"
+ TARGET_FMT_plx "\n", offset);
+ return;
+ }
+
+ if (reg_n > 1) {
+ hw_error("s5pc210.combiner: unallowed write access at offset 0x"
+ TARGET_FMT_plx "\n", offset);
+ return;
+ }
+
+ if (offset >> 2 >= IIC_REGSET_SIZE) {
+ hw_error("s5pc210.combiner: overflow of reg_set by 0x"
+ TARGET_FMT_plx "offset\n", offset);
+ }
+ s->reg_set[offset >> 2] = val;
+
+ switch (reg_n) {
+ /* IIESR */
+ case 0:
+ /* FIXME: what if irq is pending, allowed by mask, and we allow it
+ * again. Interrupt will rise again! */
+
+ DPRINTF("%s enable IRQ for groups %d, %d, %d, %d\n",
+ s->external ? "EXT" : "INT", grp_quad_base_n,
grp_quad_base_n+1,
+ grp_quad_base_n+2, grp_quad_base_n+3);
+ /* Enable interrupt sources */
+ s->group[grp_quad_base_n].src_mask |= val&0xFF;
+ s->group[grp_quad_base_n+1].src_mask |= (val&0xFF00)>>8;
+ s->group[grp_quad_base_n+2].src_mask |= (val&0xFF0000)>>16;
+ s->group[grp_quad_base_n+3].src_mask |= (val&0xFF000000)>>24;
+
+ s5pc210_combiner_update(s, grp_quad_base_n);
+ s5pc210_combiner_update(s, grp_quad_base_n+1);
+ s5pc210_combiner_update(s, grp_quad_base_n+2);
+ s5pc210_combiner_update(s, grp_quad_base_n+3);
+ break;
+ /* IIECR */
+ case 1:
+ DPRINTF("%s disable IRQ for groups %d, %d, %d, %d\n",
+ s->external ? "EXT" : "INT", grp_quad_base_n,
grp_quad_base_n+1,
+ grp_quad_base_n+2, grp_quad_base_n+3);
+ /* Disable interrupt sources */
+ s->group[grp_quad_base_n].src_mask &= ~(val&0xFF);
+ s->group[grp_quad_base_n+1].src_mask &= ~((val&0xFF00)>>8);
+ s->group[grp_quad_base_n+2].src_mask &= ~((val&0xFF0000)>>16);
+ s->group[grp_quad_base_n+3].src_mask &= ~((val&0xFF000000)>>24);
+
+ s5pc210_combiner_update(s, grp_quad_base_n);
+ s5pc210_combiner_update(s, grp_quad_base_n+1);
+ s5pc210_combiner_update(s, grp_quad_base_n+2);
+ s5pc210_combiner_update(s, grp_quad_base_n+3);
+ break;
+ default:
+ hw_error("s5pc210.combiner: unallowed write access at offset 0x"
+ TARGET_FMT_plx "\n", offset);
+ break;
+ }
+
+ return;
+}
+
+/* Get combiner group and bit from irq number */
+static uint8_t get_combiner_group_and_bit(int irq, uint8_t *bit)
+{
+ *bit = irq - ((irq >> 3)<<3);
+ return irq >> 3;
+}
+
+/* Process a change in an external IRQ input. */
+static void s5pc210_combiner_handler(void *opaque, int irq, int level)
+{
+ struct S5pc210CombinerState *s = (struct S5pc210CombinerState *)opaque;
+ uint8_t bit_n, group_n;
+
+ group_n = get_combiner_group_and_bit(irq, &bit_n);
+
+ if (s->external && group_n >= S5PC210_MAX_EXT_COMBINER_OUT_IRQ) {
+ DPRINTF("%s unallowed IRQ group 0x%x\n", s->external ? "EXT" : "INT"
+ , group_n);
+ return;
+ }
+
+ if (level) {
+ s->group[group_n].src_pending |= 1 << bit_n;
+ } else {
+ s->group[group_n].src_pending &= ~(1 << bit_n);
+ }
+
+ s5pc210_combiner_update(s, group_n);
+
+ return;
+}
+
+static void s5pc210_combiner_reset(void *opaque)
+{
+ struct S5pc210CombinerState *s = (struct S5pc210CombinerState *)opaque;
+
+ memset(&s->group, 0, sizeof(s->group));
+ memset(&s->reg_set, 0, sizeof(s->reg_set));
+
+ s->reg_set[0xC0 >> 2] = 0x01010101;
+ s->reg_set[0xC4 >> 2] = 0x01010101;
+ s->reg_set[0xD0 >> 2] = 0x01010101;
+ s->reg_set[0xD4 >> 2] = 0x01010101;
+}
+
+static const MemoryRegionOps s5pc210_combiner_ops = {
+ .read = s5pc210_combiner_read,
+ .write = s5pc210_combiner_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/*
+ * Internal Combiner initialization.
+ */
+static int s5pc210_combiner_init(SysBusDevice *dev)
+{
+ unsigned int i;
+ struct S5pc210CombinerState *s =
+ FROM_SYSBUS(struct S5pc210CombinerState, dev);
+
+ /* Allocate general purpose input signals and connect a handler to each of
+ * them */
+ qdev_init_gpio_in(&s->busdev.qdev, s5pc210_combiner_handler, IIC_NIRQ);
+
+ /* Connect SysBusDev irqs to device specific irqs */
+ for (i = 0; i < IIC_NIRQ; i++) {
+ sysbus_init_irq(dev, &s->output_irq[i]);
+ }
+
+ memory_region_init_io(&s->iomem, &s5pc210_combiner_ops, s,
+ "s5pc210-combiner", IIC_REGION_SIZE);
+ sysbus_init_mmio_region(dev, &s->iomem);
+
+ s5pc210_combiner_reset(s);
+ vmstate_register(NULL, -1, &VMState_S5pc210Combiner, s);
+ return 0;
+}
+
+static SysBusDeviceInfo s5pc210_combiner_info = {
+ .qdev.name = "s5pc210.combiner",
+ .qdev.size = sizeof(struct S5pc210CombinerState),
+ .qdev.vmsd = &VMState_S5pc210Combiner,
+ .init = s5pc210_combiner_init,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("external",
+ struct S5pc210CombinerState,
+ external,
+ 0),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void s5pc210_combiner_register_devices(void)
+{
+ sysbus_register_withprop(&s5pc210_combiner_info);
+}
+
+device_init(s5pc210_combiner_register_devices)
diff --git a/hw/s5pc210_gic.c b/hw/s5pc210_gic.c
new file mode 100644
index 0000000..c6f18d4
--- /dev/null
+++ b/hw/s5pc210_gic.c
@@ -0,0 +1,411 @@
+/*
+ * Samsung s5pc210 GIC implementation. Based on hw/arm_gic.c
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <address@hidden>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sysbus.h"
+#include "qemu-common.h"
+#include "irq.h"
+#include "s5pc210.h"
+
+//#define DEBUG_S5PC210_IRQ
+//#define DEBUG_S5PC210_GIC
+
+#ifdef DEBUG_S5PC210_IRQ
+#define DPRINTF_S5PC210_GIC(fmt, ...) \
+ do { fprintf(stdout, "S5PC210_IRQ: [%24s:%5d] " fmt, __func__, \
+ __LINE__, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_S5PC210_GIC(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S5PC210_GIC
+#define DPRINTF_S5PC210_GIC(fmt, ...) \
+ do { fprintf(stdout, "EXT_GIC: [%24s:%5d] " fmt, __func__, __LINE__, \
+ ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_S5PC210_GIC(fmt, ...) do {} while (0)
+#endif
+
+#define EXT_GIC_ID_TVENC 127
+#define EXT_GIC_ID_MFC 126
+#define EXT_GIC_ID_HDMI_I2C 125
+#define EXT_GIC_ID_HDMI 124
+#define EXT_GIC_ID_MIXER 123
+#define EXT_GIC_ID_PCIe 122
+#define EXT_GIC_ID_2D 121
+#define EXT_GIC_ID_JPEG 120
+#define EXT_GIC_ID_FIMC3 119
+#define EXT_GIC_ID_FIMC2 118
+#define EXT_GIC_ID_FIMC1 117
+#define EXT_GIC_ID_FIMC0 116
+#define EXT_GIC_ID_ROTATOR 115
+#define EXT_GIC_ID_ONENAND_AUDI 114
+#define EXT_GIC_ID_MIPI_DSI_2LANE 113
+#define EXT_GIC_ID_MIPI_CSI_2LANE 112
+#define EXT_GIC_ID_MIPI_DSI_4LANE 111
+#define EXT_GIC_ID_MIPI_CSI_4LANE 110
+#define EXT_GIC_ID_SDMMC 109
+#define EXT_GIC_ID_HSMMC3 108
+#define EXT_GIC_ID_HSMMC2 107
+#define EXT_GIC_ID_HSMMC1 106
+#define EXT_GIC_ID_HSMMC0 105
+#define EXT_GIC_ID_MODEMIF 104
+#define EXT_GIC_ID_USB_DEVICE 103
+#define EXT_GIC_ID_USB_HOST 102
+#define EXT_GIC_ID_MCT_G1 101
+#define EXT_GIC_ID_SPI2 100
+#define EXT_GIC_ID_SPI1 99
+#define EXT_GIC_ID_SPI0 98
+#define EXT_GIC_ID_I2C7 97
+#define EXT_GIC_ID_I2C6 96
+#define EXT_GIC_ID_I2C5 95
+#define EXT_GIC_ID_I2C4 94
+#define EXT_GIC_ID_I2C3 93
+#define EXT_GIC_ID_I2C2 92
+#define EXT_GIC_ID_I2C1 91
+#define EXT_GIC_ID_I2C0 90
+#define EXT_GIC_ID_MCT_G0 89
+#define EXT_GIC_ID_UART4 88
+#define EXT_GIC_ID_UART3 87
+#define EXT_GIC_ID_UART2 86
+#define EXT_GIC_ID_UART1 85
+#define EXT_GIC_ID_UART0 84
+#define EXT_GIC_ID_NFC 83
+#define EXT_GIC_ID_IEM_IEC 82
+#define EXT_GIC_ID_IEM_APC 81
+#define EXT_GIC_ID_MCT_L1 80
+#define EXT_GIC_ID_GPIO_XA 79
+#define EXT_GIC_ID_GPIO_XB 78
+#define EXT_GIC_ID_RTC_TIC 77
+#define EXT_GIC_ID_RTC_ALARM 76
+#define EXT_GIC_ID_WDT 75
+#define EXT_GIC_ID_MCT_L0 74
+#define EXT_GIC_ID_TIMER4 73
+#define EXT_GIC_ID_TIMER3 72
+#define EXT_GIC_ID_TIMER2 71
+#define EXT_GIC_ID_TIMER1 70
+#define EXT_GIC_ID_TIMER0 69
+#define EXT_GIC_ID_PDMA1 68
+#define EXT_GIC_ID_PDMA0 67
+#define EXT_GIC_ID_MDMA_LCD0 66
+
+enum ext_int {
+ EXT_GIC_ID_EXTINT0 = 48,
+ EXT_GIC_ID_EXTINT1,
+ EXT_GIC_ID_EXTINT2,
+ EXT_GIC_ID_EXTINT3,
+ EXT_GIC_ID_EXTINT4,
+ EXT_GIC_ID_EXTINT5,
+ EXT_GIC_ID_EXTINT6,
+ EXT_GIC_ID_EXTINT7,
+ EXT_GIC_ID_EXTINT8,
+ EXT_GIC_ID_EXTINT9,
+ EXT_GIC_ID_EXTINT10,
+ EXT_GIC_ID_EXTINT11,
+ EXT_GIC_ID_EXTINT12,
+ EXT_GIC_ID_EXTINT13,
+ EXT_GIC_ID_EXTINT14,
+ EXT_GIC_ID_EXTINT15
+};
+
+/*
+ * External GIC sources which are not from External Interrupt Combiner or
+ * External Interrupts are starting from S5PC210_MAX_EXT_COMBINER_OUT_IRQ,
+ * which is INTG16 in Internal Interrupt Combiner.
+ */
+
+static uint32_t
+combiner_grp_to_gic_id[64-S5PC210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
+ /* int combiner groups 16-19 */
+ {}, {}, {}, {},
+ /* int combiner group 20 */
+ {0, EXT_GIC_ID_MDMA_LCD0},
+ /* int combiner group 21 */
+ {EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1},
+ /* int combiner group 22 */
+ {EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2,
+ EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4},
+ /* int combiner group 23 */
+ {EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC},
+ /* int combiner group 24 */
+ {EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA},
+ /* int combiner group 25 */
+ {EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC},
+ /* int combiner group 26 */
+ {EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2,
EXT_GIC_ID_UART3,
+ EXT_GIC_ID_UART4},
+ /* int combiner group 27 */
+ {EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3,
+ EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6,
+ EXT_GIC_ID_I2C7},
+ /* int combiner group 28 */
+ {EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2},
+ /* int combiner group 29 */
+ {EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2,
+ EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC},
+ /* int combiner group 30 */
+ {EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE},
+ /* int combiner group 31 */
+ {EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE},
+ /* int combiner group 32 */
+ {EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1},
+ /* int combiner group 33 */
+ {EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3},
+ /* int combiner group 34 */
+ {EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC},
+ /* int combiner group 35 */
+ {0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1},
+ /* int combiner group 36 */
+ {EXT_GIC_ID_MIXER},
+ /* int combiner group 37 */
+ {EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6,
+ EXT_GIC_ID_EXTINT7},
+ /* groups 38-50 */
+ {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
+ /* int combiner group 51 */
+ {EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1},
+ /* group 52 */
+ {},
+ /* int combiner group 53 */
+ {EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1},
+ /* groups 54-63 */
+ {}, {}, {}, {}, {}, {}, {}, {}, {}, {}
+};
+
+#define GIC_NIRQ 160
+#define NCPU S5PC210_MAX_CPUS
+
+#define S5PC210_GIC_CPU_REGION_SIZE 0x8050
+#define S5PC210_GIC_DIST_REGION_SIZE 0x8F04
+
+static void s5pc210_irq_handler(void *opaque, int irq, int level)
+{
+ S5pc210Irq *s = (S5pc210Irq *)opaque;
+
+ /* Bypass */
+ qemu_set_irq(s->board_irqs[irq], level);
+
+ return;
+}
+
+/*
+ * Initialize s5pc210 IRQ subsystem stub.
+ */
+qemu_irq *s5pc210_init_irq(S5pc210Irq *s)
+{
+ return qemu_allocate_irqs(s5pc210_irq_handler, s,
+ S5PC210_MAX_INT_COMBINER_IN_IRQ);
+}
+
+/*
+ * Initialize board IRQs.
+ * These IRQs contain splitted Int/External Combiner and External Gic IRQs.
+ */
+void s5pc210_init_board_irqs(S5pc210Irq *s)
+{
+ uint32_t grp, bit, irq_id, n;
+
+ for (n = 0; n < S5PC210_MAX_EXT_COMBINER_IN_IRQ; n++) {
+ s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
+ s->ext_combiner_irq[n]);
+
+ irq_id = 0;
+ if (n == S5PC210_COMBINER_GET_IRQ_NUM(1, 4) ||
+ n == S5PC210_COMBINER_GET_IRQ_NUM(12, 4)) {
+ /* MCT_G0 is passed to External GIC */
+ irq_id = EXT_GIC_ID_MCT_G0;
+ }
+ if (n == S5PC210_COMBINER_GET_IRQ_NUM(1, 5) ||
+ n == S5PC210_COMBINER_GET_IRQ_NUM(12, 5)) {
+ /* MCT_G1 is passed to External and GIC */
+ irq_id = EXT_GIC_ID_MCT_G1;
+ }
+ if (irq_id) {
+ s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
+ s->ext_gic_irq[irq_id-32]);
+ }
+
+ }
+ for (; n < S5PC210_MAX_INT_COMBINER_IN_IRQ; n++) {
+ /* these IDs are passed to Internal Combiner and External GIC */
+ grp = S5PC210_COMBINER_GET_GRP_NUM(n);
+ bit = S5PC210_COMBINER_GET_BIT_NUM(n);
+ irq_id =
+ combiner_grp_to_gic_id[grp -
+ S5PC210_MAX_EXT_COMBINER_OUT_IRQ][bit];
+
+ if (irq_id) {
+ s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
+ s->ext_gic_irq[irq_id-32]);
+ }
+ }
+}
+
+/*
+ * Get IRQ number from s5pc210 IRQ subsystem stub.
+ * To identify IRQ source use internal combiner group and bit number
+ * grp - group number
+ * bit - bit number inside group
+ */
+uint32_t s5pc210_get_irq(uint32_t grp, uint32_t bit)
+{
+ return S5PC210_COMBINER_GET_IRQ_NUM(grp, bit);
+}
+
+/********* GIC part *********/
+
+static inline int
+gic_get_current_cpu(void)
+{
+ return cpu_single_env->cpu_index;
+}
+
+#include "arm_gic.c"
+
+typedef struct {
+ gic_state gic;
+ MemoryRegion cpu_container;
+ MemoryRegion dist_container;
+ uint32_t num_cpu;
+} S5pc210GicState;
+
+static uint64_t s5pc210_gic_cpu_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ S5pc210GicState *s = (S5pc210GicState *) opaque;
+ DPRINTF_S5PC210_GIC("CPU%d: read offset 0x%x\n",
+ gic_get_current_cpu(), offset);
+ return gic_cpu_read(&s->gic, gic_get_current_cpu(), offset & ~0x8000);
+}
+
+static void s5pc210_gic_cpu_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ S5pc210GicState *s = (S5pc210GicState *) opaque;
+ DPRINTF_S5PC210_GIC("CPU%d: write offset 0x%x, value 0x%x\n",
+ gic_get_current_cpu(), offset, value);
+ gic_cpu_write(&s->gic, gic_get_current_cpu(), offset & ~0x8000, value);
+}
+
+static uint32_t s5pc210_gic_dist_readb(void *opaque, target_phys_addr_t offset)
+{
+ S5pc210GicState *s = (S5pc210GicState *) opaque;
+ DPRINTF_S5PC210_GIC("DIST: readb offset 0x%x\n", offset);
+ return gic_dist_readb(&s->gic, offset & ~0x8000);
+}
+
+static uint32_t s5pc210_gic_dist_readw(void *opaque, target_phys_addr_t offset)
+{
+ S5pc210GicState *s = (S5pc210GicState *) opaque;
+ DPRINTF_S5PC210_GIC("DIST: readw offset 0x%x\n", offset);
+ return gic_dist_readw(&s->gic, offset & ~0x8000);
+}
+
+static uint32_t s5pc210_gic_dist_readl(void *opaque, target_phys_addr_t offset)
+{
+ S5pc210GicState *s = (S5pc210GicState *) opaque;
+ DPRINTF_S5PC210_GIC("DIST: readl offset 0x%x\n", offset);
+ return gic_dist_readl(&s->gic, offset & ~0x8000);
+}
+
+static void s5pc210_gic_dist_writeb(void *opaque, target_phys_addr_t offset,
+ uint32_t value)
+{
+ S5pc210GicState *s = (S5pc210GicState *) opaque;
+ DPRINTF_S5PC210_GIC("DIST: writeb offset 0x%x, value 0x%x\n", offset,
+ value);
+ gic_dist_writeb(&s->gic, offset & ~0x8000, value);
+}
+
+static void s5pc210_gic_dist_writew(void *opaque, target_phys_addr_t offset,
+ uint32_t value)
+{
+ S5pc210GicState *s = (S5pc210GicState *) opaque;
+ DPRINTF_S5PC210_GIC("DIST: writew offset 0x%x, value 0x%x\n", offset,
+ value);
+ gic_dist_writew(&s->gic, offset & ~0x8000, value);
+}
+
+static void s5pc210_gic_dist_writel(void *opaque, target_phys_addr_t offset,
+ uint32_t value)
+{
+ S5pc210GicState *s = (S5pc210GicState *) opaque;
+ DPRINTF_S5PC210_GIC("DIST: writel offset 0x%x, value 0x%x\n", offset,
+ value);
+ gic_dist_writel(&s->gic, offset & ~0x8000, value);
+}
+
+static const MemoryRegionOps s5pc210_gic_cpu_ops = {
+ .read = s5pc210_gic_cpu_read,
+ .write = s5pc210_gic_cpu_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps s5pc210_gic_dist_ops = {
+ .old_mmio = {
+ .read = { s5pc210_gic_dist_readb,
+ s5pc210_gic_dist_readw,
+ s5pc210_gic_dist_readl, },
+ .write = { s5pc210_gic_dist_writeb,
+ s5pc210_gic_dist_writew,
+ s5pc210_gic_dist_writel, },
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int s5pc210_gic_init(SysBusDevice *dev)
+{
+ S5pc210GicState *s = FROM_SYSBUSGIC(S5pc210GicState, dev);
+ gic_init(&s->gic, s->num_cpu);
+
+ memory_region_init(&s->cpu_container, "s5pc210-gic-cpu_container",
+ S5PC210_GIC_CPU_REGION_SIZE);
+ memory_region_init(&s->cpu_container, "s5pc210-gic-dist_container",
+ S5PC210_GIC_DIST_REGION_SIZE);
+ memory_region_init_io(&s->cpu_container, &s5pc210_gic_cpu_ops, &s->gic,
+ "s5pc210-gic-cpu", S5PC210_GIC_CPU_REGION_SIZE);
+ memory_region_init_io(&s->dist_container, &s5pc210_gic_dist_ops, &s->gic,
+ "s5pc210-gic-dist", S5PC210_GIC_DIST_REGION_SIZE);
+
+ sysbus_init_mmio_region(dev, &s->cpu_container);
+ sysbus_init_mmio_region(dev, &s->dist_container);
+
+ gic_cpu_write(&s->gic, 1, 0, 1);
+ return 0;
+}
+
+static SysBusDeviceInfo s5pc210_gic_info = {
+ .init = s5pc210_gic_init,
+ .qdev.name = "s5pc210_gic",
+ .qdev.size = sizeof(S5pc210GicState),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("num-cpu", S5pc210GicState, num_cpu, 1),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void s5pc210_gic_register_devices(void)
+{
+ sysbus_register_withprop(&s5pc210_gic_info);
+}
+
+device_init(s5pc210_gic_register_devices)
--
1.7.4.1
- [Qemu-devel] [PATCH 00/14] ARM: Samsung S5PC210-based boards support., Evgeny Voevodin, 2011/12/07
- [Qemu-devel] [PATCH 02/14] hw/sysbus.h: Increase maximum number of device IRQs., Evgeny Voevodin, 2011/12/07
- [Qemu-devel] [PATCH 05/14] hw/arm_boot.c: Add new secondary CPU bootloader., Evgeny Voevodin, 2011/12/07
- [Qemu-devel] [PATCH 04/14] ARM: s5pc210: PWM support., Evgeny Voevodin, 2011/12/07
- [Qemu-devel] [PATCH 01/14] ARM: s5pc210: Basic support of s5pc210 boards, Evgeny Voevodin, 2011/12/07
- [Qemu-devel] [PATCH 03/14] ARM: s5pc210: IRQ subsystem support.,
Evgeny Voevodin <=
- [Qemu-devel] [PATCH 09/14] hw/lan9118.c: Basic byte/word/long access support., Evgeny Voevodin, 2011/12/07
- [Qemu-devel] [PATCH 08/14] ARM: s5pc210: Boot secondary CPU., Evgeny Voevodin, 2011/12/07
- [Qemu-devel] [PATCH 12/14] SD card: add query function to check wether SD card currently ready to recieve data Before executing data transfer to card, we must check that previously issued command wasn't a simple query command (for ex. CMD13), which doesn't require data transfer. Currently, we only can aquire information about whether SD card is in sending data state or not. This patch allows us to query wether previous command was data write command and it was successfully accepted by card (meaning that SD card in recieving data state)., Evgeny Voevodin, 2011/12/07
- [Qemu-devel] [PATCH 06/14] hw/arm_gic.c: lower IRQ only on changing of enable bit., Evgeny Voevodin, 2011/12/07
- [Qemu-devel] [PATCH 14/14] s5pc210: Switch to sysbus_init_mmio., Evgeny Voevodin, 2011/12/07
- [Qemu-devel] [PATCH 07/14] ARM: s5pc210: MCT support., Evgeny Voevodin, 2011/12/07