ARM GIC qdev conversion
Signed-off-by: Paul Brook <paul@codesourcery.com>
diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index 32a5e9f..367dd25 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -34,11 +34,8 @@
};
void arm_load_kernel(CPUState *env, struct arm_boot_info *info);
-/* armv7m_nvic.c */
-
/* Multiplication factor to convert from system clock ticks to qemu timer
ticks. */
extern int system_clock_scale;
-qemu_irq *armv7m_nvic_init(CPUState *env);
#endif /* !ARM_MISC_H */
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index cb774d6..5dc9448 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -32,6 +32,9 @@
#define GIC_BASE_IRQ 0
#endif
+#define FROM_SYSBUSGIC(type, dev) \
+ DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev))
+
typedef struct gic_irq_state
{
/* ??? The documentation seems to imply the enable bits are global, even
@@ -74,6 +77,7 @@
typedef struct gic_state
{
+ SysBusDevice busdev;
qemu_irq parent_irq[NCPU];
int enabled;
int cpu_enabled[NCPU];
@@ -91,10 +95,7 @@
int running_priority[NCPU];
int current_pending[NCPU];
- qemu_irq *in;
-#ifdef NVIC
- void *nvic;
-#endif
+ int iomemtype;
} gic_state;
/* TODO: Many places that call this routine could be optimized. */
@@ -363,7 +364,7 @@
uint32_t addr;
addr = offset;
if (addr < 0x100 || addr > 0xd00)
- return nvic_readl(s->nvic, addr);
+ return nvic_readl(s, addr);
#endif
val = gic_dist_readw(opaque, offset);
val |= gic_dist_readw(opaque, offset + 2) << 16;
@@ -523,7 +524,7 @@
uint32_t addr;
addr = offset;
if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) {
- nvic_writel(s->nvic, addr, value);
+ nvic_writel(s, addr, value);
return;
}
#endif
@@ -716,22 +717,16 @@
return 0;
}
-static gic_state *gic_init(uint32_t dist_base, qemu_irq *parent_irq)
+static void gic_init(gic_state *s)
{
- gic_state *s;
- int iomemtype;
int i;
- s = (gic_state *)qemu_mallocz(sizeof(gic_state));
- s->in = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ);
+ qdev_init_irq_sink(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
for (i = 0; i < NCPU; i++) {
- s->parent_irq[i] = parent_irq[i];
+ sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
}
- iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
- gic_dist_writefn, s);
- cpu_register_physical_memory(dist_base, 0x00001000,
- iomemtype);
+ s->iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
+ gic_dist_writefn, s);
gic_reset(s);
register_savevm("arm_gic", -1, 1, gic_save, gic_load, s);
- return s;
}
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 1d5619c..6be9940 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -7,7 +7,7 @@
* This code is licenced under the GPL.
*/
-#include "hw.h"
+#include "sysbus.h"
#include "arm-misc.h"
#include "sysemu.h"
@@ -140,11 +140,15 @@
const char *kernel_filename, const char *cpu_model)
{
CPUState *env;
- qemu_irq *pic;
+ DeviceState *nvic;
+ /* FIXME: make this local state. */
+ static qemu_irq pic[64];
+ qemu_irq *cpu_pic;
uint32_t pc;
int image_size;
uint64_t entry;
uint64_t lowaddr;
+ int i;
flash_size *= 1024;
sram_size *= 1024;
@@ -176,7 +180,14 @@
qemu_ram_alloc(sram_size) | IO_MEM_RAM);
armv7m_bitband_init();
- pic = armv7m_nvic_init(env);
+ nvic = qdev_create(NULL, "armv7m_nvic");
+ qdev_set_prop_ptr(nvic, "cpu", env);
+ qdev_init(nvic);
+ cpu_pic = arm_pic_init_cpu(env);
+ sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
+ for (i = 0; i < 64; i++) {
+ pic[i] = qdev_get_irq_sink(nvic, i);
+ }
image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
if (image_size < 0) {
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 306ac38..2a948ac 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -10,7 +10,7 @@
* NVIC. Much of that is also implemented here.
*/
-#include "hw.h"
+#include "sysbus.h"
#include "qemu-timer.h"
#include "arm-misc.h"
@@ -33,13 +33,13 @@
#include "arm_gic.c"
typedef struct {
+ gic_state gic;
struct {
uint32_t control;
uint32_t reload;
int64_t tick;
QEMUTimer *timer;
} systick;
- gic_state *gic;
} nvic_state;
/* qemu timers run at 1GHz. We want something closer to 1MHz. */
@@ -91,7 +91,7 @@
nvic_state *s = (nvic_state *)opaque;
if (irq >= 16)
irq += 16;
- gic_set_pending_private(s->gic, 0, irq);
+ gic_set_pending_private(&s->gic, 0, irq);
}
/* Make pending IRQ active. */
@@ -100,7 +100,7 @@
nvic_state *s = (nvic_state *)opaque;
uint32_t irq;
- irq = gic_acknowledge_irq(s->gic, 0);
+ irq = gic_acknowledge_irq(&s->gic, 0);
if (irq == 1023)
hw_error("Interrupt but no vector\n");
if (irq >= 32)
@@ -113,7 +113,7 @@
nvic_state *s = (nvic_state *)opaque;
if (irq >= 16)
irq += 16;
- gic_complete_irq(s->gic, 0, irq);
+ gic_complete_irq(&s->gic, 0, irq);
}
static uint32_t nvic_readl(void *opaque, uint32_t offset)
@@ -153,35 +153,35 @@
return cpu_single_env->cp15.c0_cpuid;
case 0xd04: /* Interrypt Control State. */
/* VECTACTIVE */
- val = s->gic->running_irq[0];
+ val = s->gic.running_irq[0];
if (val == 1023) {
val = 0;
} else if (val >= 32) {
val -= 16;
}
/* RETTOBASE */
- if (s->gic->running_irq[0] == 1023
- || s->gic->last_active[s->gic->running_irq[0]][0] == 1023) {
+ if (s->gic.running_irq[0] == 1023
+ || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
val |= (1 << 11);
}
/* VECTPENDING */
- if (s->gic->current_pending[0] != 1023)
- val |= (s->gic->current_pending[0] << 12);
+ if (s->gic.current_pending[0] != 1023)
+ val |= (s->gic.current_pending[0] << 12);
/* ISRPENDING */
for (irq = 32; irq < GIC_NIRQ; irq++) {
- if (s->gic->irq_state[irq].pending) {
+ if (s->gic.irq_state[irq].pending) {
val |= (1 << 22);
break;
}
}
/* PENDSTSET */
- if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending)
+ if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
val |= (1 << 26);
/* PENDSVSET */
- if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending)
+ if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
val |= (1 << 28);
/* NMIPENDSET */
- if (s->gic->irq_state[ARMV7M_EXCP_NMI].pending)
+ if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
val |= (1 << 31);
return val;
case 0xd08: /* Vector Table Offset. */
@@ -197,27 +197,27 @@
case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */
irq = offset - 0xd14;
val = 0;
- val = s->gic->priority1[irq++][0];
- val = s->gic->priority1[irq++][0] << 8;
- val = s->gic->priority1[irq++][0] << 16;
- val = s->gic->priority1[irq][0] << 24;
+ val = s->gic.priority1[irq++][0];
+ val = s->gic.priority1[irq++][0] << 8;
+ val = s->gic.priority1[irq++][0] << 16;
+ val = s->gic.priority1[irq][0] << 24;
return val;
case 0xd24: /* System Handler Status. */
val = 0;
- if (s->gic->irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
- if (s->gic->irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
- if (s->gic->irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
- if (s->gic->irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
- if (s->gic->irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
- if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
- if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
- if (s->gic->irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
- if (s->gic->irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
- if (s->gic->irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
- if (s->gic->irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
- if (s->gic->irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
- if (s->gic->irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
- if (s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
+ if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
+ if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
+ if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
+ if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
+ if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
+ if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
+ if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
+ if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
+ if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
+ if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
+ if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
+ if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
+ if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
+ if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
return val;
case 0xd28: /* Configurable Fault Status. */
/* TODO: Implement Fault Status. */
@@ -307,14 +307,14 @@
if (value & (1 << 28)) {
armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
} else if (value & (1 << 27)) {
- s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
- gic_update(s->gic);
+ s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
+ gic_update(&s->gic);
}
if (value & (1 << 26)) {
armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
} else if (value & (1 << 25)) {
- s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
- gic_update(s->gic);
+ s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
+ gic_update(&s->gic);
}
break;
case 0xd08: /* Vector Table Offset. */
@@ -338,19 +338,19 @@
{
int irq;
irq = offset - 0xd14;
- s->gic->priority1[irq++][0] = value & 0xff;
- s->gic->priority1[irq++][0] = (value >> 8) & 0xff;
- s->gic->priority1[irq++][0] = (value >> 16) & 0xff;
- s->gic->priority1[irq][0] = (value >> 24) & 0xff;
- gic_update(s->gic);
+ s->gic.priority1[irq++][0] = value & 0xff;
+ s->gic.priority1[irq++][0] = (value >> 8) & 0xff;
+ s->gic.priority1[irq++][0] = (value >> 16) & 0xff;
+ s->gic.priority1[irq][0] = (value >> 24) & 0xff;
+ gic_update(&s->gic);
}
break;
case 0xd24: /* System Handler Control. */
/* TODO: Real hardware allows you to set/clear the active bits
under some circumstances. We don't implement this. */
- s->gic->irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
- s->gic->irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
- s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
+ s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
+ s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
+ s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
break;
case 0xd28: /* Configurable Fault Status. */
case 0xd2c: /* Hard Fault Status. */
@@ -390,19 +390,24 @@
return 0;
}
-qemu_irq *armv7m_nvic_init(CPUState *env)
+static void armv7m_nvic_init(SysBusDevice *dev)
{
- nvic_state *s;
- qemu_irq *parent;
+ nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
+ CPUState *env;
- parent = arm_pic_init_cpu(env);
- s = (nvic_state *)qemu_mallocz(sizeof(nvic_state));
- s->gic = gic_init(0xe000e000, &parent[ARM_PIC_CPU_IRQ]);
- s->gic->nvic = s;
+ env = qdev_get_prop_ptr(&dev->qdev, "cpu");
+ gic_init(&s->gic);
+ cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype);
s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s);
if (env->v7m.nvic)
hw_error("CPU can only have one NVIC\n");
env->v7m.nvic = s;
register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, s);
- return s->gic->in;
}
+
+static void armv7m_nvic_register_devices(void)
+{
+ sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init);
+}
+
+device_init(armv7m_nvic_register_devices)
diff --git a/hw/mpcore.c b/hw/mpcore.c
index f90f73a..6df9a91 100644
--- a/hw/mpcore.c
+++ b/hw/mpcore.c
@@ -7,9 +7,8 @@
* This code is licenced under the GPL.
*/
-#include "hw.h"
+#include "sysbus.h"
#include "qemu-timer.h"
-#include "primecell.h"
#define MPCORE_PRIV_BASE 0x10100000
#define NCPU 4
@@ -41,8 +40,9 @@
} mpcore_timer_state;
typedef struct mpcore_priv_state {
- gic_state *gic;
+ gic_state gic;
uint32_t scu_control;
+ int iomemtype;
mpcore_timer_state timer[8];
} mpcore_priv_state;
@@ -51,7 +51,7 @@
static inline void mpcore_timer_update_irq(mpcore_timer_state *s)
{
if (s->status & ~s->old_status) {
- gic_set_pending_private(s->mpcore->gic, s->id >> 1, 29 + (s->id & 1));
+ gic_set_pending_private(&s->mpcore->gic, s->id >> 1, 29 + (s->id & 1));
}
s->old_status = s->status;
}
@@ -181,7 +181,7 @@
} else {
id = (offset - 0x200) >> 8;
}
- return gic_cpu_read(s->gic, id, offset & 0xff);
+ return gic_cpu_read(&s->gic, id, offset & 0xff);
} else if (offset < 0xb00) {
/* Timers. */
if (offset < 0x700) {
@@ -224,7 +224,7 @@
} else {
id = (offset - 0x200) >> 8;
}
- gic_cpu_write(s->gic, id, offset & 0xff, value);
+ gic_cpu_write(&s->gic, id, offset & 0xff, value);
} else if (offset < 0xb00) {
/* Timers. */
if (offset < 0x700) {
@@ -255,32 +255,34 @@
mpcore_priv_write
};
-
-static qemu_irq *mpcore_priv_init(uint32_t base, qemu_irq *pic_irq)
+static void mpcore_priv_map(SysBusDevice *dev, target_phys_addr_t base)
{
- mpcore_priv_state *s;
- int iomemtype;
+ mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
+ cpu_register_physical_memory(base, 0x1000, s->iomemtype);
+ cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype);
+}
+
+static void mpcore_priv_init(SysBusDevice *dev)
+{
+ mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
int i;
- s = (mpcore_priv_state *)qemu_mallocz(sizeof(mpcore_priv_state));
- s->gic = gic_init(base + 0x1000, pic_irq);
- if (!s->gic)
- return NULL;
- iomemtype = cpu_register_io_memory(0, mpcore_priv_readfn,
- mpcore_priv_writefn, s);
- cpu_register_physical_memory(base, 0x00001000, iomemtype);
+ gic_init(&s->gic);
+ s->iomemtype = cpu_register_io_memory(0, mpcore_priv_readfn,
+ mpcore_priv_writefn, s);
+ sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map);
for (i = 0; i < 8; i++) {
mpcore_timer_init(s, &s->timer[i], i);
}
- return s->gic->in;
}
/* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
controllers. The output of these, plus some of the raw input lines
are fed into a single SMP-aware interrupt controller on the CPU. */
typedef struct {
- qemu_irq *cpuic;
- qemu_irq *rvic[4];
+ SysBusDevice busdev;
+ qemu_irq cpuic[32];
+ qemu_irq rvic[4][64];
} mpcore_rirq_state;
/* Map baseboard IRQs onto CPU IRQ lines. */
@@ -307,17 +309,36 @@
}
}
-qemu_irq *mpcore_irq_init(qemu_irq *cpu_irq)
+static void realview_mpcore_init(SysBusDevice *dev)
{
- mpcore_rirq_state *s;
+ mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
+ DeviceState *gic;
+ DeviceState *priv;
int n;
+ int i;
- /* ??? IRQ routing is hardcoded to "normal" mode. */
- s = qemu_mallocz(sizeof(mpcore_rirq_state));
- s->cpuic = mpcore_priv_init(MPCORE_PRIV_BASE, cpu_irq);
- for (n = 0; n < 4; n++) {
- s->rvic[n] = realview_gic_init(0x10040000 + n * 0x10000,
- s->cpuic[10 + n]);
+ priv = sysbus_create_simple("arm11mpcore_priv", MPCORE_PRIV_BASE, NULL);
+ sysbus_pass_irq(dev, sysbus_from_qdev(priv));
+ for (i = 0; i < 32; i++) {
+ s->cpuic[i] = qdev_get_irq_sink(priv, i);
}
- return qemu_allocate_irqs(mpcore_rirq_set_irq, s, 64);
+ /* ??? IRQ routing is hardcoded to "normal" mode. */
+ for (n = 0; n < 4; n++) {
+ gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000,
+ s->cpuic[10 + n]);
+ for (i = 0; i < 64; i++) {
+ s->rvic[n][i] = qdev_get_irq_sink(gic, i);
+ }
+ }
+ qdev_init_irq_sink(&dev->qdev, mpcore_rirq_set_irq, 64);
}
+
+static void mpcore_register_devices(void)
+{
+ sysbus_register_dev("realview_mpcore", sizeof(mpcore_rirq_state),
+ realview_mpcore_init);
+ sysbus_register_dev("arm11mpcore_priv", sizeof(mpcore_priv_state),
+ mpcore_priv_init);
+}
+
+device_init(mpcore_register_devices)
diff --git a/hw/primecell.h b/hw/primecell.h
index 7d8aa04..bbc91ec 100644
--- a/hw/primecell.h
+++ b/hw/primecell.h
@@ -17,12 +17,6 @@
/* pl080.c */
void *pl080_init(uint32_t base, qemu_irq irq, int nchannels);
-/* realview_gic.c */
-qemu_irq *realview_gic_init(uint32_t base, qemu_irq parent_irq);
-
-/* mpcore.c */
-extern qemu_irq *mpcore_irq_init(qemu_irq *cpu_irq);
-
/* arm_sysctl.c */
void arm_sysctl_init(uint32_t base, uint32_t sys_id);
diff --git a/hw/realview.c b/hw/realview.c
index 5d7073a..da2948b 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -31,8 +31,9 @@
{
CPUState *env;
ram_addr_t ram_offset;
- qemu_irq *pic;
DeviceState *dev;
+ qemu_irq *irqp;
+ qemu_irq pic[64];
PCIBus *pci_bus;
NICInfo *nd;
int n;
@@ -55,8 +56,8 @@
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
- pic = arm_pic_init_cpu(env);
- cpu_irq[n] = pic[ARM_PIC_CPU_IRQ];
+ irqp = arm_pic_init_cpu(env);
+ cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
if (n > 0) {
/* Set entry point for secondary CPUs. This assumes we're using
the init code from arm_boot.c. Real hardware resets all CPUs
@@ -76,9 +77,14 @@
/* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3
is nIRQ (there are inconsistencies). However Linux 2.6.17 expects
GIC1 to be nIRQ and ignores all the others, so do that for now. */
- pic = realview_gic_init(0x10040000, cpu_irq[0]);
+ dev = sysbus_create_simple("realview_gic", 0x10040000, cpu_irq[0]);
} else {
- pic = mpcore_irq_init(cpu_irq);
+ dev = sysbus_create_varargs("realview_mpcore", -1,
+ cpu_irq[0], cpu_irq[1], cpu_irq[2],
+ cpu_irq[3], NULL);
+ }
+ for (n = 0; n < 64; n++) {
+ pic[n] = qdev_get_irq_sink(dev, n);
}
sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]);
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index e9645c2..cae0f7e 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -7,8 +7,7 @@
* This code is licenced under the GPL.
*/
-#include "hw.h"
-#include "primecell.h"
+#include "sysbus.h"
#define GIC_NIRQ 96
#define NCPU 1
@@ -22,6 +21,11 @@
#include "arm_gic.c"
+typedef struct {
+ gic_state gic;
+ int iomemtype;
+} RealViewGICState;
+
static uint32_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset)
{
gic_state *s = (gic_state *)opaque;
@@ -47,16 +51,27 @@
realview_gic_cpu_write
};
-qemu_irq *realview_gic_init(uint32_t base, qemu_irq parent_irq)
+static void realview_gic_map(SysBusDevice *dev, target_phys_addr_t base)
{
- gic_state *s;
- int iomemtype;
-
- s = gic_init(base + 0x1000, &parent_irq);
- if (!s)
- return NULL;
- iomemtype = cpu_register_io_memory(0, realview_gic_cpu_readfn,
- realview_gic_cpu_writefn, s);
- cpu_register_physical_memory(base, 0x00001000, iomemtype);
- return s->in;
+ RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
+ cpu_register_physical_memory(base, 0x1000, s->iomemtype);
+ cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype);
}
+
+static void realview_gic_init(SysBusDevice *dev)
+{
+ RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
+
+ gic_init(&s->gic);
+ s->iomemtype = cpu_register_io_memory(0, realview_gic_cpu_readfn,
+ realview_gic_cpu_writefn, s);
+ sysbus_init_mmio_cb(dev, 0x2000, realview_gic_map);
+}
+
+static void realview_gic_register_devices(void)
+{
+ sysbus_register_dev("realview_gic", sizeof(RealViewGICState),
+ realview_gic_init);
+}
+
+device_init(realview_gic_register_devices)