xref: /qemu/hw/mips/cps.c (revision 2edd5261fffcc8494936d353ffffe996d191da3b)
18e7e8a5bSLeon Alrae /*
28e7e8a5bSLeon Alrae  * Coherent Processing System emulation.
38e7e8a5bSLeon Alrae  *
48e7e8a5bSLeon Alrae  * Copyright (c) 2016 Imagination Technologies
58e7e8a5bSLeon Alrae  *
68e7e8a5bSLeon Alrae  * This library is free software; you can redistribute it and/or
78e7e8a5bSLeon Alrae  * modify it under the terms of the GNU Lesser General Public
88e7e8a5bSLeon Alrae  * License as published by the Free Software Foundation; either
98e7e8a5bSLeon Alrae  * version 2 of the License, or (at your option) any later version.
108e7e8a5bSLeon Alrae  *
118e7e8a5bSLeon Alrae  * This library is distributed in the hope that it will be useful,
128e7e8a5bSLeon Alrae  * but WITHOUT ANY WARRANTY; without even the implied warranty of
138e7e8a5bSLeon Alrae  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
148e7e8a5bSLeon Alrae  * Lesser General Public License for more details.
158e7e8a5bSLeon Alrae  *
168e7e8a5bSLeon Alrae  * You should have received a copy of the GNU Lesser General Public
178e7e8a5bSLeon Alrae  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
188e7e8a5bSLeon Alrae  */
198e7e8a5bSLeon Alrae 
208e7e8a5bSLeon Alrae #include "qemu/osdep.h"
218e7e8a5bSLeon Alrae #include "qapi/error.h"
228e7e8a5bSLeon Alrae #include "hw/mips/cps.h"
238e7e8a5bSLeon Alrae #include "hw/mips/mips.h"
248e7e8a5bSLeon Alrae #include "hw/mips/cpudevs.h"
258e7e8a5bSLeon Alrae 
268e7e8a5bSLeon Alrae qemu_irq get_cps_irq(MIPSCPSState *s, int pin_number)
278e7e8a5bSLeon Alrae {
288e7e8a5bSLeon Alrae     MIPSCPU *cpu = MIPS_CPU(first_cpu);
298e7e8a5bSLeon Alrae     CPUMIPSState *env = &cpu->env;
308e7e8a5bSLeon Alrae 
318e7e8a5bSLeon Alrae     assert(pin_number < s->num_irq);
328e7e8a5bSLeon Alrae 
338e7e8a5bSLeon Alrae     /* TODO: return GIC pins once implemented */
348e7e8a5bSLeon Alrae     return env->irq[pin_number];
358e7e8a5bSLeon Alrae }
368e7e8a5bSLeon Alrae 
378e7e8a5bSLeon Alrae static void mips_cps_init(Object *obj)
388e7e8a5bSLeon Alrae {
398e7e8a5bSLeon Alrae     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
408e7e8a5bSLeon Alrae     MIPSCPSState *s = MIPS_CPS(obj);
418e7e8a5bSLeon Alrae 
428e7e8a5bSLeon Alrae     /* Cover entire address space as there do not seem to be any
438e7e8a5bSLeon Alrae      * constraints for the base address of CPC and GIC. */
448e7e8a5bSLeon Alrae     memory_region_init(&s->container, obj, "mips-cps-container", UINT64_MAX);
458e7e8a5bSLeon Alrae     sysbus_init_mmio(sbd, &s->container);
468e7e8a5bSLeon Alrae }
478e7e8a5bSLeon Alrae 
488e7e8a5bSLeon Alrae static void main_cpu_reset(void *opaque)
498e7e8a5bSLeon Alrae {
508e7e8a5bSLeon Alrae     MIPSCPU *cpu = opaque;
518e7e8a5bSLeon Alrae     CPUState *cs = CPU(cpu);
528e7e8a5bSLeon Alrae 
538e7e8a5bSLeon Alrae     cpu_reset(cs);
548e7e8a5bSLeon Alrae 
558e7e8a5bSLeon Alrae     /* All VPs are halted on reset. Leave powering up to CPC. */
568e7e8a5bSLeon Alrae     cs->halted = 1;
578e7e8a5bSLeon Alrae }
588e7e8a5bSLeon Alrae 
598e7e8a5bSLeon Alrae static void mips_cps_realize(DeviceState *dev, Error **errp)
608e7e8a5bSLeon Alrae {
618e7e8a5bSLeon Alrae     MIPSCPSState *s = MIPS_CPS(dev);
628e7e8a5bSLeon Alrae     CPUMIPSState *env;
638e7e8a5bSLeon Alrae     MIPSCPU *cpu;
648e7e8a5bSLeon Alrae     int i;
65a9bd9b5aSLeon Alrae     Error *err = NULL;
66a9bd9b5aSLeon Alrae     target_ulong gcr_base;
678e7e8a5bSLeon Alrae 
688e7e8a5bSLeon Alrae     for (i = 0; i < s->num_vp; i++) {
698e7e8a5bSLeon Alrae         cpu = cpu_mips_init(s->cpu_model);
708e7e8a5bSLeon Alrae         if (cpu == NULL) {
718e7e8a5bSLeon Alrae             error_setg(errp, "%s: CPU initialization failed\n",  __func__);
728e7e8a5bSLeon Alrae             return;
738e7e8a5bSLeon Alrae         }
748e7e8a5bSLeon Alrae         env = &cpu->env;
758e7e8a5bSLeon Alrae 
768e7e8a5bSLeon Alrae         /* Init internal devices */
778e7e8a5bSLeon Alrae         cpu_mips_irq_init_cpu(env);
788e7e8a5bSLeon Alrae         cpu_mips_clock_init(env);
798e7e8a5bSLeon Alrae         qemu_register_reset(main_cpu_reset, cpu);
808e7e8a5bSLeon Alrae     }
81a9bd9b5aSLeon Alrae 
82a9bd9b5aSLeon Alrae     cpu = MIPS_CPU(first_cpu);
83a9bd9b5aSLeon Alrae     env = &cpu->env;
84a9bd9b5aSLeon Alrae 
85*2edd5261SLeon Alrae     /* Cluster Power Controller */
86*2edd5261SLeon Alrae     object_initialize(&s->cpc, sizeof(s->cpc), TYPE_MIPS_CPC);
87*2edd5261SLeon Alrae     qdev_set_parent_bus(DEVICE(&s->cpc), sysbus_get_default());
88*2edd5261SLeon Alrae 
89*2edd5261SLeon Alrae     object_property_set_int(OBJECT(&s->cpc), s->num_vp, "num-vp", &err);
90*2edd5261SLeon Alrae     object_property_set_int(OBJECT(&s->cpc), 1, "vp-start-running", &err);
91*2edd5261SLeon Alrae     object_property_set_bool(OBJECT(&s->cpc), true, "realized", &err);
92*2edd5261SLeon Alrae     if (err != NULL) {
93*2edd5261SLeon Alrae         error_propagate(errp, err);
94*2edd5261SLeon Alrae         return;
95*2edd5261SLeon Alrae     }
96*2edd5261SLeon Alrae 
97*2edd5261SLeon Alrae     memory_region_add_subregion(&s->container, 0,
98*2edd5261SLeon Alrae                             sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpc), 0));
99*2edd5261SLeon Alrae 
100a9bd9b5aSLeon Alrae     /* Global Configuration Registers */
101a9bd9b5aSLeon Alrae     gcr_base = env->CP0_CMGCRBase << 4;
102a9bd9b5aSLeon Alrae 
103a9bd9b5aSLeon Alrae     object_initialize(&s->gcr, sizeof(s->gcr), TYPE_MIPS_GCR);
104a9bd9b5aSLeon Alrae     qdev_set_parent_bus(DEVICE(&s->gcr), sysbus_get_default());
105a9bd9b5aSLeon Alrae 
106a9bd9b5aSLeon Alrae     object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp", &err);
107a9bd9b5aSLeon Alrae     object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev", &err);
108a9bd9b5aSLeon Alrae     object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base", &err);
109*2edd5261SLeon Alrae     object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc", &err);
110a9bd9b5aSLeon Alrae     object_property_set_bool(OBJECT(&s->gcr), true, "realized", &err);
111a9bd9b5aSLeon Alrae     if (err != NULL) {
112a9bd9b5aSLeon Alrae         error_propagate(errp, err);
113a9bd9b5aSLeon Alrae         return;
114a9bd9b5aSLeon Alrae     }
115a9bd9b5aSLeon Alrae 
116a9bd9b5aSLeon Alrae     memory_region_add_subregion(&s->container, gcr_base,
117a9bd9b5aSLeon Alrae                             sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gcr), 0));
1188e7e8a5bSLeon Alrae }
1198e7e8a5bSLeon Alrae 
1208e7e8a5bSLeon Alrae static Property mips_cps_properties[] = {
1218e7e8a5bSLeon Alrae     DEFINE_PROP_UINT32("num-vp", MIPSCPSState, num_vp, 1),
1228e7e8a5bSLeon Alrae     DEFINE_PROP_UINT32("num-irq", MIPSCPSState, num_irq, 8),
1238e7e8a5bSLeon Alrae     DEFINE_PROP_STRING("cpu-model", MIPSCPSState, cpu_model),
1248e7e8a5bSLeon Alrae     DEFINE_PROP_END_OF_LIST()
1258e7e8a5bSLeon Alrae };
1268e7e8a5bSLeon Alrae 
1278e7e8a5bSLeon Alrae static void mips_cps_class_init(ObjectClass *klass, void *data)
1288e7e8a5bSLeon Alrae {
1298e7e8a5bSLeon Alrae     DeviceClass *dc = DEVICE_CLASS(klass);
1308e7e8a5bSLeon Alrae 
1318e7e8a5bSLeon Alrae     dc->realize = mips_cps_realize;
1328e7e8a5bSLeon Alrae     dc->props = mips_cps_properties;
1338e7e8a5bSLeon Alrae }
1348e7e8a5bSLeon Alrae 
1358e7e8a5bSLeon Alrae static const TypeInfo mips_cps_info = {
1368e7e8a5bSLeon Alrae     .name = TYPE_MIPS_CPS,
1378e7e8a5bSLeon Alrae     .parent = TYPE_SYS_BUS_DEVICE,
1388e7e8a5bSLeon Alrae     .instance_size = sizeof(MIPSCPSState),
1398e7e8a5bSLeon Alrae     .instance_init = mips_cps_init,
1408e7e8a5bSLeon Alrae     .class_init = mips_cps_class_init,
1418e7e8a5bSLeon Alrae };
1428e7e8a5bSLeon Alrae 
1438e7e8a5bSLeon Alrae static void mips_cps_register_types(void)
1448e7e8a5bSLeon Alrae {
1458e7e8a5bSLeon Alrae     type_register_static(&mips_cps_info);
1468e7e8a5bSLeon Alrae }
1478e7e8a5bSLeon Alrae 
1488e7e8a5bSLeon Alrae type_init(mips_cps_register_types)
149