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); 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 /* Multiplication factor to convert from system clock ticks to qemu timer
ticks. */ ticks. */
extern int system_clock_scale; extern int system_clock_scale;
qemu_irq *armv7m_nvic_init(CPUState *env);
#endif /* !ARM_MISC_H */ #endif /* !ARM_MISC_H */

View File

@ -32,6 +32,9 @@ static const uint8_t gic_id[] =
#define GIC_BASE_IRQ 0 #define GIC_BASE_IRQ 0
#endif #endif
#define FROM_SYSBUSGIC(type, dev) \
DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev))
typedef struct gic_irq_state typedef struct gic_irq_state
{ {
/* ??? The documentation seems to imply the enable bits are global, even /* ??? The documentation seems to imply the enable bits are global, even
@ -74,6 +77,7 @@ typedef struct gic_irq_state
typedef struct gic_state typedef struct gic_state
{ {
SysBusDevice busdev;
qemu_irq parent_irq[NCPU]; qemu_irq parent_irq[NCPU];
int enabled; int enabled;
int cpu_enabled[NCPU]; int cpu_enabled[NCPU];
@ -91,10 +95,7 @@ typedef struct gic_state
int running_priority[NCPU]; int running_priority[NCPU];
int current_pending[NCPU]; int current_pending[NCPU];
qemu_irq *in; int iomemtype;
#ifdef NVIC
void *nvic;
#endif
} gic_state; } gic_state;
/* TODO: Many places that call this routine could be optimized. */ /* 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; uint32_t addr;
addr = offset; addr = offset;
if (addr < 0x100 || addr > 0xd00) if (addr < 0x100 || addr > 0xd00)
return nvic_readl(s->nvic, addr); return nvic_readl(s, addr);
#endif #endif
val = gic_dist_readw(opaque, offset); val = gic_dist_readw(opaque, offset);
val |= gic_dist_readw(opaque, offset + 2) << 16; 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; uint32_t addr;
addr = offset; addr = offset;
if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) { if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) {
nvic_writel(s->nvic, addr, value); nvic_writel(s, addr, value);
return; return;
} }
#endif #endif
@ -716,22 +717,16 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
return 0; 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; int i;
s = (gic_state *)qemu_mallocz(sizeof(gic_state)); qdev_init_irq_sink(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
s->in = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ);
for (i = 0; i < NCPU; i++) { 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, s->iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
gic_dist_writefn, s); gic_dist_writefn, s);
cpu_register_physical_memory(dist_base, 0x00001000,
iomemtype);
gic_reset(s); gic_reset(s);
register_savevm("arm_gic", -1, 1, gic_save, gic_load, 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. * This code is licenced under the GPL.
*/ */
#include "hw.h" #include "sysbus.h"
#include "arm-misc.h" #include "arm-misc.h"
#include "sysemu.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) const char *kernel_filename, const char *cpu_model)
{ {
CPUState *env; CPUState *env;
qemu_irq *pic; DeviceState *nvic;
/* FIXME: make this local state. */
static qemu_irq pic[64];
qemu_irq *cpu_pic;
uint32_t pc; uint32_t pc;
int image_size; int image_size;
uint64_t entry; uint64_t entry;
uint64_t lowaddr; uint64_t lowaddr;
int i;
flash_size *= 1024; flash_size *= 1024;
sram_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); qemu_ram_alloc(sram_size) | IO_MEM_RAM);
armv7m_bitband_init(); 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); image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
if (image_size < 0) { if (image_size < 0) {

View File

@ -10,7 +10,7 @@
* NVIC. Much of that is also implemented here. * NVIC. Much of that is also implemented here.
*/ */
#include "hw.h" #include "sysbus.h"
#include "qemu-timer.h" #include "qemu-timer.h"
#include "arm-misc.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" #include "arm_gic.c"
typedef struct { typedef struct {
gic_state gic;
struct { struct {
uint32_t control; uint32_t control;
uint32_t reload; uint32_t reload;
int64_t tick; int64_t tick;
QEMUTimer *timer; QEMUTimer *timer;
} systick; } systick;
gic_state *gic;
} nvic_state; } nvic_state;
/* qemu timers run at 1GHz. We want something closer to 1MHz. */ /* 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; nvic_state *s = (nvic_state *)opaque;
if (irq >= 16) if (irq >= 16)
irq += 16; irq += 16;
gic_set_pending_private(s->gic, 0, irq); gic_set_pending_private(&s->gic, 0, irq);
} }
/* Make pending IRQ active. */ /* Make pending IRQ active. */
@ -100,7 +100,7 @@ int armv7m_nvic_acknowledge_irq(void *opaque)
nvic_state *s = (nvic_state *)opaque; nvic_state *s = (nvic_state *)opaque;
uint32_t irq; uint32_t irq;
irq = gic_acknowledge_irq(s->gic, 0); irq = gic_acknowledge_irq(&s->gic, 0);
if (irq == 1023) if (irq == 1023)
hw_error("Interrupt but no vector\n"); hw_error("Interrupt but no vector\n");
if (irq >= 32) if (irq >= 32)
@ -113,7 +113,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq)
nvic_state *s = (nvic_state *)opaque; nvic_state *s = (nvic_state *)opaque;
if (irq >= 16) if (irq >= 16)
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) 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; return cpu_single_env->cp15.c0_cpuid;
case 0xd04: /* Interrypt Control State. */ case 0xd04: /* Interrypt Control State. */
/* VECTACTIVE */ /* VECTACTIVE */
val = s->gic->running_irq[0]; val = s->gic.running_irq[0];
if (val == 1023) { if (val == 1023) {
val = 0; val = 0;
} else if (val >= 32) { } else if (val >= 32) {
val -= 16; val -= 16;
} }
/* RETTOBASE */ /* RETTOBASE */
if (s->gic->running_irq[0] == 1023 if (s->gic.running_irq[0] == 1023
|| s->gic->last_active[s->gic->running_irq[0]][0] == 1023) { || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
val |= (1 << 11); val |= (1 << 11);
} }
/* VECTPENDING */ /* VECTPENDING */
if (s->gic->current_pending[0] != 1023) if (s->gic.current_pending[0] != 1023)
val |= (s->gic->current_pending[0] << 12); val |= (s->gic.current_pending[0] << 12);
/* ISRPENDING */ /* ISRPENDING */
for (irq = 32; irq < GIC_NIRQ; irq++) { for (irq = 32; irq < GIC_NIRQ; irq++) {
if (s->gic->irq_state[irq].pending) { if (s->gic.irq_state[irq].pending) {
val |= (1 << 22); val |= (1 << 22);
break; break;
} }
} }
/* PENDSTSET */ /* PENDSTSET */
if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending) if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
val |= (1 << 26); val |= (1 << 26);
/* PENDSVSET */ /* PENDSVSET */
if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending) if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
val |= (1 << 28); val |= (1 << 28);
/* NMIPENDSET */ /* NMIPENDSET */
if (s->gic->irq_state[ARMV7M_EXCP_NMI].pending) if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
val |= (1 << 31); val |= (1 << 31);
return val; return val;
case 0xd08: /* Vector Table Offset. */ 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. */ case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */
irq = offset - 0xd14; irq = offset - 0xd14;
val = 0; val = 0;
val = s->gic->priority1[irq++][0]; val = s->gic.priority1[irq++][0];
val = s->gic->priority1[irq++][0] << 8; val = s->gic.priority1[irq++][0] << 8;
val = s->gic->priority1[irq++][0] << 16; val = s->gic.priority1[irq++][0] << 16;
val = s->gic->priority1[irq][0] << 24; val = s->gic.priority1[irq][0] << 24;
return val; return val;
case 0xd24: /* System Handler Status. */ case 0xd24: /* System Handler Status. */
val = 0; val = 0;
if (s->gic->irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 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_BUS].active) val |= (1 << 1);
if (s->gic->irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3); 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_SVC].active) val |= (1 << 7);
if (s->gic->irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8); 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_PENDSV].active) val |= (1 << 10);
if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11); 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_USAGE].pending) val |= (1 << 12);
if (s->gic->irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13); 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_BUS].pending) val |= (1 << 14);
if (s->gic->irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15); 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_MEM].enabled) val |= (1 << 16);
if (s->gic->irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17); 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_USAGE].enabled) val |= (1 << 18);
return val; return val;
case 0xd28: /* Configurable Fault Status. */ case 0xd28: /* Configurable Fault Status. */
/* TODO: Implement 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)) { if (value & (1 << 28)) {
armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV); armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
} else if (value & (1 << 27)) { } else if (value & (1 << 27)) {
s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending = 0; s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
gic_update(s->gic); gic_update(&s->gic);
} }
if (value & (1 << 26)) { if (value & (1 << 26)) {
armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
} else if (value & (1 << 25)) { } else if (value & (1 << 25)) {
s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending = 0; s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
gic_update(s->gic); gic_update(&s->gic);
} }
break; break;
case 0xd08: /* Vector Table Offset. */ case 0xd08: /* Vector Table Offset. */
@ -338,19 +338,19 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
{ {
int irq; int irq;
irq = offset - 0xd14; irq = offset - 0xd14;
s->gic->priority1[irq++][0] = value & 0xff; s->gic.priority1[irq++][0] = value & 0xff;
s->gic->priority1[irq++][0] = (value >> 8) & 0xff; s->gic.priority1[irq++][0] = (value >> 8) & 0xff;
s->gic->priority1[irq++][0] = (value >> 16) & 0xff; s->gic.priority1[irq++][0] = (value >> 16) & 0xff;
s->gic->priority1[irq][0] = (value >> 24) & 0xff; s->gic.priority1[irq][0] = (value >> 24) & 0xff;
gic_update(s->gic); gic_update(&s->gic);
} }
break; break;
case 0xd24: /* System Handler Control. */ case 0xd24: /* System Handler Control. */
/* TODO: Real hardware allows you to set/clear the active bits /* TODO: Real hardware allows you to set/clear the active bits
under some circumstances. We don't implement this. */ 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_MEM].enabled = (value & (1 << 16)) != 0;
s->gic->irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 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_USAGE].enabled = (value & (1 << 18)) != 0;
break; break;
case 0xd28: /* Configurable Fault Status. */ case 0xd28: /* Configurable Fault Status. */
case 0xd2c: /* Hard Fault Status. */ case 0xd2c: /* Hard Fault Status. */
@ -390,19 +390,24 @@ static int nvic_load(QEMUFile *f, void *opaque, int version_id)
return 0; return 0;
} }
qemu_irq *armv7m_nvic_init(CPUState *env) static void armv7m_nvic_init(SysBusDevice *dev)
{ {
nvic_state *s; nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
qemu_irq *parent; CPUState *env;
parent = arm_pic_init_cpu(env); env = qdev_get_prop_ptr(&dev->qdev, "cpu");
s = (nvic_state *)qemu_mallocz(sizeof(nvic_state)); gic_init(&s->gic);
s->gic = gic_init(0xe000e000, &parent[ARM_PIC_CPU_IRQ]); cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype);
s->gic->nvic = s;
s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s); s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s);
if (env->v7m.nvic) if (env->v7m.nvic)
hw_error("CPU can only have one NVIC\n"); hw_error("CPU can only have one NVIC\n");
env->v7m.nvic = s; env->v7m.nvic = s;
register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, 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. * This code is licenced under the GPL.
*/ */
#include "hw.h" #include "sysbus.h"
#include "qemu-timer.h" #include "qemu-timer.h"
#include "primecell.h"
#define MPCORE_PRIV_BASE 0x10100000 #define MPCORE_PRIV_BASE 0x10100000
#define NCPU 4 #define NCPU 4
@ -41,8 +40,9 @@ typedef struct {
} mpcore_timer_state; } mpcore_timer_state;
typedef struct mpcore_priv_state { typedef struct mpcore_priv_state {
gic_state *gic; gic_state gic;
uint32_t scu_control; uint32_t scu_control;
int iomemtype;
mpcore_timer_state timer[8]; mpcore_timer_state timer[8];
} mpcore_priv_state; } mpcore_priv_state;
@ -51,7 +51,7 @@ typedef struct mpcore_priv_state {
static inline void mpcore_timer_update_irq(mpcore_timer_state *s) static inline void mpcore_timer_update_irq(mpcore_timer_state *s)
{ {
if (s->status & ~s->old_status) { 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; s->old_status = s->status;
} }
@ -181,7 +181,7 @@ static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset)
} else { } else {
id = (offset - 0x200) >> 8; 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) { } else if (offset < 0xb00) {
/* Timers. */ /* Timers. */
if (offset < 0x700) { if (offset < 0x700) {
@ -224,7 +224,7 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
} else { } else {
id = (offset - 0x200) >> 8; 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) { } else if (offset < 0xb00) {
/* Timers. */ /* Timers. */
if (offset < 0x700) { if (offset < 0x700) {
@ -255,32 +255,34 @@ static CPUWriteMemoryFunc *mpcore_priv_writefn[] = {
mpcore_priv_write mpcore_priv_write
}; };
static void mpcore_priv_map(SysBusDevice *dev, target_phys_addr_t base)
static qemu_irq *mpcore_priv_init(uint32_t base, qemu_irq *pic_irq)
{ {
mpcore_priv_state *s; mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
int iomemtype; 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; int i;
s = (mpcore_priv_state *)qemu_mallocz(sizeof(mpcore_priv_state)); gic_init(&s->gic);
s->gic = gic_init(base + 0x1000, pic_irq); s->iomemtype = cpu_register_io_memory(0, mpcore_priv_readfn,
if (!s->gic)
return NULL;
iomemtype = cpu_register_io_memory(0, mpcore_priv_readfn,
mpcore_priv_writefn, s); mpcore_priv_writefn, s);
cpu_register_physical_memory(base, 0x00001000, iomemtype); sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
mpcore_timer_init(s, &s->timer[i], 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 /* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
controllers. The output of these, plus some of the raw input lines controllers. The output of these, plus some of the raw input lines
are fed into a single SMP-aware interrupt controller on the CPU. */ are fed into a single SMP-aware interrupt controller on the CPU. */
typedef struct { typedef struct {
qemu_irq *cpuic; SysBusDevice busdev;
qemu_irq *rvic[4]; qemu_irq cpuic[32];
qemu_irq rvic[4][64];
} mpcore_rirq_state; } mpcore_rirq_state;
/* Map baseboard IRQs onto CPU IRQ lines. */ /* 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 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. */ /* ??? 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++) { for (n = 0; n < 4; n++) {
s->rvic[n] = realview_gic_init(0x10040000 + n * 0x10000, gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000,
s->cpuic[10 + n]); 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)

View File

@ -17,12 +17,6 @@ qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out);
/* pl080.c */ /* pl080.c */
void *pl080_init(uint32_t base, qemu_irq irq, int nchannels); 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 */ /* arm_sysctl.c */
void arm_sysctl_init(uint32_t base, uint32_t sys_id); 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; CPUState *env;
ram_addr_t ram_offset; ram_addr_t ram_offset;
qemu_irq *pic;
DeviceState *dev; DeviceState *dev;
qemu_irq *irqp;
qemu_irq pic[64];
PCIBus *pci_bus; PCIBus *pci_bus;
NICInfo *nd; NICInfo *nd;
int n; int n;
@ -55,8 +56,8 @@ static void realview_init(ram_addr_t ram_size,
fprintf(stderr, "Unable to find CPU definition\n"); fprintf(stderr, "Unable to find CPU definition\n");
exit(1); exit(1);
} }
pic = arm_pic_init_cpu(env); irqp = arm_pic_init_cpu(env);
cpu_irq[n] = pic[ARM_PIC_CPU_IRQ]; cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
if (n > 0) { if (n > 0) {
/* Set entry point for secondary CPUs. This assumes we're using /* Set entry point for secondary CPUs. This assumes we're using
the init code from arm_boot.c. Real hardware resets all CPUs 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 /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3
is nIRQ (there are inconsistencies). However Linux 2.6.17 expects 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. */ 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 { } 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]); sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]);

View File

@ -7,8 +7,7 @@
* This code is licenced under the GPL. * This code is licenced under the GPL.
*/ */
#include "hw.h" #include "sysbus.h"
#include "primecell.h"
#define GIC_NIRQ 96 #define GIC_NIRQ 96
#define NCPU 1 #define NCPU 1
@ -22,6 +21,11 @@ gic_get_current_cpu(void)
#include "arm_gic.c" #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) static uint32_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset)
{ {
gic_state *s = (gic_state *)opaque; gic_state *s = (gic_state *)opaque;
@ -47,16 +51,27 @@ static CPUWriteMemoryFunc *realview_gic_cpu_writefn[] = {
realview_gic_cpu_write 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; RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
int iomemtype; cpu_register_physical_memory(base, 0x1000, s->iomemtype);
cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.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;
} }
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)