ARM GIC qdev conversion

Signed-off-by: Paul Brook <paul@codesourcery.com>
This commit is contained in:
Paul Brook 2009-05-14 22:35:08 +01:00
parent 0027b06d0e
commit fe7e8758d0
8 changed files with 172 additions and 128 deletions

View file

@ -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 */

View file

@ -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;
}

View file

@ -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) {

View file

@ -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)

View file

@ -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 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 @@ 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;
/* ??? 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)

View file

@ -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);

View file

@ -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]);

View file

@ -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;
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)