d4715c4183
Currently for both qemu-system-arm and qemu-system-aarch64 the default board model if the user doesn't specify one is the 'integratorcp'. This is a totally arbitrary historical accident since it was the first board to be modelled. That board is now just one target among many for us, and is a very poor choice of default: * it's an ancient board that is now only found in the junkpiles of longtime ARM/Linux hackers, if at all * it's an ARMv5 CPU, when most distros are now assuming ARMv7 * it's pretty much unmaintained in QEMU * it doesn't even have versatilepb's advantage of supporting PCI Making it or any other board the default serves only to confuse people new to ARM who expect something more like the x86 monoculture. Remove the is_default marker from integratorcp, and don't set it for any other board, to give users a nudge that they need to think about which board they want a QEMU model of. (QEMU will produce the admittedly slightly cryptic error "No machine found.") Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
588 lines
17 KiB
C
588 lines
17 KiB
C
/*
|
|
* ARM Integrator CP System emulation.
|
|
*
|
|
* Copyright (c) 2005-2007 CodeSourcery.
|
|
* Written by Paul Brook
|
|
*
|
|
* This code is licensed under the GPL
|
|
*/
|
|
|
|
#include "hw/sysbus.h"
|
|
#include "hw/devices.h"
|
|
#include "hw/boards.h"
|
|
#include "hw/arm/arm.h"
|
|
#include "hw/misc/arm_integrator_debug.h"
|
|
#include "net/net.h"
|
|
#include "exec/address-spaces.h"
|
|
#include "sysemu/sysemu.h"
|
|
|
|
#define TYPE_INTEGRATOR_CM "integrator_core"
|
|
#define INTEGRATOR_CM(obj) \
|
|
OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM)
|
|
|
|
typedef struct IntegratorCMState {
|
|
/*< private >*/
|
|
SysBusDevice parent_obj;
|
|
/*< public >*/
|
|
|
|
MemoryRegion iomem;
|
|
uint32_t memsz;
|
|
MemoryRegion flash;
|
|
uint32_t cm_osc;
|
|
uint32_t cm_ctrl;
|
|
uint32_t cm_lock;
|
|
uint32_t cm_auxosc;
|
|
uint32_t cm_sdram;
|
|
uint32_t cm_init;
|
|
uint32_t cm_flags;
|
|
uint32_t cm_nvflags;
|
|
uint32_t cm_refcnt_offset;
|
|
uint32_t int_level;
|
|
uint32_t irq_enabled;
|
|
uint32_t fiq_enabled;
|
|
} IntegratorCMState;
|
|
|
|
static uint8_t integrator_spd[128] = {
|
|
128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
|
|
0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
|
|
};
|
|
|
|
static uint64_t integratorcm_read(void *opaque, hwaddr offset,
|
|
unsigned size)
|
|
{
|
|
IntegratorCMState *s = opaque;
|
|
if (offset >= 0x100 && offset < 0x200) {
|
|
/* CM_SPD */
|
|
if (offset >= 0x180)
|
|
return 0;
|
|
return integrator_spd[offset >> 2];
|
|
}
|
|
switch (offset >> 2) {
|
|
case 0: /* CM_ID */
|
|
return 0x411a3001;
|
|
case 1: /* CM_PROC */
|
|
return 0;
|
|
case 2: /* CM_OSC */
|
|
return s->cm_osc;
|
|
case 3: /* CM_CTRL */
|
|
return s->cm_ctrl;
|
|
case 4: /* CM_STAT */
|
|
return 0x00100000;
|
|
case 5: /* CM_LOCK */
|
|
if (s->cm_lock == 0xa05f) {
|
|
return 0x1a05f;
|
|
} else {
|
|
return s->cm_lock;
|
|
}
|
|
case 6: /* CM_LMBUSCNT */
|
|
/* ??? High frequency timer. */
|
|
hw_error("integratorcm_read: CM_LMBUSCNT");
|
|
case 7: /* CM_AUXOSC */
|
|
return s->cm_auxosc;
|
|
case 8: /* CM_SDRAM */
|
|
return s->cm_sdram;
|
|
case 9: /* CM_INIT */
|
|
return s->cm_init;
|
|
case 10: /* CM_REFCNT */
|
|
/* This register, CM_REFCNT, provides a 32-bit count value.
|
|
* The count increments at the fixed reference clock frequency of 24MHz
|
|
* and can be used as a real-time counter.
|
|
*/
|
|
return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
|
|
1000) - s->cm_refcnt_offset;
|
|
case 12: /* CM_FLAGS */
|
|
return s->cm_flags;
|
|
case 14: /* CM_NVFLAGS */
|
|
return s->cm_nvflags;
|
|
case 16: /* CM_IRQ_STAT */
|
|
return s->int_level & s->irq_enabled;
|
|
case 17: /* CM_IRQ_RSTAT */
|
|
return s->int_level;
|
|
case 18: /* CM_IRQ_ENSET */
|
|
return s->irq_enabled;
|
|
case 20: /* CM_SOFT_INTSET */
|
|
return s->int_level & 1;
|
|
case 24: /* CM_FIQ_STAT */
|
|
return s->int_level & s->fiq_enabled;
|
|
case 25: /* CM_FIQ_RSTAT */
|
|
return s->int_level;
|
|
case 26: /* CM_FIQ_ENSET */
|
|
return s->fiq_enabled;
|
|
case 32: /* CM_VOLTAGE_CTL0 */
|
|
case 33: /* CM_VOLTAGE_CTL1 */
|
|
case 34: /* CM_VOLTAGE_CTL2 */
|
|
case 35: /* CM_VOLTAGE_CTL3 */
|
|
/* ??? Voltage control unimplemented. */
|
|
return 0;
|
|
default:
|
|
hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
|
|
(int)offset);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void integratorcm_do_remap(IntegratorCMState *s)
|
|
{
|
|
/* Sync memory region state with CM_CTRL REMAP bit:
|
|
* bit 0 => flash at address 0; bit 1 => RAM
|
|
*/
|
|
memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
|
|
}
|
|
|
|
static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value)
|
|
{
|
|
if (value & 8) {
|
|
qemu_system_reset_request();
|
|
}
|
|
if ((s->cm_ctrl ^ value) & 1) {
|
|
/* (value & 1) != 0 means the green "MISC LED" is lit.
|
|
* We don't have any nice place to display LEDs. printf is a bad
|
|
* idea because Linux uses the LED as a heartbeat and the output
|
|
* will swamp anything else on the terminal.
|
|
*/
|
|
}
|
|
/* Note that the RESET bit [3] always reads as zero */
|
|
s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
|
|
integratorcm_do_remap(s);
|
|
}
|
|
|
|
static void integratorcm_update(IntegratorCMState *s)
|
|
{
|
|
/* ??? The CPU irq/fiq is raised when either the core module or base PIC
|
|
are active. */
|
|
if (s->int_level & (s->irq_enabled | s->fiq_enabled))
|
|
hw_error("Core module interrupt\n");
|
|
}
|
|
|
|
static void integratorcm_write(void *opaque, hwaddr offset,
|
|
uint64_t value, unsigned size)
|
|
{
|
|
IntegratorCMState *s = opaque;
|
|
switch (offset >> 2) {
|
|
case 2: /* CM_OSC */
|
|
if (s->cm_lock == 0xa05f)
|
|
s->cm_osc = value;
|
|
break;
|
|
case 3: /* CM_CTRL */
|
|
integratorcm_set_ctrl(s, value);
|
|
break;
|
|
case 5: /* CM_LOCK */
|
|
s->cm_lock = value & 0xffff;
|
|
break;
|
|
case 7: /* CM_AUXOSC */
|
|
if (s->cm_lock == 0xa05f)
|
|
s->cm_auxosc = value;
|
|
break;
|
|
case 8: /* CM_SDRAM */
|
|
s->cm_sdram = value;
|
|
break;
|
|
case 9: /* CM_INIT */
|
|
/* ??? This can change the memory bus frequency. */
|
|
s->cm_init = value;
|
|
break;
|
|
case 12: /* CM_FLAGSS */
|
|
s->cm_flags |= value;
|
|
break;
|
|
case 13: /* CM_FLAGSC */
|
|
s->cm_flags &= ~value;
|
|
break;
|
|
case 14: /* CM_NVFLAGSS */
|
|
s->cm_nvflags |= value;
|
|
break;
|
|
case 15: /* CM_NVFLAGSS */
|
|
s->cm_nvflags &= ~value;
|
|
break;
|
|
case 18: /* CM_IRQ_ENSET */
|
|
s->irq_enabled |= value;
|
|
integratorcm_update(s);
|
|
break;
|
|
case 19: /* CM_IRQ_ENCLR */
|
|
s->irq_enabled &= ~value;
|
|
integratorcm_update(s);
|
|
break;
|
|
case 20: /* CM_SOFT_INTSET */
|
|
s->int_level |= (value & 1);
|
|
integratorcm_update(s);
|
|
break;
|
|
case 21: /* CM_SOFT_INTCLR */
|
|
s->int_level &= ~(value & 1);
|
|
integratorcm_update(s);
|
|
break;
|
|
case 26: /* CM_FIQ_ENSET */
|
|
s->fiq_enabled |= value;
|
|
integratorcm_update(s);
|
|
break;
|
|
case 27: /* CM_FIQ_ENCLR */
|
|
s->fiq_enabled &= ~value;
|
|
integratorcm_update(s);
|
|
break;
|
|
case 32: /* CM_VOLTAGE_CTL0 */
|
|
case 33: /* CM_VOLTAGE_CTL1 */
|
|
case 34: /* CM_VOLTAGE_CTL2 */
|
|
case 35: /* CM_VOLTAGE_CTL3 */
|
|
/* ??? Voltage control unimplemented. */
|
|
break;
|
|
default:
|
|
hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
|
|
(int)offset);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Integrator/CM control registers. */
|
|
|
|
static const MemoryRegionOps integratorcm_ops = {
|
|
.read = integratorcm_read,
|
|
.write = integratorcm_write,
|
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
|
};
|
|
|
|
static int integratorcm_init(SysBusDevice *dev)
|
|
{
|
|
IntegratorCMState *s = INTEGRATOR_CM(dev);
|
|
|
|
s->cm_osc = 0x01000048;
|
|
/* ??? What should the high bits of this value be? */
|
|
s->cm_auxosc = 0x0007feff;
|
|
s->cm_sdram = 0x00011122;
|
|
if (s->memsz >= 256) {
|
|
integrator_spd[31] = 64;
|
|
s->cm_sdram |= 0x10;
|
|
} else if (s->memsz >= 128) {
|
|
integrator_spd[31] = 32;
|
|
s->cm_sdram |= 0x0c;
|
|
} else if (s->memsz >= 64) {
|
|
integrator_spd[31] = 16;
|
|
s->cm_sdram |= 0x08;
|
|
} else if (s->memsz >= 32) {
|
|
integrator_spd[31] = 4;
|
|
s->cm_sdram |= 0x04;
|
|
} else {
|
|
integrator_spd[31] = 2;
|
|
}
|
|
memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
|
|
s->cm_init = 0x00000112;
|
|
s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
|
|
1000);
|
|
memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000);
|
|
vmstate_register_ram_global(&s->flash);
|
|
|
|
memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s,
|
|
"integratorcm", 0x00800000);
|
|
sysbus_init_mmio(dev, &s->iomem);
|
|
|
|
integratorcm_do_remap(s);
|
|
/* ??? Save/restore. */
|
|
return 0;
|
|
}
|
|
|
|
/* Integrator/CP hardware emulation. */
|
|
/* Primary interrupt controller. */
|
|
|
|
#define TYPE_INTEGRATOR_PIC "integrator_pic"
|
|
#define INTEGRATOR_PIC(obj) \
|
|
OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC)
|
|
|
|
typedef struct icp_pic_state {
|
|
/*< private >*/
|
|
SysBusDevice parent_obj;
|
|
/*< public >*/
|
|
|
|
MemoryRegion iomem;
|
|
uint32_t level;
|
|
uint32_t irq_enabled;
|
|
uint32_t fiq_enabled;
|
|
qemu_irq parent_irq;
|
|
qemu_irq parent_fiq;
|
|
} icp_pic_state;
|
|
|
|
static void icp_pic_update(icp_pic_state *s)
|
|
{
|
|
uint32_t flags;
|
|
|
|
flags = (s->level & s->irq_enabled);
|
|
qemu_set_irq(s->parent_irq, flags != 0);
|
|
flags = (s->level & s->fiq_enabled);
|
|
qemu_set_irq(s->parent_fiq, flags != 0);
|
|
}
|
|
|
|
static void icp_pic_set_irq(void *opaque, int irq, int level)
|
|
{
|
|
icp_pic_state *s = (icp_pic_state *)opaque;
|
|
if (level)
|
|
s->level |= 1 << irq;
|
|
else
|
|
s->level &= ~(1 << irq);
|
|
icp_pic_update(s);
|
|
}
|
|
|
|
static uint64_t icp_pic_read(void *opaque, hwaddr offset,
|
|
unsigned size)
|
|
{
|
|
icp_pic_state *s = (icp_pic_state *)opaque;
|
|
|
|
switch (offset >> 2) {
|
|
case 0: /* IRQ_STATUS */
|
|
return s->level & s->irq_enabled;
|
|
case 1: /* IRQ_RAWSTAT */
|
|
return s->level;
|
|
case 2: /* IRQ_ENABLESET */
|
|
return s->irq_enabled;
|
|
case 4: /* INT_SOFTSET */
|
|
return s->level & 1;
|
|
case 8: /* FRQ_STATUS */
|
|
return s->level & s->fiq_enabled;
|
|
case 9: /* FRQ_RAWSTAT */
|
|
return s->level;
|
|
case 10: /* FRQ_ENABLESET */
|
|
return s->fiq_enabled;
|
|
case 3: /* IRQ_ENABLECLR */
|
|
case 5: /* INT_SOFTCLR */
|
|
case 11: /* FRQ_ENABLECLR */
|
|
default:
|
|
printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void icp_pic_write(void *opaque, hwaddr offset,
|
|
uint64_t value, unsigned size)
|
|
{
|
|
icp_pic_state *s = (icp_pic_state *)opaque;
|
|
|
|
switch (offset >> 2) {
|
|
case 2: /* IRQ_ENABLESET */
|
|
s->irq_enabled |= value;
|
|
break;
|
|
case 3: /* IRQ_ENABLECLR */
|
|
s->irq_enabled &= ~value;
|
|
break;
|
|
case 4: /* INT_SOFTSET */
|
|
if (value & 1)
|
|
icp_pic_set_irq(s, 0, 1);
|
|
break;
|
|
case 5: /* INT_SOFTCLR */
|
|
if (value & 1)
|
|
icp_pic_set_irq(s, 0, 0);
|
|
break;
|
|
case 10: /* FRQ_ENABLESET */
|
|
s->fiq_enabled |= value;
|
|
break;
|
|
case 11: /* FRQ_ENABLECLR */
|
|
s->fiq_enabled &= ~value;
|
|
break;
|
|
case 0: /* IRQ_STATUS */
|
|
case 1: /* IRQ_RAWSTAT */
|
|
case 8: /* FRQ_STATUS */
|
|
case 9: /* FRQ_RAWSTAT */
|
|
default:
|
|
printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
|
|
return;
|
|
}
|
|
icp_pic_update(s);
|
|
}
|
|
|
|
static const MemoryRegionOps icp_pic_ops = {
|
|
.read = icp_pic_read,
|
|
.write = icp_pic_write,
|
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
|
};
|
|
|
|
static int icp_pic_init(SysBusDevice *sbd)
|
|
{
|
|
DeviceState *dev = DEVICE(sbd);
|
|
icp_pic_state *s = INTEGRATOR_PIC(dev);
|
|
|
|
qdev_init_gpio_in(dev, icp_pic_set_irq, 32);
|
|
sysbus_init_irq(sbd, &s->parent_irq);
|
|
sysbus_init_irq(sbd, &s->parent_fiq);
|
|
memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s,
|
|
"icp-pic", 0x00800000);
|
|
sysbus_init_mmio(sbd, &s->iomem);
|
|
return 0;
|
|
}
|
|
|
|
/* CP control registers. */
|
|
|
|
static uint64_t icp_control_read(void *opaque, hwaddr offset,
|
|
unsigned size)
|
|
{
|
|
switch (offset >> 2) {
|
|
case 0: /* CP_IDFIELD */
|
|
return 0x41034003;
|
|
case 1: /* CP_FLASHPROG */
|
|
return 0;
|
|
case 2: /* CP_INTREG */
|
|
return 0;
|
|
case 3: /* CP_DECODE */
|
|
return 0x11;
|
|
default:
|
|
hw_error("icp_control_read: Bad offset %x\n", (int)offset);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void icp_control_write(void *opaque, hwaddr offset,
|
|
uint64_t value, unsigned size)
|
|
{
|
|
switch (offset >> 2) {
|
|
case 1: /* CP_FLASHPROG */
|
|
case 2: /* CP_INTREG */
|
|
case 3: /* CP_DECODE */
|
|
/* Nothing interesting implemented yet. */
|
|
break;
|
|
default:
|
|
hw_error("icp_control_write: Bad offset %x\n", (int)offset);
|
|
}
|
|
}
|
|
|
|
static const MemoryRegionOps icp_control_ops = {
|
|
.read = icp_control_read,
|
|
.write = icp_control_write,
|
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
|
};
|
|
|
|
static void icp_control_init(hwaddr base)
|
|
{
|
|
MemoryRegion *io;
|
|
|
|
io = (MemoryRegion *)g_malloc0(sizeof(MemoryRegion));
|
|
memory_region_init_io(io, NULL, &icp_control_ops, NULL,
|
|
"control", 0x00800000);
|
|
memory_region_add_subregion(get_system_memory(), base, io);
|
|
/* ??? Save/restore. */
|
|
}
|
|
|
|
|
|
/* Board init. */
|
|
|
|
static struct arm_boot_info integrator_binfo = {
|
|
.loader_start = 0x0,
|
|
.board_id = 0x113,
|
|
};
|
|
|
|
static void integratorcp_init(QEMUMachineInitArgs *args)
|
|
{
|
|
ram_addr_t ram_size = args->ram_size;
|
|
const char *cpu_model = args->cpu_model;
|
|
const char *kernel_filename = args->kernel_filename;
|
|
const char *kernel_cmdline = args->kernel_cmdline;
|
|
const char *initrd_filename = args->initrd_filename;
|
|
ARMCPU *cpu;
|
|
MemoryRegion *address_space_mem = get_system_memory();
|
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
|
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
|
qemu_irq pic[32];
|
|
DeviceState *dev;
|
|
int i;
|
|
|
|
if (!cpu_model) {
|
|
cpu_model = "arm926";
|
|
}
|
|
cpu = cpu_arm_init(cpu_model);
|
|
if (!cpu) {
|
|
fprintf(stderr, "Unable to find CPU definition\n");
|
|
exit(1);
|
|
}
|
|
|
|
memory_region_init_ram(ram, NULL, "integrator.ram", ram_size);
|
|
vmstate_register_ram_global(ram);
|
|
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
|
|
/* ??? RAM should repeat to fill physical memory space. */
|
|
/* SDRAM at address zero*/
|
|
memory_region_add_subregion(address_space_mem, 0, ram);
|
|
/* And again at address 0x80000000 */
|
|
memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
|
|
memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
|
|
|
|
dev = qdev_create(NULL, TYPE_INTEGRATOR_CM);
|
|
qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
|
|
qdev_init_nofail(dev);
|
|
sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
|
|
|
|
dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000,
|
|
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
|
|
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
|
|
NULL);
|
|
for (i = 0; i < 32; i++) {
|
|
pic[i] = qdev_get_gpio_in(dev, i);
|
|
}
|
|
sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
|
|
sysbus_create_varargs("integrator_pit", 0x13000000,
|
|
pic[5], pic[6], pic[7], NULL);
|
|
sysbus_create_simple("pl031", 0x15000000, pic[8]);
|
|
sysbus_create_simple("pl011", 0x16000000, pic[1]);
|
|
sysbus_create_simple("pl011", 0x17000000, pic[2]);
|
|
icp_control_init(0xcb000000);
|
|
sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
|
|
sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
|
|
sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
|
|
sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
|
|
if (nd_table[0].used)
|
|
smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
|
|
|
|
sysbus_create_simple("pl110", 0xc0000000, pic[22]);
|
|
|
|
integrator_binfo.ram_size = ram_size;
|
|
integrator_binfo.kernel_filename = kernel_filename;
|
|
integrator_binfo.kernel_cmdline = kernel_cmdline;
|
|
integrator_binfo.initrd_filename = initrd_filename;
|
|
arm_load_kernel(cpu, &integrator_binfo);
|
|
}
|
|
|
|
static QEMUMachine integratorcp_machine = {
|
|
.name = "integratorcp",
|
|
.desc = "ARM Integrator/CP (ARM926EJ-S)",
|
|
.init = integratorcp_init,
|
|
};
|
|
|
|
static void integratorcp_machine_init(void)
|
|
{
|
|
qemu_register_machine(&integratorcp_machine);
|
|
}
|
|
|
|
machine_init(integratorcp_machine_init);
|
|
|
|
static Property core_properties[] = {
|
|
DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0),
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
};
|
|
|
|
static void core_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
|
|
|
k->init = integratorcm_init;
|
|
dc->props = core_properties;
|
|
}
|
|
|
|
static const TypeInfo core_info = {
|
|
.name = TYPE_INTEGRATOR_CM,
|
|
.parent = TYPE_SYS_BUS_DEVICE,
|
|
.instance_size = sizeof(IntegratorCMState),
|
|
.class_init = core_class_init,
|
|
};
|
|
|
|
static void icp_pic_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
|
|
|
|
sdc->init = icp_pic_init;
|
|
}
|
|
|
|
static const TypeInfo icp_pic_info = {
|
|
.name = TYPE_INTEGRATOR_PIC,
|
|
.parent = TYPE_SYS_BUS_DEVICE,
|
|
.instance_size = sizeof(icp_pic_state),
|
|
.class_init = icp_pic_class_init,
|
|
};
|
|
|
|
static void integratorcp_register_types(void)
|
|
{
|
|
type_register_static(&icp_pic_info);
|
|
type_register_static(&core_info);
|
|
}
|
|
|
|
type_init(integratorcp_register_types)
|