aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-03-30 16:06:44 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-03-30 16:06:45 +0100
commit489ef4c810033e63af570c8a430af8b9858bfa5f (patch)
tree83d922b35a8b37ea1515040c2590c67b38aab102 /hw
parent69bc7f5029db5ea55359f7905e9829777ae5a34f (diff)
parentf6d4dd810983fdf3d1c9fb81838167efef63d1c8 (diff)
Merge remote-tracking branch 'remotes/lalrae/tags/mips-20160329-2' into staging
MIPS patches 2016-03-29 Changes: * add initial MIPS CPS support * implement ITU block * implement MAAR # gpg: Signature made Wed 30 Mar 2016 09:27:01 BST using RSA key ID 0B29DA6B # gpg: Good signature from "Leon Alrae <leon.alrae@imgtec.com>" * remotes/lalrae/tags/mips-20160329-2: (21 commits) target-mips: add MAAR, MAARI register target-mips: use CP0_CHECK for gen_m{f|t}hc0 hw/mips/cps: enable ITU for multithreading processors target-mips: make ITC Configuration Tags accessible to the CPU target-mips: check CP0 enabled for CACHE instruction also in R6 hw/mips: implement ITC Storage - Bypass View hw/mips: implement ITC Storage - P/V Sync and Try Views hw/mips: implement ITC Storage - Empty/Full Sync and Try Views hw/mips: implement ITC Storage - Control View hw/mips: implement ITC Configuration Tags and Storage Cells target-mips: enable CM GCR in MIPS64R6-generic CPU hw/mips_malta: add CPS to Malta board hw/mips_malta: move CPU creation to a separate function hw/mips_malta: remove redundant irq and clock init hw/mips_malta: remove CPUMIPSState from the write_bootloader() hw/mips/cps: create CPC block inside CPS hw/mips: add initial Cluster Power Controller support hw/mips/cps: create GCR block inside CPS hw/mips: add initial Global Config Register support target-mips: add CMGCRBase register ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/mips/Makefile.objs1
-rw-r--r--hw/mips/cps.c180
-rw-r--r--hw/mips/mips_malta.c118
-rw-r--r--hw/misc/Makefile.objs3
-rw-r--r--hw/misc/mips_cmgcr.c160
-rw-r--r--hw/misc/mips_cpc.c177
-rw-r--r--hw/misc/mips_itu.c526
7 files changed, 1128 insertions, 37 deletions
diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
index 9633f3a57d..9352a1c062 100644
--- a/hw/mips/Makefile.objs
+++ b/hw/mips/Makefile.objs
@@ -3,3 +3,4 @@ obj-y += addr.o cputimer.o mips_int.o
obj-$(CONFIG_JAZZ) += mips_jazz.o
obj-$(CONFIG_FULONG) += mips_fulong2e.o
obj-y += gt64xxx_pci.o
+obj-$(CONFIG_MIPS_CPS) += cps.o
diff --git a/hw/mips/cps.c b/hw/mips/cps.c
new file mode 100644
index 0000000000..1bafbbb278
--- /dev/null
+++ b/hw/mips/cps.c
@@ -0,0 +1,180 @@
+/*
+ * Coherent Processing System emulation.
+ *
+ * Copyright (c) 2016 Imagination Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/mips/cps.h"
+#include "hw/mips/mips.h"
+#include "hw/mips/cpudevs.h"
+#include "sysemu/kvm.h"
+
+qemu_irq get_cps_irq(MIPSCPSState *s, int pin_number)
+{
+ MIPSCPU *cpu = MIPS_CPU(first_cpu);
+ CPUMIPSState *env = &cpu->env;
+
+ assert(pin_number < s->num_irq);
+
+ /* TODO: return GIC pins once implemented */
+ return env->irq[pin_number];
+}
+
+static void mips_cps_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ MIPSCPSState *s = MIPS_CPS(obj);
+
+ /* Cover entire address space as there do not seem to be any
+ * constraints for the base address of CPC and GIC. */
+ memory_region_init(&s->container, obj, "mips-cps-container", UINT64_MAX);
+ sysbus_init_mmio(sbd, &s->container);
+}
+
+static void main_cpu_reset(void *opaque)
+{
+ MIPSCPU *cpu = opaque;
+ CPUState *cs = CPU(cpu);
+
+ cpu_reset(cs);
+
+ /* All VPs are halted on reset. Leave powering up to CPC. */
+ cs->halted = 1;
+}
+
+static bool cpu_mips_itu_supported(CPUMIPSState *env)
+{
+ bool is_mt = (env->CP0_Config5 & (1 << CP0C5_VP)) ||
+ (env->CP0_Config3 & (1 << CP0C3_MT));
+
+ return is_mt && !kvm_enabled();
+}
+
+static void mips_cps_realize(DeviceState *dev, Error **errp)
+{
+ MIPSCPSState *s = MIPS_CPS(dev);
+ CPUMIPSState *env;
+ MIPSCPU *cpu;
+ int i;
+ Error *err = NULL;
+ target_ulong gcr_base;
+ bool itu_present = false;
+
+ for (i = 0; i < s->num_vp; i++) {
+ cpu = cpu_mips_init(s->cpu_model);
+ if (cpu == NULL) {
+ error_setg(errp, "%s: CPU initialization failed\n", __func__);
+ return;
+ }
+ env = &cpu->env;
+
+ /* Init internal devices */
+ cpu_mips_irq_init_cpu(env);
+ cpu_mips_clock_init(env);
+ if (cpu_mips_itu_supported(env)) {
+ itu_present = true;
+ /* Attach ITC Tag to the VP */
+ env->itc_tag = mips_itu_get_tag_region(&s->itu);
+ }
+ qemu_register_reset(main_cpu_reset, cpu);
+ }
+
+ cpu = MIPS_CPU(first_cpu);
+ env = &cpu->env;
+
+ /* Inter-Thread Communication Unit */
+ if (itu_present) {
+ object_initialize(&s->itu, sizeof(s->itu), TYPE_MIPS_ITU);
+ qdev_set_parent_bus(DEVICE(&s->itu), sysbus_get_default());
+
+ object_property_set_int(OBJECT(&s->itu), 16, "num-fifo", &err);
+ object_property_set_int(OBJECT(&s->itu), 16, "num-semaphores", &err);
+ object_property_set_bool(OBJECT(&s->itu), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ memory_region_add_subregion(&s->container, 0,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->itu), 0));
+ }
+
+ /* Cluster Power Controller */
+ object_initialize(&s->cpc, sizeof(s->cpc), TYPE_MIPS_CPC);
+ qdev_set_parent_bus(DEVICE(&s->cpc), sysbus_get_default());
+
+ object_property_set_int(OBJECT(&s->cpc), s->num_vp, "num-vp", &err);
+ object_property_set_int(OBJECT(&s->cpc), 1, "vp-start-running", &err);
+ object_property_set_bool(OBJECT(&s->cpc), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ memory_region_add_subregion(&s->container, 0,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpc), 0));
+
+ /* Global Configuration Registers */
+ gcr_base = env->CP0_CMGCRBase << 4;
+
+ object_initialize(&s->gcr, sizeof(s->gcr), TYPE_MIPS_GCR);
+ qdev_set_parent_bus(DEVICE(&s->gcr), sysbus_get_default());
+
+ object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp", &err);
+ object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev", &err);
+ object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base", &err);
+ object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc", &err);
+ object_property_set_bool(OBJECT(&s->gcr), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ memory_region_add_subregion(&s->container, gcr_base,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gcr), 0));
+}
+
+static Property mips_cps_properties[] = {
+ DEFINE_PROP_UINT32("num-vp", MIPSCPSState, num_vp, 1),
+ DEFINE_PROP_UINT32("num-irq", MIPSCPSState, num_irq, 8),
+ DEFINE_PROP_STRING("cpu-model", MIPSCPSState, cpu_model),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void mips_cps_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = mips_cps_realize;
+ dc->props = mips_cps_properties;
+}
+
+static const TypeInfo mips_cps_info = {
+ .name = TYPE_MIPS_CPS,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MIPSCPSState),
+ .instance_init = mips_cps_init,
+ .class_init = mips_cps_class_init,
+};
+
+static void mips_cps_register_types(void)
+{
+ type_register_static(&mips_cps_info);
+}
+
+type_init(mips_cps_register_types)
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index 4ff1bb2562..fa769e5c00 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -57,6 +57,7 @@
#include "hw/empty_slot.h"
#include "sysemu/kvm.h"
#include "exec/semihost.h"
+#include "hw/mips/cps.h"
//#define DEBUG_BOARD_INIT
@@ -95,6 +96,7 @@ typedef struct {
typedef struct {
SysBusDevice parent_obj;
+ MIPSCPSState *cps;
qemu_irq *i8259;
} MaltaState;
@@ -608,8 +610,8 @@ static void network_init(PCIBus *pci_bus)
a3 - RAM size in bytes
*/
-static void write_bootloader (CPUMIPSState *env, uint8_t *base,
- int64_t run_addr, int64_t kernel_entry)
+static void write_bootloader(uint8_t *base, int64_t run_addr,
+ int64_t kernel_entry)
{
uint32_t *p;
@@ -908,12 +910,81 @@ static void main_cpu_reset(void *opaque)
}
}
+static void create_cpu_without_cps(const char *cpu_model,
+ qemu_irq *cbus_irq, qemu_irq *i8259_irq)
+{
+ CPUMIPSState *env;
+ MIPSCPU *cpu;
+ int i;
+
+ for (i = 0; i < smp_cpus; i++) {
+ cpu = cpu_mips_init(cpu_model);
+ if (cpu == NULL) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+ env = &cpu->env;
+
+ /* Init internal devices */
+ cpu_mips_irq_init_cpu(env);
+ cpu_mips_clock_init(env);
+ qemu_register_reset(main_cpu_reset, cpu);
+ }
+
+ cpu = MIPS_CPU(first_cpu);
+ env = &cpu->env;
+ *i8259_irq = env->irq[2];
+ *cbus_irq = env->irq[4];
+}
+
+static void create_cps(MaltaState *s, const char *cpu_model,
+ qemu_irq *cbus_irq, qemu_irq *i8259_irq)
+{
+ Error *err = NULL;
+ s->cps = g_new0(MIPSCPSState, 1);
+
+ object_initialize(s->cps, sizeof(MIPSCPSState), TYPE_MIPS_CPS);
+ qdev_set_parent_bus(DEVICE(s->cps), sysbus_get_default());
+
+ object_property_set_str(OBJECT(s->cps), cpu_model, "cpu-model", &err);
+ object_property_set_int(OBJECT(s->cps), smp_cpus, "num-vp", &err);
+ object_property_set_bool(OBJECT(s->cps), true, "realized", &err);
+ if (err != NULL) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+
+ sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->cps), 0, 0, 1);
+
+ /* FIXME: When GIC is present then we should use GIC's IRQ 3.
+ Until then CPS exposes CPU's IRQs thus use the default IRQ 2. */
+ *i8259_irq = get_cps_irq(s->cps, 2);
+ *cbus_irq = NULL;
+}
+
+static void create_cpu(MaltaState *s, const char *cpu_model,
+ qemu_irq *cbus_irq, qemu_irq *i8259_irq)
+{
+ if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+ cpu_model = "20Kc";
+#else
+ cpu_model = "24Kf";
+#endif
+ }
+
+ if ((smp_cpus > 1) && cpu_supports_cps_smp(cpu_model)) {
+ create_cps(s, cpu_model, cbus_irq, i8259_irq);
+ } else {
+ create_cpu_without_cps(cpu_model, cbus_irq, i8259_irq);
+ }
+}
+
static
void mips_malta_init(MachineState *machine)
{
ram_addr_t ram_size = machine->ram_size;
ram_addr_t ram_low_size;
- const char *cpu_model = machine->cpu_model;
const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
const char *initrd_filename = machine->initrd_filename;
@@ -930,9 +1001,8 @@ void mips_malta_init(MachineState *machine)
int64_t kernel_entry, bootloader_run_addr;
PCIBus *pci_bus;
ISABus *isa_bus;
- MIPSCPU *cpu;
- CPUMIPSState *env;
qemu_irq *isa_irq;
+ qemu_irq cbus_irq, i8259_irq;
int piix4_devfn;
I2CBus *smbus;
int i;
@@ -962,30 +1032,8 @@ void mips_malta_init(MachineState *machine)
}
}
- /* init CPUs */
- if (cpu_model == NULL) {
-#ifdef TARGET_MIPS64
- cpu_model = "20Kc";
-#else
- cpu_model = "24Kf";
-#endif
- }
-
- for (i = 0; i < smp_cpus; i++) {
- cpu = cpu_mips_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- /* Init internal devices */
- cpu_mips_irq_init_cpu(env);
- cpu_mips_clock_init(env);
- qemu_register_reset(main_cpu_reset, cpu);
- }
- cpu = MIPS_CPU(first_cpu);
- env = &cpu->env;
+ /* create CPU */
+ create_cpu(s, machine->cpu_model, &cbus_irq, &i8259_irq);
/* allocate RAM */
if (ram_size > (2048u << 20)) {
@@ -1026,7 +1074,7 @@ void mips_malta_init(MachineState *machine)
#endif
/* FPGA */
/* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
- malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[4], serial_hds[2]);
+ malta_fpga_init(system_memory, FPGA_ADDRESS, cbus_irq, serial_hds[2]);
/* Load firmware in flash / BIOS. */
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
@@ -1063,11 +1111,11 @@ void mips_malta_init(MachineState *machine)
loaderparams.initrd_filename = initrd_filename;
kernel_entry = load_kernel();
- write_bootloader(env, memory_region_get_ram_ptr(bios),
+ write_bootloader(memory_region_get_ram_ptr(bios),
bootloader_run_addr, kernel_entry);
if (kvm_enabled()) {
/* Write the bootloader code @ the end of RAM, 1MB reserved */
- write_bootloader(env, memory_region_get_ram_ptr(ram_low_preio) +
+ write_bootloader(memory_region_get_ram_ptr(ram_low_preio) +
ram_low_size,
bootloader_run_addr, kernel_entry);
}
@@ -1135,10 +1183,6 @@ void mips_malta_init(MachineState *machine)
/* Board ID = 0x420 (Malta Board with CoreLV) */
stl_p(memory_region_get_ram_ptr(bios_copy) + 0x10, 0x00000420);
- /* Init internal devices */
- cpu_mips_irq_init_cpu(env);
- cpu_mips_clock_init(env);
-
/*
* We have a circular dependency problem: pci_bus depends on isa_irq,
* isa_irq is provided by i8259, i8259 depends on ISA, ISA depends
@@ -1158,7 +1202,7 @@ void mips_malta_init(MachineState *machine)
/* Interrupt controller */
/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
- s->i8259 = i8259_init(isa_bus, env->irq[2]);
+ s->i8259 = i8259_init(isa_bus, i8259_irq);
isa_bus_irqs(isa_bus, s->i8259);
pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 44ac2e14a3..93f952880a 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -43,6 +43,9 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o
obj-$(CONFIG_ZYNQ) += zynq_slcr.o
obj-$(CONFIG_ZYNQ) += zynq-xadc.o
obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
+obj-$(CONFIG_MIPS_CPS) += mips_cmgcr.o
+obj-$(CONFIG_MIPS_CPS) += mips_cpc.o
+obj-$(CONFIG_MIPS_ITU) += mips_itu.o
obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_EDU) += edu.o
diff --git a/hw/misc/mips_cmgcr.c b/hw/misc/mips_cmgcr.c
new file mode 100644
index 0000000000..37be23995b
--- /dev/null
+++ b/hw/misc/mips_cmgcr.c
@@ -0,0 +1,160 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
+ * Authors: Sanjay Lal <sanjayl@kymasys.com>
+ *
+ * Copyright (C) 2015 Imagination Technologies
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "hw/misc/mips_cmgcr.h"
+#include "hw/misc/mips_cpc.h"
+
+static inline bool is_cpc_connected(MIPSGCRState *s)
+{
+ return s->cpc_mr != NULL;
+}
+
+static inline void update_cpc_base(MIPSGCRState *gcr, uint64_t val)
+{
+ if (is_cpc_connected(gcr)) {
+ gcr->cpc_base = val & GCR_CPC_BASE_MSK;
+ memory_region_transaction_begin();
+ memory_region_set_address(gcr->cpc_mr,
+ gcr->cpc_base & GCR_CPC_BASE_CPCBASE_MSK);
+ memory_region_set_enabled(gcr->cpc_mr,
+ gcr->cpc_base & GCR_CPC_BASE_CPCEN_MSK);
+ memory_region_transaction_commit();
+ }
+}
+
+/* Read GCR registers */
+static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size)
+{
+ MIPSGCRState *gcr = (MIPSGCRState *) opaque;
+
+ switch (addr) {
+ /* Global Control Block Register */
+ case GCR_CONFIG_OFS:
+ /* Set PCORES to 0 */
+ return 0;
+ case GCR_BASE_OFS:
+ return gcr->gcr_base;
+ case GCR_REV_OFS:
+ return gcr->gcr_rev;
+ case GCR_CPC_BASE_OFS:
+ return gcr->cpc_base;
+ case GCR_CPC_STATUS_OFS:
+ return is_cpc_connected(gcr);
+ case GCR_L2_CONFIG_OFS:
+ /* L2 BYPASS */
+ return GCR_L2_CONFIG_BYPASS_MSK;
+ /* Core-Local and Core-Other Control Blocks */
+ case MIPS_CLCB_OFS + GCR_CL_CONFIG_OFS:
+ case MIPS_COCB_OFS + GCR_CL_CONFIG_OFS:
+ /* Set PVP to # of VPs - 1 */
+ return gcr->num_vps - 1;
+ case MIPS_CLCB_OFS + GCR_CL_OTHER_OFS:
+ return 0;
+ default:
+ qemu_log_mask(LOG_UNIMP, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx
+ "\n", size, addr);
+ return 0;
+ }
+ return 0;
+}
+
+/* Write GCR registers */
+static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
+{
+ MIPSGCRState *gcr = (MIPSGCRState *)opaque;
+
+ switch (addr) {
+ case GCR_CPC_BASE_OFS:
+ update_cpc_base(gcr, data);
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx
+ " 0x%" PRIx64 "\n", size, addr, data);
+ break;
+ }
+}
+
+static const MemoryRegionOps gcr_ops = {
+ .read = gcr_read,
+ .write = gcr_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .max_access_size = 8,
+ },
+};
+
+static void mips_gcr_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ MIPSGCRState *s = MIPS_GCR(obj);
+
+ object_property_add_link(obj, "cpc", TYPE_MEMORY_REGION,
+ (Object **)&s->cpc_mr,
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_UNREF_ON_RELEASE,
+ &error_abort);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &gcr_ops, s,
+ "mips-gcr", GCR_ADDRSPACE_SZ);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void mips_gcr_reset(DeviceState *dev)
+{
+ MIPSGCRState *s = MIPS_GCR(dev);
+
+ update_cpc_base(s, 0);
+}
+
+static const VMStateDescription vmstate_mips_gcr = {
+ .name = "mips-gcr",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(cpc_base, MIPSGCRState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static Property mips_gcr_properties[] = {
+ DEFINE_PROP_INT32("num-vp", MIPSGCRState, num_vps, 1),
+ DEFINE_PROP_INT32("gcr-rev", MIPSGCRState, gcr_rev, 0x800),
+ DEFINE_PROP_UINT64("gcr-base", MIPSGCRState, gcr_base, GCR_BASE_ADDR),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mips_gcr_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->props = mips_gcr_properties;
+ dc->vmsd = &vmstate_mips_gcr;
+ dc->reset = mips_gcr_reset;
+}
+
+static const TypeInfo mips_gcr_info = {
+ .name = TYPE_MIPS_GCR,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MIPSGCRState),
+ .instance_init = mips_gcr_init,
+ .class_init = mips_gcr_class_init,
+};
+
+static void mips_gcr_register_types(void)
+{
+ type_register_static(&mips_gcr_info);
+}
+
+type_init(mips_gcr_register_types)
diff --git a/hw/misc/mips_cpc.c b/hw/misc/mips_cpc.c
new file mode 100644
index 0000000000..d2b8e42da7
--- /dev/null
+++ b/hw/misc/mips_cpc.c
@@ -0,0 +1,177 @@
+/*
+ * Cluster Power Controller emulation
+ *
+ * Copyright (c) 2016 Imagination Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/sysbus.h"
+
+#include "hw/misc/mips_cpc.h"
+
+static inline uint64_t cpc_vp_run_mask(MIPSCPCState *cpc)
+{
+ return (1ULL << cpc->num_vp) - 1;
+}
+
+static void cpc_run_vp(MIPSCPCState *cpc, uint64_t vp_run)
+{
+ CPUState *cs = first_cpu;
+
+ CPU_FOREACH(cs) {
+ uint64_t i = 1ULL << cs->cpu_index;
+ if (i & vp_run & ~cpc->vp_running) {
+ cpu_interrupt(cs, CPU_INTERRUPT_WAKE);
+ cpc->vp_running |= i;
+ }
+ }
+}
+
+static void cpc_stop_vp(MIPSCPCState *cpc, uint64_t vp_stop)
+{
+ CPUState *cs = first_cpu;
+
+ CPU_FOREACH(cs) {
+ uint64_t i = 1ULL << cs->cpu_index;
+ if (i & vp_stop & cpc->vp_running) {
+ cs->halted = 1;
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
+ cpc->vp_running &= ~i;
+ }
+ }
+}
+
+static void cpc_write(void *opaque, hwaddr offset, uint64_t data,
+ unsigned size)
+{
+ MIPSCPCState *s = opaque;
+
+ switch (offset) {
+ case CPC_CL_BASE_OFS + CPC_VP_RUN_OFS:
+ case CPC_CO_BASE_OFS + CPC_VP_RUN_OFS:
+ cpc_run_vp(s, data & cpc_vp_run_mask(s));
+ break;
+ case CPC_CL_BASE_OFS + CPC_VP_STOP_OFS:
+ case CPC_CO_BASE_OFS + CPC_VP_STOP_OFS:
+ cpc_stop_vp(s, data & cpc_vp_run_mask(s));
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ break;
+ }
+
+ return;
+}
+
+static uint64_t cpc_read(void *opaque, hwaddr offset, unsigned size)
+{
+ MIPSCPCState *s = opaque;
+
+ switch (offset) {
+ case CPC_CL_BASE_OFS + CPC_VP_RUNNING_OFS:
+ case CPC_CO_BASE_OFS + CPC_VP_RUNNING_OFS:
+ return s->vp_running;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ return 0;
+ }
+}
+
+static const MemoryRegionOps cpc_ops = {
+ .read = cpc_read,
+ .write = cpc_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .max_access_size = 8,
+ },
+};
+
+static void mips_cpc_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ MIPSCPCState *s = MIPS_CPC(obj);
+
+ memory_region_init_io(&s->mr, OBJECT(s), &cpc_ops, s, "mips-cpc",
+ CPC_ADDRSPACE_SZ);
+ sysbus_init_mmio(sbd, &s->mr);
+}
+
+static void mips_cpc_realize(DeviceState *dev, Error **errp)
+{
+ MIPSCPCState *s = MIPS_CPC(dev);
+
+ if (s->vp_start_running > cpc_vp_run_mask(s)) {
+ error_setg(errp,
+ "incorrect vp_start_running 0x%" PRIx64 " for num_vp = %d",
+ s->vp_running, s->num_vp);
+ return;
+ }
+}
+
+static void mips_cpc_reset(DeviceState *dev)
+{
+ MIPSCPCState *s = MIPS_CPC(dev);
+
+ /* Reflect the fact that all VPs are halted on reset */
+ s->vp_running = 0;
+
+ /* Put selected VPs into run state */
+ cpc_run_vp(s, s->vp_start_running);
+}
+
+static const VMStateDescription vmstate_mips_cpc = {
+ .name = "mips-cpc",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(vp_running, MIPSCPCState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static Property mips_cpc_properties[] = {
+ DEFINE_PROP_UINT32("num-vp", MIPSCPCState, num_vp, 0x1),
+ DEFINE_PROP_UINT64("vp-start-running", MIPSCPCState, vp_start_running, 0x1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mips_cpc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = mips_cpc_realize;
+ dc->reset = mips_cpc_reset;
+ dc->vmsd = &vmstate_mips_cpc;
+ dc->props = mips_cpc_properties;
+}
+
+static const TypeInfo mips_cpc_info = {
+ .name = TYPE_MIPS_CPC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MIPSCPCState),
+ .instance_init = mips_cpc_init,
+ .class_init = mips_cpc_class_init,
+};
+
+static void mips_cpc_register_types(void)
+{
+ type_register_static(&mips_cpc_info);
+}
+
+type_init(mips_cpc_register_types)
diff --git a/hw/misc/mips_itu.c b/hw/misc/mips_itu.c
new file mode 100644
index 0000000000..8461d2379b
--- /dev/null
+++ b/hw/misc/mips_itu.c
@@ -0,0 +1,526 @@
+/*
+ * Inter-Thread Communication Unit emulation.
+ *
+ * Copyright (c) 2016 Imagination Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "hw/misc/mips_itu.h"
+
+#define ITC_TAG_ADDRSPACE_SZ (ITC_ADDRESSMAP_NUM * 8)
+/* Initialize as 4kB area to fit all 32 cells with default 128B grain.
+ Storage may be resized by the software. */
+#define ITC_STORAGE_ADDRSPACE_SZ 0x1000
+
+#define ITC_FIFO_NUM_MAX 16
+#define ITC_SEMAPH_NUM_MAX 16
+#define ITC_AM1_NUMENTRIES_OFS 20
+
+#define ITC_CELL_PV_MAX_VAL 0xFFFF
+
+#define ITC_CELL_TAG_FIFO_DEPTH 28
+#define ITC_CELL_TAG_FIFO_PTR 18
+#define ITC_CELL_TAG_FIFO 17
+#define ITC_CELL_TAG_T 16
+#define ITC_CELL_TAG_F 1
+#define ITC_CELL_TAG_E 0
+
+#define ITC_AM0_BASE_ADDRESS_MASK 0xFFFFFC00ULL
+#define ITC_AM0_EN_MASK 0x1
+
+#define ITC_AM1_ADDR_MASK_MASK 0x1FC00
+#define ITC_AM1_ENTRY_GRAIN_MASK 0x7
+
+typedef enum ITCView {
+ ITCVIEW_BYPASS = 0,
+ ITCVIEW_CONTROL = 1,
+ ITCVIEW_EF_SYNC = 2,
+ ITCVIEW_EF_TRY = 3,
+ ITCVIEW_PV_SYNC = 4,
+ ITCVIEW_PV_TRY = 5
+} ITCView;
+
+MemoryRegion *mips_itu_get_tag_region(MIPSITUState *itu)
+{
+ return &itu->tag_io;
+}
+
+static uint64_t itc_tag_read(void *opaque, hwaddr addr, unsigned size)
+{
+ MIPSITUState *tag = (MIPSITUState *)opaque;
+ uint64_t index = addr >> 3;
+ uint64_t ret = 0;
+
+ switch (index) {
+ case 0 ... ITC_ADDRESSMAP_NUM:
+ ret = tag->ITCAddressMap[index];
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "Read 0x%" PRIx64 "\n", addr);
+ break;
+ }
+
+ return ret;
+}
+
+static void itc_reconfigure(MIPSITUState *tag)
+{
+ uint64_t *am = &tag->ITCAddressMap[0];
+ MemoryRegion *mr = &tag->storage_io;
+ hwaddr address = am[0] & ITC_AM0_BASE_ADDRESS_MASK;
+ uint64_t size = (1 << 10) + (am[1] & ITC_AM1_ADDR_MASK_MASK);
+ bool is_enabled = (am[0] & ITC_AM0_EN_MASK) != 0;
+
+ memory_region_transaction_begin();
+ if (!(size & (size - 1))) {
+ memory_region_set_size(mr, size);
+ }
+ memory_region_set_address(mr, address);
+ memory_region_set_enabled(mr, is_enabled);
+ memory_region_transaction_commit();
+}
+
+static void itc_tag_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ MIPSITUState *tag = (MIPSITUState *)opaque;
+ uint64_t *am = &tag->ITCAddressMap[0];
+ uint64_t am_old, mask;
+ uint64_t index = addr >> 3;
+
+ switch (index) {
+ case 0:
+ mask = ITC_AM0_BASE_ADDRESS_MASK | ITC_AM0_EN_MASK;
+ break;
+ case 1:
+ mask = ITC_AM1_ADDR_MASK_MASK | ITC_AM1_ENTRY_GRAIN_MASK;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "Bad write 0x%" PRIx64 "\n", addr);
+ return;
+ }
+
+ am_old = am[index];
+ am[index] = (data & mask) | (am_old & ~mask);
+ if (am_old != am[index]) {
+ itc_reconfigure(tag);
+ }
+}
+
+static const MemoryRegionOps itc_tag_ops = {
+ .read = itc_tag_read,
+ .write = itc_tag_write,
+ .impl = {
+ .max_access_size = 8,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static inline uint32_t get_num_cells(MIPSITUState *s)
+{
+ return s->num_fifo + s->num_semaphores;
+}
+
+static inline ITCView get_itc_view(hwaddr addr)
+{
+ return (addr >> 3) & 0xf;
+}
+
+static inline int get_cell_stride_shift(const MIPSITUState *s)
+{
+ /* Minimum interval (for EntryGain = 0) is 128 B */
+ return 7 + (s->ITCAddressMap[1] & ITC_AM1_ENTRY_GRAIN_MASK);
+}
+
+static inline ITCStorageCell *get_cell(MIPSITUState *s,
+ hwaddr addr)
+{
+ uint32_t cell_idx = addr >> get_cell_stride_shift(s);
+ uint32_t num_cells = get_num_cells(s);
+
+ if (cell_idx >= num_cells) {
+ cell_idx = num_cells - 1;
+ }
+
+ return &s->cell[cell_idx];
+}
+
+static void wake_blocked_threads(ITCStorageCell *c)
+{
+ CPUState *cs;
+ CPU_FOREACH(cs) {
+ if (cs->halted && (c->blocked_threads & (1ULL << cs->cpu_index))) {
+ cpu_interrupt(cs, CPU_INTERRUPT_WAKE);
+ }
+ }
+ c->blocked_threads = 0;
+}
+
+static void QEMU_NORETURN block_thread_and_exit(ITCStorageCell *c)
+{
+ c->blocked_threads |= 1ULL << current_cpu->cpu_index;
+ cpu_restore_state(current_cpu, current_cpu->mem_io_pc);
+ current_cpu->halted = 1;
+ current_cpu->exception_index = EXCP_HLT;
+ cpu_loop_exit(current_cpu);
+}
+
+/* ITC Bypass View */
+
+static inline uint64_t view_bypass_read(ITCStorageCell *c)
+{
+ if (c->tag.FIFO) {
+ return c->data[c->fifo_out];
+ } else {
+ return c->data[0];
+ }
+}
+
+static inline void view_bypass_write(ITCStorageCell *c, uint64_t val)
+{
+ if (c->tag.FIFO && (c->tag.FIFOPtr > 0)) {
+ int idx = (c->fifo_out + c->tag.FIFOPtr - 1) % ITC_CELL_DEPTH;
+ c->data[idx] = val;
+ }
+
+ /* ignore a write to the semaphore cell */
+}
+
+/* ITC Control View */
+
+static inline uint64_t view_control_read(ITCStorageCell *c)
+{
+ return ((uint64_t)c->tag.FIFODepth << ITC_CELL_TAG_FIFO_DEPTH) |
+ (c->tag.FIFOPtr << ITC_CELL_TAG_FIFO_PTR) |
+ (c->tag.FIFO << ITC_CELL_TAG_FIFO) |
+ (c->tag.T << ITC_CELL_TAG_T) |
+ (c->tag.E << ITC_CELL_TAG_E) |
+ (c->tag.F << ITC_CELL_TAG_F);
+}
+
+static inline void view_control_write(ITCStorageCell *c, uint64_t val)
+{
+ c->tag.T = (val >> ITC_CELL_TAG_T) & 1;
+ c->tag.E = (val >> ITC_CELL_TAG_E) & 1;
+ c->tag.F = (val >> ITC_CELL_TAG_F) & 1;
+
+ if (c->tag.E) {
+ c->tag.FIFOPtr = 0;
+ }
+}
+
+/* ITC Empty/Full View */
+
+static uint64_t view_ef_common_read(ITCStorageCell *c, bool blocking)
+{
+ uint64_t ret = 0;
+
+ if (!c->tag.FIFO) {
+ return 0;
+ }
+
+ c->tag.F = 0;
+
+ if (blocking && c->tag.E) {
+ block_thread_and_exit(c);
+ }
+
+ if (c->blocked_threads) {
+ wake_blocked_threads(c);
+ }
+
+ if (c->tag.FIFOPtr > 0) {
+ ret = c->data[c->fifo_out];
+ c->fifo_out = (c->fifo_out + 1) % ITC_CELL_DEPTH;
+ c->tag.FIFOPtr--;
+ }
+
+ if (c->tag.FIFOPtr == 0) {
+ c->tag.E = 1;
+ }
+
+ return ret;
+}
+
+static uint64_t view_ef_sync_read(ITCStorageCell *c)
+{
+ return view_ef_common_read(c, true);
+}
+
+static uint64_t view_ef_try_read(ITCStorageCell *c)
+{
+ return view_ef_common_read(c, false);
+}
+
+static inline void view_ef_common_write(ITCStorageCell *c, uint64_t val,
+ bool blocking)
+{
+ if (!c->tag.FIFO) {
+ return;
+ }
+
+ c->tag.E = 0;
+
+ if (blocking && c->tag.F) {
+ block_thread_and_exit(c);
+ }
+
+ if (c->blocked_threads) {
+ wake_blocked_threads(c);
+ }
+
+ if (c->tag.FIFOPtr < ITC_CELL_DEPTH) {
+ int idx = (c->fifo_out + c->tag.FIFOPtr) % ITC_CELL_DEPTH;
+ c->data[idx] = val;
+ c->tag.FIFOPtr++;
+ }
+
+ if (c->tag.FIFOPtr == ITC_CELL_DEPTH) {
+ c->tag.F = 1;
+ }
+}
+
+static void view_ef_sync_write(ITCStorageCell *c, uint64_t val)
+{
+ view_ef_common_write(c, val, true);
+}
+
+static void view_ef_try_write(ITCStorageCell *c, uint64_t val)
+{
+ view_ef_common_write(c, val, false);
+}
+
+/* ITC P/V View */
+
+static uint64_t view_pv_common_read(ITCStorageCell *c, bool blocking)
+{
+ uint64_t ret = c->data[0];
+
+ if (c->tag.FIFO) {
+ return 0;
+ }
+
+ if (c->data[0] > 0) {
+ c->data[0]--;
+ } else if (blocking) {
+ block_thread_and_exit(c);
+ }
+
+ return ret;
+}
+
+static uint64_t view_pv_sync_read(ITCStorageCell *c)
+{
+ return view_pv_common_read(c, true);
+}
+
+static uint64_t view_pv_try_read(ITCStorageCell *c)
+{
+ return view_pv_common_read(c, false);
+}
+
+static inline void view_pv_common_write(ITCStorageCell *c)
+{
+ if (c->tag.FIFO) {
+ return;
+ }
+
+ if (c->data[0] < ITC_CELL_PV_MAX_VAL) {
+ c->data[0]++;
+ }
+
+ if (c->blocked_threads) {
+ wake_blocked_threads(c);
+ }
+}
+
+static void view_pv_sync_write(ITCStorageCell *c)
+{
+ view_pv_common_write(c);
+}
+
+static void view_pv_try_write(ITCStorageCell *c)
+{
+ view_pv_common_write(c);
+}
+
+static uint64_t itc_storage_read(void *opaque, hwaddr addr, unsigned size)
+{
+ MIPSITUState *s = (MIPSITUState *)opaque;
+ ITCStorageCell *cell = get_cell(s, addr);
+ ITCView view = get_itc_view(addr);
+ uint64_t ret = -1;
+
+ switch (view) {
+ case ITCVIEW_BYPASS:
+ ret = view_bypass_read(cell);
+ break;
+ case ITCVIEW_CONTROL:
+ ret = view_control_read(cell);
+ break;
+ case ITCVIEW_EF_SYNC:
+ ret = view_ef_sync_read(cell);
+ break;
+ case ITCVIEW_EF_TRY:
+ ret = view_ef_try_read(cell);
+ break;
+ case ITCVIEW_PV_SYNC:
+ ret = view_pv_sync_read(cell);
+ break;
+ case ITCVIEW_PV_TRY:
+ ret = view_pv_try_read(cell);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "itc_storage_read: Bad ITC View %d\n", (int)view);
+ break;
+ }
+
+ return ret;
+}
+
+static void itc_storage_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned size)
+{
+ MIPSITUState *s = (MIPSITUState *)opaque;
+ ITCStorageCell *cell = get_cell(s, addr);
+ ITCView view = get_itc_view(addr);
+
+ switch (view) {
+ case ITCVIEW_BYPASS:
+ view_bypass_write(cell, data);
+ break;
+ case ITCVIEW_CONTROL:
+ view_control_write(cell, data);
+ break;
+ case ITCVIEW_EF_SYNC:
+ view_ef_sync_write(cell, data);
+ break;
+ case ITCVIEW_EF_TRY:
+ view_ef_try_write(cell, data);
+ break;
+ case ITCVIEW_PV_SYNC:
+ view_pv_sync_write(cell);
+ break;
+ case ITCVIEW_PV_TRY:
+ view_pv_try_write(cell);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "itc_storage_write: Bad ITC View %d\n", (int)view);
+ break;
+ }
+
+}
+
+static const MemoryRegionOps itc_storage_ops = {
+ .read = itc_storage_read,
+ .write = itc_storage_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void itc_reset_cells(MIPSITUState *s)
+{
+ int i;
+
+ memset(s->cell, 0, get_num_cells(s) * sizeof(s->cell[0]));
+
+ for (i = 0; i < s->num_fifo; i++) {
+ s->cell[i].tag.E = 1;
+ s->cell[i].tag.FIFO = 1;
+ s->cell[i].tag.FIFODepth = ITC_CELL_DEPTH_SHIFT;
+ }
+}
+
+static void mips_itu_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ MIPSITUState *s = MIPS_ITU(obj);
+
+ memory_region_init_io(&s->storage_io, OBJECT(s), &itc_storage_ops, s,
+ "mips-itc-storage", ITC_STORAGE_ADDRSPACE_SZ);
+ sysbus_init_mmio(sbd, &s->storage_io);
+
+ memory_region_init_io(&s->tag_io, OBJECT(s), &itc_tag_ops, s,
+ "mips-itc-tag", ITC_TAG_ADDRSPACE_SZ);
+}
+
+static void mips_itu_realize(DeviceState *dev, Error **errp)
+{
+ MIPSITUState *s = MIPS_ITU(dev);
+
+ if (s->num_fifo > ITC_FIFO_NUM_MAX) {
+ error_setg(errp, "Exceed maximum number of FIFO cells: %d",
+ s->num_fifo);
+ return;
+ }
+ if (s->num_semaphores > ITC_SEMAPH_NUM_MAX) {
+ error_setg(errp, "Exceed maximum number of Semaphore cells: %d",
+ s->num_semaphores);
+ return;
+ }
+
+ s->cell = g_new(ITCStorageCell, get_num_cells(s));
+}
+
+static void mips_itu_reset(DeviceState *dev)
+{
+ MIPSITUState *s = MIPS_ITU(dev);
+
+ s->ITCAddressMap[0] = 0;
+ s->ITCAddressMap[1] =
+ ((ITC_STORAGE_ADDRSPACE_SZ - 1) & ITC_AM1_ADDR_MASK_MASK) |
+ (get_num_cells(s) << ITC_AM1_NUMENTRIES_OFS);
+ itc_reconfigure(s);
+
+ itc_reset_cells(s);
+}
+
+static Property mips_itu_properties[] = {
+ DEFINE_PROP_INT32("num-fifo", MIPSITUState, num_fifo,
+ ITC_FIFO_NUM_MAX),
+ DEFINE_PROP_INT32("num-semaphores", MIPSITUState, num_semaphores,
+ ITC_SEMAPH_NUM_MAX),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mips_itu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = mips_itu_properties;
+ dc->realize = mips_itu_realize;
+ dc->reset = mips_itu_reset;
+}
+
+static const TypeInfo mips_itu_info = {
+ .name = TYPE_MIPS_ITU,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MIPSITUState),
+ .instance_init = mips_itu_init,
+ .class_init = mips_itu_class_init,
+};
+
+static void mips_itu_register_types(void)
+{
+ type_register_static(&mips_itu_info);
+}
+
+type_init(mips_itu_register_types)