ARM GIC qdev conversion
Signed-off-by: Paul Brook <paul@codesourcery.com>
This commit is contained in:
parent
0027b06d0e
commit
fe7e8758d0
@ -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 */
|
||||
|
29
hw/arm_gic.c
29
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;
|
||||
}
|
||||
|
17
hw/armv7m.c
17
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) {
|
||||
|
109
hw/armv7m_nvic.c
109
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)
|
||||
|
79
hw/mpcore.c
79
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 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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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]);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user