diff options
-rw-r--r-- | hw/arm-misc.h | 3 | ||||
-rw-r--r-- | hw/arm_gic.c | 29 | ||||
-rw-r--r-- | hw/armv7m.c | 17 | ||||
-rw-r--r-- | hw/armv7m_nvic.c | 109 | ||||
-rw-r--r-- | hw/mpcore.c | 73 | ||||
-rw-r--r-- | hw/primecell.h | 6 | ||||
-rw-r--r-- | hw/realview.c | 16 | ||||
-rw-r--r-- | hw/realview_gic.c | 39 |
8 files changed, 168 insertions, 124 deletions
diff --git a/hw/arm-misc.h b/hw/arm-misc.h index 32a5e9f664..367dd25c0b 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -34,11 +34,8 @@ struct arm_boot_info { }; 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 cb774d6e20..5dc9448360 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -32,6 +32,9 @@ static const uint8_t gic_id[] = #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_irq_state typedef struct gic_state { + SysBusDevice busdev; qemu_irq parent_irq[NCPU]; int enabled; int cpu_enabled[NCPU]; @@ -91,10 +95,7 @@ typedef struct gic_state 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 @@ static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset) 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 @@ static void gic_dist_writel(void *opaque, target_phys_addr_t offset, 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 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) 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 1d5619c0dd..6be9940bcd 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 @@ qemu_irq *armv7m_init(int flash_size, int sram_size, 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_irq *armv7m_init(int flash_size, int sram_size, 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 306ac38337..2a948ac346 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 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value); #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 @@ void armv7m_nvic_set_pending(void *opaque, int irq) 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 @@ int armv7m_nvic_acknowledge_irq(void *opaque) 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 @@ void armv7m_nvic_complete_irq(void *opaque, int irq) 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 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) 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 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) 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 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) 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 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) { 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 @@ static int nvic_load(QEMUFile *f, void *opaque, int version_id) 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 f90f73a1dd..6df9a91ad3 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 @@ typedef struct { } 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 @@ typedef struct mpcore_priv_state { 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 @@ static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset) } 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 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset, } 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 @@ static CPUWriteMemoryFunc *mpcore_priv_writefn[] = { mpcore_priv_write }; +static void mpcore_priv_map(SysBusDevice *dev, target_phys_addr_t base) +{ + 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 qemu_irq *mpcore_priv_init(uint32_t base, qemu_irq *pic_irq) +static void mpcore_priv_init(SysBusDevice *dev) { - mpcore_priv_state *s; - int iomemtype; + 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 @@ static void mpcore_rirq_set_irq(void *opaque, int irq, int level) } } -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; + 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); + } /* ??? 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]); + 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); + } } - return qemu_allocate_irqs(mpcore_rirq_set_irq, s, 64); + 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 7d8aa04f4f..bbc91ec5ab 100644 --- a/hw/primecell.h +++ b/hw/primecell.h @@ -17,12 +17,6 @@ qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out); /* 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 5d7073a946..da2948b30d 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -31,8 +31,9 @@ static void realview_init(ram_addr_t ram_size, { 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 @@ static void realview_init(ram_addr_t ram_size, 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 @@ static void realview_init(ram_addr_t ram_size, /* ??? 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 e9645c27c0..cae0f7ee72 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 @@ gic_get_current_cpu(void) #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 @@ static CPUWriteMemoryFunc *realview_gic_cpu_writefn[] = { 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; + 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); - 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; + 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) |