master
c 196 lines 6.89 KB
Raw
1 /*
2 * Coherent Processing System emulation.
3 *
4 * Copyright (c) 2016 Imagination Technologies
5 *
6 * Copyright (c) 2025 MIPS
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 *
10 */
11
12 #include "qemu/osdep.h"
13 #include "qapi/error.h"
14 #include "qemu/module.h"
15 #include "hw/riscv/cps.h"
16 #include "hw/core/qdev-properties.h"
17 #include "system/reset.h"
18 #include "hw/intc/riscv_aclint.h"
19 #include "hw/intc/riscv_aplic.h"
20 #include "hw/intc/riscv_imsic.h"
21 #include "hw/pci/msi.h"
22
23 static void riscv_cps_init(Object *obj)
24 {
25 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
26 RISCVCPSState *s = RISCV_CPS(obj);
27
28 /*
29 * Cover entire address space as there do not seem to be any
30 * constraints for the base address of CPC .
31 */
32 memory_region_init(&s->container, obj, "mips-cps-container", UINT64_MAX);
33 sysbus_init_mmio(sbd, &s->container);
34 }
35
36 static void main_cpu_reset(void *opaque)
37 {
38 CPUState *cs = opaque;
39
40 cpu_reset(cs);
41 }
42
43 static void riscv_cps_realize(DeviceState *dev, Error **errp)
44 {
45 RISCVCPSState *s = RISCV_CPS(dev);
46 RISCVCPU *cpu;
47 int i;
48
49 /* Validate num_vp */
50 if (s->num_vp == 0) {
51 error_setg(errp, "num-vp must be at least 1");
52 return;
53 }
54 if (s->num_vp > MAX_HARTS) {
55 error_setg(errp, "num-vp cannot exceed %d", MAX_HARTS);
56 return;
57 }
58
59 /* Allocate CPU array */
60 s->cpus = g_new0(CPUState *, s->num_vp);
61
62 /* Set up cpu_index and mhartid for avaiable CPUs. */
63 int harts_in_cluster = s->num_hart * s->num_core;
64 int num_of_clusters = s->num_vp / harts_in_cluster;
65 for (i = 0; i < s->num_vp; i++) {
66 cpu = RISCV_CPU(object_new(s->cpu_type));
67
68 /* All VPs are halted on reset. Leave powering up to CPC. */
69 object_property_set_bool(OBJECT(cpu), "start-powered-off", true,
70 &error_abort);
71
72 if (!qdev_realize_and_unref(DEVICE(cpu), NULL, errp)) {
73 return;
74 }
75
76 /* Store CPU in array */
77 s->cpus[i] = CPU(cpu);
78
79 /* Set up mhartid */
80 int cluster_id = i / harts_in_cluster;
81 int hart_id = (i % harts_in_cluster) % s->num_hart;
82 int core_id = (i % harts_in_cluster) / s->num_hart;
83 int mhartid = (cluster_id << MHARTID_CLUSTER_SHIFT) +
84 (core_id << MHARTID_CORE_SHIFT) +
85 (hart_id << MHARTID_HART_SHIFT);
86 cpu->env.mhartid = mhartid;
87 qemu_register_reset(main_cpu_reset, s->cpus[i]);
88 }
89
90 /* Cluster Power Controller */
91 object_initialize_child(OBJECT(dev), "cpc", &s->cpc, TYPE_RISCV_CPC);
92 object_property_set_uint(OBJECT(&s->cpc), "cluster-id", 0,
93 &error_abort);
94 object_property_set_uint(OBJECT(&s->cpc), "num-vp", s->num_vp,
95 &error_abort);
96 object_property_set_uint(OBJECT(&s->cpc), "num-hart", s->num_hart,
97 &error_abort);
98 object_property_set_uint(OBJECT(&s->cpc), "num-core", s->num_core,
99 &error_abort);
100
101 /* Pass CPUs to CPC using link properties */
102 for (i = 0; i < s->num_vp; i++) {
103 char *propname = g_strdup_printf("cpu[%d]", i);
104 object_property_set_link(OBJECT(&s->cpc), propname,
105 OBJECT(s->cpus[i]), &error_abort);
106 g_free(propname);
107 }
108
109 if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpc), errp)) {
110 return;
111 }
112
113 memory_region_add_subregion(&s->container, 0,
114 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpc), 0));
115
116 /* Global Configuration Registers */
117 object_initialize_child(OBJECT(dev), "gcr", &s->gcr, TYPE_RISCV_GCR);
118 object_property_set_uint(OBJECT(&s->gcr), "cluster-id", 0,
119 &error_abort);
120 object_property_set_uint(OBJECT(&s->gcr), "num-vp", s->num_vp,
121 &error_abort);
122 object_property_set_int(OBJECT(&s->gcr), "gcr-rev", 0xa00,
123 &error_abort);
124 object_property_set_int(OBJECT(&s->gcr), "gcr-base", s->gcr_base,
125 &error_abort);
126 object_property_set_link(OBJECT(&s->gcr), "cpc", OBJECT(&s->cpc.mr),
127 &error_abort);
128 if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) {
129 return;
130 }
131
132 memory_region_add_subregion(&s->container, s->gcr_base,
133 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gcr), 0));
134
135 for (i = 0; i < num_of_clusters; i++) {
136 uint64_t cm_base = GLOBAL_CM_BASE + (CM_SIZE * i);
137 uint32_t hartid_base = i << MHARTID_CLUSTER_SHIFT;
138 s->aplic = riscv_aplic_create(cm_base + AIA_PLIC_M_OFFSET,
139 AIA_PLIC_M_SIZE,
140 hartid_base, /* hartid_base */
141 MAX_HARTS, /* num_harts */
142 APLIC_NUM_SOURCES,
143 APLIC_NUM_PRIO_BITS,
144 false, true, NULL);
145 riscv_aplic_create(cm_base + AIA_PLIC_S_OFFSET,
146 AIA_PLIC_S_SIZE,
147 hartid_base, /* hartid_base */
148 MAX_HARTS, /* num_harts */
149 APLIC_NUM_SOURCES,
150 APLIC_NUM_PRIO_BITS,
151 false, false, s->aplic);
152 /* PLIC changes msi_nonbroken to ture. We revert the change. */
153 msi_nonbroken = false;
154 riscv_aclint_swi_create(cm_base + AIA_CLINT_OFFSET,
155 hartid_base, MAX_HARTS, false);
156 riscv_aclint_mtimer_create(cm_base + AIA_CLINT_OFFSET +
157 RISCV_ACLINT_SWI_SIZE,
158 RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
159 hartid_base,
160 MAX_HARTS,
161 RISCV_ACLINT_DEFAULT_MTIMECMP,
162 RISCV_ACLINT_DEFAULT_MTIME,
163 RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, false);
164 }
165 }
166
167 static const Property riscv_cps_properties[] = {
168 DEFINE_PROP_UINT32("num-vp", RISCVCPSState, num_vp, 1),
169 DEFINE_PROP_UINT32("num-hart", RISCVCPSState, num_hart, 1),
170 DEFINE_PROP_UINT32("num-core", RISCVCPSState, num_core, 1),
171 DEFINE_PROP_UINT64("gcr-base", RISCVCPSState, gcr_base, GCR_BASE_ADDR),
172 DEFINE_PROP_STRING("cpu-type", RISCVCPSState, cpu_type),
173 };
174
175 static void riscv_cps_class_init(ObjectClass *klass, const void *data)
176 {
177 DeviceClass *dc = DEVICE_CLASS(klass);
178
179 dc->realize = riscv_cps_realize;
180 device_class_set_props(dc, riscv_cps_properties);
181 }
182
183 static const TypeInfo riscv_cps_info = {
184 .name = TYPE_RISCV_CPS,
185 .parent = TYPE_SYS_BUS_DEVICE,
186 .instance_size = sizeof(RISCVCPSState),
187 .instance_init = riscv_cps_init,
188 .class_init = riscv_cps_class_init,
189 };
190
191 static void riscv_cps_register_types(void)
192 {
193 type_register_static(&riscv_cps_info);
194 }
195
196 type_init(riscv_cps_register_types)