qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Evgeny Voevodin <e.voevodin@samsung.com>
To: qemu-devel@nongnu.org
Cc: d.solodkiy@samsung.com, Evgeny Voevodin <e.voevodin@samsung.com>
Subject: [Qemu-devel] [PATCH 03/14] ARM: s5pc210: IRQ subsystem support.
Date: Wed, 07 Dec 2011 13:46:54 +0400	[thread overview]
Message-ID: <1323251225-1072-4-git-send-email-e.voevodin@samsung.com> (raw)
In-Reply-To: <1323251225-1072-1-git-send-email-e.voevodin@samsung.com>


Signed-off-by: Evgeny Voevodin <e.voevodin@samsung.com>
---
 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 <e.voevodin@samsung.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.
+ *
+ * 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 <e.voevodin@samsung.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.
+ *
+ * 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

  parent reply	other threads:[~2011-12-07  9:48 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-12-07  9:46 [Qemu-devel] [PATCH 00/14] ARM: Samsung S5PC210-based boards support Evgeny Voevodin
2011-12-07  9:46 ` [Qemu-devel] [PATCH 01/14] ARM: s5pc210: Basic support of s5pc210 boards Evgeny Voevodin
2011-12-07 11:01   ` Peter Maydell
2011-12-07  9:46 ` [Qemu-devel] [PATCH 02/14] hw/sysbus.h: Increase maximum number of device IRQs Evgeny Voevodin
2011-12-07  9:46 ` Evgeny Voevodin [this message]
2011-12-07  9:46 ` [Qemu-devel] [PATCH 04/14] ARM: s5pc210: PWM support Evgeny Voevodin
2011-12-07  9:46 ` [Qemu-devel] [PATCH 05/14] hw/arm_boot.c: Add new secondary CPU bootloader Evgeny Voevodin
2011-12-07  9:46 ` [Qemu-devel] [PATCH 06/14] hw/arm_gic.c: lower IRQ only on changing of enable bit Evgeny Voevodin
2011-12-07  9:46 ` [Qemu-devel] [PATCH 07/14] ARM: s5pc210: MCT support Evgeny Voevodin
2011-12-07  9:46 ` [Qemu-devel] [PATCH 08/14] ARM: s5pc210: Boot secondary CPU Evgeny Voevodin
2011-12-07  9:47 ` [Qemu-devel] [PATCH 09/14] hw/lan9118.c: Basic byte/word/long access support Evgeny Voevodin
2011-12-07 10:09   ` Peter Maydell
2011-12-07 10:58     ` Evgeny Voevodin
2011-12-07 11:17       ` Peter Maydell
2011-12-07  9:47 ` [Qemu-devel] [PATCH 10/14] hw/s5pc210.c: Add lan9118 support to SMDK board Evgeny Voevodin
2011-12-07  9:47 ` [Qemu-devel] [PATCH 11/14] ARM: s5pc210: added s5pc210 display controller device (FIMD) Evgeny Voevodin
2011-12-07  9:47 ` [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  9:47 ` [Qemu-devel] [PATCH 13/14] ARM: s5pc210: added SD/MMC host controller (ver. 2.0 compliant) implementation Evgeny Voevodin
2011-12-07  9:47 ` [Qemu-devel] [PATCH 14/14] s5pc210: Switch to sysbus_init_mmio Evgeny Voevodin
2011-12-07 10:41   ` Peter Maydell
2011-12-07 10:33 ` [Qemu-devel] [PATCH 00/14] ARM: Samsung S5PC210-based boards support Peter Maydell
2011-12-07 10:45   ` Dmitry Solodkiy
2011-12-08 10:58     ` Peter Maydell
2011-12-09  1:54       ` Chih-Min Chao
2011-12-09  9:21       ` Dmitry Solodkiy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1323251225-1072-4-git-send-email-e.voevodin@samsung.com \
    --to=e.voevodin@samsung.com \
    --cc=d.solodkiy@samsung.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).