arm11mpcore: Split off SCU device

Inspired by a9scu.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Andreas Färber <afaerber@suse.de>
This commit is contained in:
Andreas Färber 2013-08-18 20:07:36 +02:00
parent 2c42c3a063
commit 53cb9a1c2f
5 changed files with 145 additions and 51 deletions

View File

@ -61,6 +61,7 @@ CONFIG_BITBANG_I2C=y
CONFIG_FRAMEBUFFER=y CONFIG_FRAMEBUFFER=y
CONFIG_XILINX_SPIPS=y CONFIG_XILINX_SPIPS=y
CONFIG_ARM11SCU=y
CONFIG_A9SCU=y CONFIG_A9SCU=y
CONFIG_MARVELL_88W8618=y CONFIG_MARVELL_88W8618=y
CONFIG_OMAP=y CONFIG_OMAP=y

View File

@ -8,6 +8,7 @@
*/ */
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/misc/arm11scu.h"
#include "qemu/timer.h" #include "qemu/timer.h"
/* MPCore private memory region. */ /* MPCore private memory region. */
@ -19,64 +20,18 @@
typedef struct ARM11MPCorePriveState { typedef struct ARM11MPCorePriveState {
SysBusDevice parent_obj; SysBusDevice parent_obj;
uint32_t scu_control;
uint32_t num_cpu; uint32_t num_cpu;
MemoryRegion iomem;
MemoryRegion container; MemoryRegion container;
DeviceState *mptimer; DeviceState *mptimer;
DeviceState *wdtimer; DeviceState *wdtimer;
DeviceState *gic; DeviceState *gic;
uint32_t num_irq; uint32_t num_irq;
ARM11SCUState scu;
} ARM11MPCorePriveState; } ARM11MPCorePriveState;
/* Per-CPU private memory mapped IO. */ /* Per-CPU private memory mapped IO. */
static uint64_t mpcore_scu_read(void *opaque, hwaddr offset,
unsigned size)
{
ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque;
int id;
/* SCU */
switch (offset) {
case 0x00: /* Control. */
return s->scu_control;
case 0x04: /* Configuration. */
id = ((1 << s->num_cpu) - 1) << 4;
return id | (s->num_cpu - 1);
case 0x08: /* CPU status. */
return 0;
case 0x0c: /* Invalidate all. */
return 0;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"mpcore_priv_read: Bad offset %x\n", (int)offset);
return 0;
}
}
static void mpcore_scu_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque;
/* SCU */
switch (offset) {
case 0: /* Control register. */
s->scu_control = value & 1;
break;
case 0x0c: /* Invalidate all. */
/* This is a no-op as cache is not emulated. */
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"mpcore_priv_read: Bad offset %x\n", (int)offset);
}
}
static const MemoryRegionOps mpcore_scu_ops = {
.read = mpcore_scu_read,
.write = mpcore_scu_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void mpcore_priv_set_irq(void *opaque, int irq, int level) static void mpcore_priv_set_irq(void *opaque, int irq, int level)
{ {
@ -87,12 +42,13 @@ static void mpcore_priv_set_irq(void *opaque, int irq, int level)
static void mpcore_priv_map_setup(ARM11MPCorePriveState *s) static void mpcore_priv_map_setup(ARM11MPCorePriveState *s)
{ {
int i; int i;
SysBusDevice *scubusdev = SYS_BUS_DEVICE(&s->scu);
SysBusDevice *gicbusdev = SYS_BUS_DEVICE(s->gic); SysBusDevice *gicbusdev = SYS_BUS_DEVICE(s->gic);
SysBusDevice *timerbusdev = SYS_BUS_DEVICE(s->mptimer); SysBusDevice *timerbusdev = SYS_BUS_DEVICE(s->mptimer);
SysBusDevice *wdtbusdev = SYS_BUS_DEVICE(s->wdtimer); SysBusDevice *wdtbusdev = SYS_BUS_DEVICE(s->wdtimer);
memory_region_init_io(&s->iomem, OBJECT(s),
&mpcore_scu_ops, s, "mpcore-scu", 0x100); memory_region_add_subregion(&s->container, 0,
memory_region_add_subregion(&s->container, 0, &s->iomem); sysbus_mmio_get_region(scubusdev, 0));
/* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
* at 0x200, 0x300... * at 0x200, 0x300...
*/ */
@ -130,6 +86,10 @@ static int mpcore_priv_init(SysBusDevice *sbd)
{ {
DeviceState *dev = DEVICE(sbd); DeviceState *dev = DEVICE(sbd);
ARM11MPCorePriveState *s = ARM11MPCORE_PRIV(dev); ARM11MPCorePriveState *s = ARM11MPCORE_PRIV(dev);
DeviceState *scudev = DEVICE(&s->scu);
qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu);
qdev_init_nofail(scudev);
s->gic = qdev_create(NULL, "arm_gic"); s->gic = qdev_create(NULL, "arm_gic");
qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
@ -164,6 +124,9 @@ static void mpcore_priv_initfn(Object *obj)
memory_region_init(&s->container, OBJECT(s), memory_region_init(&s->container, OBJECT(s),
"mpcore-priv-container", 0x2000); "mpcore-priv-container", 0x2000);
sysbus_init_mmio(sbd, &s->container); sysbus_init_mmio(sbd, &s->container);
object_initialize(&s->scu, sizeof(s->scu), TYPE_ARM11_SCU);
qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default());
} }
#define TYPE_REALVIEW_MPCORE_RIRQ "realview_mpcore" #define TYPE_REALVIEW_MPCORE_RIRQ "realview_mpcore"

View File

@ -12,6 +12,7 @@ obj-$(CONFIG_VMPORT) += vmport.o
common-obj-$(CONFIG_PL310) += arm_l2x0.o common-obj-$(CONFIG_PL310) += arm_l2x0.o
common-obj-$(CONFIG_INTEGRATOR_DEBUG) += arm_integrator_debug.o common-obj-$(CONFIG_INTEGRATOR_DEBUG) += arm_integrator_debug.o
common-obj-$(CONFIG_A9SCU) += a9scu.o common-obj-$(CONFIG_A9SCU) += a9scu.o
common-obj-$(CONFIG_ARM11SCU) += arm11scu.o
# PKUnity SoC devices # PKUnity SoC devices
common-obj-$(CONFIG_PUV3) += puv3_pm.o common-obj-$(CONFIG_PUV3) += puv3_pm.o

100
hw/misc/arm11scu.c Normal file
View File

@ -0,0 +1,100 @@
/*
* ARM11MPCore Snoop Control Unit (SCU) emulation
*
* Copyright (c) 2006-2007 CodeSourcery.
* Copyright (c) 2013 SUSE LINUX Products GmbH
* Written by Paul Brook and Andreas Färber
*
* This code is licensed under the GPL.
*/
#include "hw/misc/arm11scu.h"
static uint64_t mpcore_scu_read(void *opaque, hwaddr offset,
unsigned size)
{
ARM11SCUState *s = (ARM11SCUState *)opaque;
int id;
/* SCU */
switch (offset) {
case 0x00: /* Control. */
return s->control;
case 0x04: /* Configuration. */
id = ((1 << s->num_cpu) - 1) << 4;
return id | (s->num_cpu - 1);
case 0x08: /* CPU status. */
return 0;
case 0x0c: /* Invalidate all. */
return 0;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"mpcore_priv_read: Bad offset %x\n", (int)offset);
return 0;
}
}
static void mpcore_scu_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
ARM11SCUState *s = (ARM11SCUState *)opaque;
/* SCU */
switch (offset) {
case 0: /* Control register. */
s->control = value & 1;
break;
case 0x0c: /* Invalidate all. */
/* This is a no-op as cache is not emulated. */
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"mpcore_priv_read: Bad offset %x\n", (int)offset);
}
}
static const MemoryRegionOps mpcore_scu_ops = {
.read = mpcore_scu_read,
.write = mpcore_scu_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void arm11_scu_realize(DeviceState *dev, Error **errp)
{
}
static void arm11_scu_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
ARM11SCUState *s = ARM11_SCU(obj);
memory_region_init_io(&s->iomem, OBJECT(s),
&mpcore_scu_ops, s, "mpcore-scu", 0x100);
sysbus_init_mmio(sbd, &s->iomem);
}
static Property arm11_scu_properties[] = {
DEFINE_PROP_UINT32("num-cpu", ARM11SCUState, num_cpu, 1),
DEFINE_PROP_END_OF_LIST()
};
static void arm11_scu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = arm11_scu_realize;
dc->props = arm11_scu_properties;
}
static const TypeInfo arm11_scu_type_info = {
.name = TYPE_ARM11_SCU,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ARM11SCUState),
.instance_init = arm11_scu_init,
.class_init = arm11_scu_class_init,
};
static void arm11_scu_register_types(void)
{
type_register_static(&arm11_scu_type_info);
}
type_init(arm11_scu_register_types)

View File

@ -0,0 +1,29 @@
/*
* ARM11MPCore Snoop Control Unit (SCU) emulation
*
* Copyright (c) 2006-2007 CodeSourcery.
* Copyright (c) 2013 SUSE LINUX Products GmbH
* Written by Paul Brook and Andreas Färber
*
* This code is licensed under the GPL.
*/
#ifndef HW_MISC_ARM11SCU_H
#define HW_MISC_ARM11SCU_H
#include "hw/sysbus.h"
#define TYPE_ARM11_SCU "arm11-scu"
#define ARM11_SCU(obj) OBJECT_CHECK(ARM11SCUState, (obj), TYPE_ARM11_SCU)
typedef struct ARM11SCUState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
uint32_t control;
uint32_t num_cpu;
MemoryRegion iomem;
} ARM11SCUState;
#endif