master
c 244 lines 7.19 KB
Raw
1 /*
2 * Coherent Manager Global Control Register
3 *
4 * Copyright (C) 2015 Imagination Technologies
5 *
6 * Copyright (C) 2025 MIPS
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 *
10 * Reference: MIPS P8700 documentation
11 * (https://mips.com/products/hardware/p8700/)
12 */
13
14 #include "qemu/osdep.h"
15 #include "qemu/log.h"
16 #include "qemu/module.h"
17 #include "qapi/error.h"
18 #include "hw/core/sysbus.h"
19 #include "migration/vmstate.h"
20 #include "hw/misc/riscv_cmgcr.h"
21 #include "hw/core/qdev-properties.h"
22 #include "exec/target_page.h"
23
24 #include "target/riscv/cpu.h"
25
26 #define CM_RESET_VEC 0x1FC00000
27 #define GCR_ADDRSPACE_SZ 0x8000
28
29 /* Offsets to register blocks */
30 #define RISCV_GCB_OFS 0x0000 /* Global Control Block */
31 #define RISCV_CLCB_OFS 0x2000 /* Core Control Block */
32 #define RISCV_CORE_REG_STRIDE 0x100 /* Stride between core-specific registers */
33
34 /* Global Control Block Register Map */
35 #define GCR_CONFIG_OFS 0x0000
36 #define GCR_BASE_OFS 0x0008
37 #define GCR_REV_OFS 0x0030
38 #define GCR_CPC_STATUS_OFS 0x00F0
39 #define GCR_L2_CONFIG_OFS 0x0130
40
41 /* GCR_L2_CONFIG register fields */
42 #define GCR_L2_CONFIG_BYPASS_SHF 20
43 #define GCR_L2_CONFIG_BYPASS_MSK ((0x1ULL) << GCR_L2_CONFIG_BYPASS_SHF)
44
45 /* GCR_BASE register fields */
46 #define GCR_BASE_GCRBASE_MSK 0xffffffff8000ULL
47
48 /* GCR_CPC_BASE register fields */
49 #define GCR_CPC_BASE_CPCEN_MSK 1
50 #define GCR_CPC_BASE_CPCBASE_MSK 0xFFFFFFFF8000ULL
51 #define GCR_CPC_BASE_MSK (GCR_CPC_BASE_CPCEN_MSK | GCR_CPC_BASE_CPCBASE_MSK)
52
53 /* GCR_CL_RESETBASE_OFS register fields */
54 #define GCR_CL_RESET_BASE_RESETBASE_MSK 0xFFFFFFFFFFFFF000U
55 #define GCR_CL_RESET_BASE_MSK GCR_CL_RESET_BASE_RESETBASE_MSK
56
57 static inline bool is_cpc_connected(RISCVGCRState *s)
58 {
59 return s->cpc_mr != NULL;
60 }
61
62 static inline void update_cpc_base(RISCVGCRState *gcr, uint64_t val)
63 {
64 if (is_cpc_connected(gcr)) {
65 gcr->cpc_base = val & GCR_CPC_BASE_MSK;
66 memory_region_transaction_begin();
67 memory_region_set_address(gcr->cpc_mr,
68 gcr->cpc_base & GCR_CPC_BASE_CPCBASE_MSK);
69 memory_region_set_enabled(gcr->cpc_mr,
70 gcr->cpc_base & GCR_CPC_BASE_CPCEN_MSK);
71 memory_region_transaction_commit();
72 }
73 }
74
75 static inline void update_gcr_base(RISCVGCRState *gcr, uint64_t val)
76 {
77 gcr->gcr_base = val & GCR_BASE_GCRBASE_MSK;
78 memory_region_set_address(&gcr->iomem, gcr->gcr_base);
79
80 /*
81 * For boston-aia, cpc_base is set to gcr_base + 0x8001 to enable
82 * cpc automatically.
83 */
84 update_cpc_base(gcr, val + 0x8001);
85 }
86
87 /* Read GCR registers */
88 static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size)
89 {
90 RISCVGCRState *gcr = (RISCVGCRState *) opaque;
91
92 switch (addr) {
93 /* Global Control Block Register */
94 case GCR_CONFIG_OFS:
95 /* Set PCORES to 0 */
96 return 0;
97 case GCR_BASE_OFS:
98 return gcr->gcr_base;
99 case GCR_REV_OFS:
100 return gcr->gcr_rev;
101 case GCR_CPC_STATUS_OFS:
102 return is_cpc_connected(gcr);
103 case GCR_L2_CONFIG_OFS:
104 /* L2 BYPASS */
105 return GCR_L2_CONFIG_BYPASS_MSK;
106 default:
107 qemu_log_mask(LOG_UNIMP, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx
108 "\n", size, addr);
109 }
110 return 0;
111 }
112
113 static inline target_ulong get_exception_base(RISCVGCRVPState *vps)
114 {
115 return vps->reset_base & GCR_CL_RESET_BASE_RESETBASE_MSK;
116 }
117
118 /* Write GCR registers */
119 static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
120 {
121 RISCVGCRState *gcr = (RISCVGCRState *)opaque;
122 RISCVGCRVPState *current_vps;
123 int cpu_index, c, h;
124
125 for (c = 0; c < gcr->num_core; c++) {
126 for (h = 0; h < gcr->num_hart; h++) {
127 if (addr == RISCV_CLCB_OFS + c * RISCV_CORE_REG_STRIDE + h * 8) {
128 cpu_index = c * gcr->num_hart + h;
129 current_vps = &gcr->vps[cpu_index];
130 current_vps->reset_base = data & GCR_CL_RESET_BASE_MSK;
131 cpu_set_exception_base(cpu_index + gcr->cluster_id *
132 gcr->num_core * gcr->num_hart,
133 get_exception_base(current_vps));
134 return;
135 }
136 }
137 }
138
139 switch (addr) {
140 case GCR_BASE_OFS:
141 update_gcr_base(gcr, data);
142 break;
143 default:
144 qemu_log_mask(LOG_UNIMP, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx
145 " 0x%" PRIx64 "\n", size, addr, data);
146 break;
147 }
148 }
149
150 static const MemoryRegionOps gcr_ops = {
151 .read = gcr_read,
152 .write = gcr_write,
153 .endianness = DEVICE_LITTLE_ENDIAN,
154 .impl = {
155 .max_access_size = 8,
156 },
157 };
158
159 static void riscv_gcr_init(Object *obj)
160 {
161 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
162 RISCVGCRState *s = RISCV_GCR(obj);
163
164 memory_region_init_io(&s->iomem, OBJECT(s), &gcr_ops, s,
165 "riscv-gcr", GCR_ADDRSPACE_SZ);
166 sysbus_init_mmio(sbd, &s->iomem);
167 }
168
169 static void riscv_gcr_reset(DeviceState *dev)
170 {
171 RISCVGCRState *s = RISCV_GCR(dev);
172 int i;
173
174 /* Update cpc_base to gcr_base + 0x8001 to enable cpc automatically. */
175 update_cpc_base(s, s->gcr_base + 0x8001);
176
177 for (i = 0; i < s->num_vps; i++) {
178 s->vps[i].reset_base = CM_RESET_VEC & GCR_CL_RESET_BASE_MSK;
179 cpu_set_exception_base(i, get_exception_base(&s->vps[i]));
180 }
181 }
182
183 static const VMStateDescription vmstate_riscv_gcr = {
184 .name = "riscv-gcr",
185 .version_id = 0,
186 .minimum_version_id = 0,
187 .fields = (VMStateField[]) {
188 VMSTATE_UINT64(cpc_base, RISCVGCRState),
189 VMSTATE_END_OF_LIST()
190 },
191 };
192
193 static const Property riscv_gcr_properties[] = {
194 DEFINE_PROP_UINT32("cluster-id", RISCVGCRState, cluster_id, 0),
195 DEFINE_PROP_UINT32("num-vp", RISCVGCRState, num_vps, 1),
196 DEFINE_PROP_UINT32("num-hart", RISCVGCRState, num_hart, 1),
197 DEFINE_PROP_UINT32("num-core", RISCVGCRState, num_core, 1),
198 DEFINE_PROP_INT32("gcr-rev", RISCVGCRState, gcr_rev, 0xa00),
199 DEFINE_PROP_UINT64("gcr-base", RISCVGCRState, gcr_base, GCR_BASE_ADDR),
200 DEFINE_PROP_LINK("cpc", RISCVGCRState, cpc_mr, TYPE_MEMORY_REGION,
201 MemoryRegion *),
202 };
203
204 static void riscv_gcr_realize(DeviceState *dev, Error **errp)
205 {
206 RISCVGCRState *s = RISCV_GCR(dev);
207
208 /* Validate num_vps */
209 if (s->num_vps == 0) {
210 error_setg(errp, "num-vp must be at least 1");
211 return;
212 }
213 if (s->num_vps > GCR_MAX_VPS) {
214 error_setg(errp, "num-vp cannot exceed %d", GCR_MAX_VPS);
215 return;
216 }
217
218 /* Create local set of registers for each VP */
219 s->vps = g_new(RISCVGCRVPState, s->num_vps);
220 }
221
222 static void riscv_gcr_class_init(ObjectClass *klass, const void *data)
223 {
224 DeviceClass *dc = DEVICE_CLASS(klass);
225 device_class_set_props(dc, riscv_gcr_properties);
226 dc->vmsd = &vmstate_riscv_gcr;
227 device_class_set_legacy_reset(dc, riscv_gcr_reset);
228 dc->realize = riscv_gcr_realize;
229 }
230
231 static const TypeInfo riscv_gcr_info = {
232 .name = TYPE_RISCV_GCR,
233 .parent = TYPE_SYS_BUS_DEVICE,
234 .instance_size = sizeof(RISCVGCRState),
235 .instance_init = riscv_gcr_init,
236 .class_init = riscv_gcr_class_init,
237 };
238
239 static void riscv_gcr_register_types(void)
240 {
241 type_register_static(&riscv_gcr_info);
242 }
243
244 type_init(riscv_gcr_register_types)