master
c 371 lines 11.4 KB
Raw
1 /*
2 * Hexagon Global Registers
3 *
4 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #include "qemu/osdep.h"
9 #include "hw/hexagon/hexagon.h"
10 #include "hw/hexagon/hexagon_globalreg.h"
11 #include "hw/core/qdev-properties.h"
12 #include "hw/core/sysbus.h"
13 #include "hw/core/resettable.h"
14 #include "hw/intc/hex-l2vic.h"
15 #include "hw/timer/qct-qtimer.h"
16 #include "migration/vmstate.h"
17 #include "qom/object.h"
18 #include "target/hexagon/cpu.h"
19 #include "target/hexagon/hex_regs.h"
20 #include "qemu/log.h"
21 #include "trace.h"
22 #include "qapi/error.h"
23
24 #define IMMUTABLE (~0)
25 #define INVALID_REG_VAL 0xdeadbeef
26
27 static const char *hex_sreg_names[] = {
28 [HEX_SREG_SGP0] = "sgp0",
29 [HEX_SREG_SGP1] = "sgp1",
30 [HEX_SREG_STID] = "stid",
31 [HEX_SREG_ELR] = "elr",
32 [HEX_SREG_BADVA0] = "badva0",
33 [HEX_SREG_BADVA1] = "badva1",
34 [HEX_SREG_SSR] = "ssr",
35 [HEX_SREG_CCR] = "ccr",
36 [HEX_SREG_HTID] = "htid",
37 [HEX_SREG_BADVA] = "badva",
38 [HEX_SREG_IMASK] = "imask",
39 [HEX_SREG_GEVB] = "gevb",
40 [HEX_SREG_EVB] = "evb",
41 [HEX_SREG_MODECTL] = "modectl",
42 [HEX_SREG_SYSCFG] = "syscfg",
43 [HEX_SREG_IPENDAD] = "ipendad",
44 [HEX_SREG_VID] = "vid",
45 [HEX_SREG_VID1] = "vid1",
46 [HEX_SREG_BESTWAIT] = "bestwait",
47 [HEX_SREG_IEL] = "iel",
48 [HEX_SREG_SCHEDCFG] = "schedcfg",
49 [HEX_SREG_IAHL] = "iahl",
50 [HEX_SREG_CFGBASE] = "cfgbase",
51 [HEX_SREG_DIAG] = "diag",
52 [HEX_SREG_REV] = "rev",
53 [HEX_SREG_PCYCLELO] = "pcyclelo",
54 [HEX_SREG_PCYCLEHI] = "pcyclehi",
55 [HEX_SREG_ISDBST] = "isdbst",
56 [HEX_SREG_ISDBCFG0] = "isdbcfg0",
57 [HEX_SREG_ISDBCFG1] = "isdbcfg1",
58 [HEX_SREG_LIVELOCK] = "livelock",
59 [HEX_SREG_BRKPTPC0] = "brkptpc0",
60 [HEX_SREG_BRKPTCFG0] = "brkptcfg0",
61 [HEX_SREG_BRKPTPC1] = "brkptpc1",
62 [HEX_SREG_BRKPTCFG1] = "brkptcfg1",
63 [HEX_SREG_ISDBMBXIN] = "isdbmbxin",
64 [HEX_SREG_ISDBMBXOUT] = "isdbmbxout",
65 [HEX_SREG_ISDBEN] = "isdben",
66 [HEX_SREG_ISDBGPR] = "isdbgpr",
67 [HEX_SREG_PMUCNT4] = "pmucnt4",
68 [HEX_SREG_PMUCNT5] = "pmucnt5",
69 [HEX_SREG_PMUCNT6] = "pmucnt6",
70 [HEX_SREG_PMUCNT7] = "pmucnt7",
71 [HEX_SREG_PMUCNT0] = "pmucnt0",
72 [HEX_SREG_PMUCNT1] = "pmucnt1",
73 [HEX_SREG_PMUCNT2] = "pmucnt2",
74 [HEX_SREG_PMUCNT3] = "pmucnt3",
75 [HEX_SREG_PMUEVTCFG] = "pmuevtcfg",
76 [HEX_SREG_PMUSTID0] = "pmustid0",
77 [HEX_SREG_PMUEVTCFG1] = "pmuevtcfg1",
78 [HEX_SREG_PMUSTID1] = "pmustid1",
79 [HEX_SREG_TIMERLO] = "timerlo",
80 [HEX_SREG_TIMERHI] = "timerhi",
81 [HEX_SREG_PMUCFG] = "pmucfg",
82 [HEX_SREG_S59] = "s59",
83 [HEX_SREG_S60] = "s60",
84 [HEX_SREG_S61] = "s61",
85 [HEX_SREG_S62] = "s62",
86 [HEX_SREG_S63] = "s63",
87 };
88
89 static const char *get_sreg_name(uint32_t reg)
90 {
91 if (reg < ARRAY_SIZE(hex_sreg_names) && hex_sreg_names[reg]) {
92 return hex_sreg_names[reg];
93 }
94 return "UNKNOWN";
95 }
96
97 /* Global system register mutability masks */
98 static const uint32_t global_sreg_immut_masks[NUM_SREGS] = {
99 [HEX_SREG_EVB] = 0x000000ff,
100 [HEX_SREG_MODECTL] = IMMUTABLE,
101 [HEX_SREG_SYSCFG] = 0x80001c00,
102 [HEX_SREG_IPENDAD] = IMMUTABLE,
103 [HEX_SREG_VID] = 0xfc00fc00,
104 [HEX_SREG_VID1] = 0xfc00fc00,
105 [HEX_SREG_BESTWAIT] = 0xfffffe00,
106 [HEX_SREG_IAHL] = 0x00000000,
107 [HEX_SREG_SCHEDCFG] = 0xfffffee0,
108 [HEX_SREG_CFGBASE] = IMMUTABLE,
109 [HEX_SREG_DIAG] = 0x00000000,
110 [HEX_SREG_REV] = IMMUTABLE,
111 [HEX_SREG_ISDBST] = IMMUTABLE,
112 [HEX_SREG_ISDBCFG0] = 0xe0000000,
113 [HEX_SREG_BRKPTPC0] = 0x00000003,
114 [HEX_SREG_BRKPTCFG0] = 0xfc007000,
115 [HEX_SREG_BRKPTPC1] = 0x00000003,
116 [HEX_SREG_BRKPTCFG1] = 0xfc007000,
117 [HEX_SREG_ISDBMBXIN] = IMMUTABLE,
118 [HEX_SREG_ISDBMBXOUT] = 0x00000000,
119 [HEX_SREG_ISDBEN] = 0xfffffffe,
120 [HEX_SREG_TIMERLO] = IMMUTABLE,
121 [HEX_SREG_TIMERHI] = IMMUTABLE,
122 };
123
124 static void hexagon_globalreg_init(Object *obj)
125 {
126 HexagonGlobalRegState *s = HEXAGON_GLOBALREG(obj);
127
128 memset(s->regs, 0, sizeof(s->regs));
129 }
130
131 static inline uint32_t apply_write_mask(uint32_t new_val, uint32_t cur_val,
132 uint32_t reg_mask)
133 {
134 if (reg_mask) {
135 return (new_val & ~reg_mask) | (cur_val & reg_mask);
136 }
137 return new_val;
138 }
139
140 static inline bool is_vid_reg(uint32_t reg)
141 {
142 return reg == HEX_SREG_VID || reg == HEX_SREG_VID1;
143 }
144
145 static inline bool is_timer_reg(uint32_t reg)
146 {
147 return reg == HEX_SREG_TIMERLO || reg == HEX_SREG_TIMERHI;
148 }
149
150 static uint32_t get_reg_value(HexagonGlobalRegState *s, uint32_t reg)
151 {
152 if (is_vid_reg(reg)) {
153 return l2vic_read_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1);
154 }
155 if (is_timer_reg(reg)) {
156 return reg == HEX_SREG_TIMERLO ?
157 qct_qtimer_get_timer_lo(s->qtimer) :
158 qct_qtimer_get_timer_hi(s->qtimer);
159 }
160 return s->regs[reg];
161 }
162
163 static void set_reg_value(HexagonGlobalRegState *s, uint32_t reg,
164 uint32_t value)
165 {
166 s->regs[reg] = value;
167 if (is_vid_reg(reg)) {
168 l2vic_update_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1, value);
169 }
170 }
171
172 uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
173 uint32_t htid)
174 {
175 uint32_t value;
176
177 if (!s) {
178 return 0;
179 }
180 g_assert(reg < NUM_SREGS);
181 g_assert(reg >= HEX_SREG_GLB_START);
182
183 value = get_reg_value(s, reg);
184
185 trace_hexagon_globalreg_read(htid, get_sreg_name(reg), value);
186 return value;
187 }
188
189 void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg,
190 uint32_t value, uint32_t htid)
191 {
192 if (!s) {
193 return;
194 }
195 g_assert(reg < NUM_SREGS);
196 g_assert(reg >= HEX_SREG_GLB_START);
197 set_reg_value(s, reg, value);
198 trace_hexagon_globalreg_write(htid, get_sreg_name(reg), value);
199 }
200
201 uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
202 uint32_t value)
203 {
204 uint32_t reg_mask;
205 uint32_t cur_val;
206
207 if (!s) {
208 return value;
209 }
210 g_assert(reg < NUM_SREGS);
211 g_assert(reg >= HEX_SREG_GLB_START);
212 reg_mask = global_sreg_immut_masks[reg];
213 cur_val = get_reg_value(s, reg);
214 return reg_mask == IMMUTABLE ?
215 cur_val :
216 apply_write_mask(value, cur_val, reg_mask);
217 }
218
219 void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg,
220 uint32_t value)
221 {
222 if (!s) {
223 return;
224 }
225 set_reg_value(s, reg, hexagon_globalreg_masked_value(s, reg, value));
226 }
227
228 uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s)
229 {
230 g_assert(s);
231 return s->g_pcycle_base;
232 }
233
234 void hexagon_globalreg_set_pcycle_base(HexagonGlobalRegState *s,
235 uint64_t value)
236 {
237 g_assert(s);
238 s->g_pcycle_base = value;
239 }
240
241 static void do_hexagon_globalreg_reset(HexagonGlobalRegState *s)
242 {
243 uint32_t isdben_val = 0;
244
245 g_assert(s);
246 memset(s->regs, 0, sizeof(s->regs));
247
248 s->g_pcycle_base = 0;
249
250 s->regs[HEX_SREG_EVB] = s->boot_evb;
251 s->regs[HEX_SREG_CFGBASE] = HEXAGON_CFG_ADDR_BASE(s->config_table_addr);
252 s->regs[HEX_SREG_REV] = s->dsp_rev;
253
254 if (s->isdben_etm_enable) {
255 isdben_val |= (1 << 0); /* ETM enable bit */
256 }
257 if (s->isdben_dfd_enable) {
258 isdben_val |= (1 << 1); /* DFD enable bit */
259 }
260 if (s->isdben_trusted) {
261 isdben_val |= (1 << 2); /* Trusted bit */
262 }
263 if (s->isdben_secure) {
264 isdben_val |= (1 << 3); /* Secure bit */
265 }
266 s->regs[HEX_SREG_ISDBEN] = isdben_val;
267 s->regs[HEX_SREG_MODECTL] = 0x1;
268
269 /*
270 * These register indices are placeholders in these arrays
271 * and their actual values are synthesized from state elsewhere.
272 * We can initialize these with invalid values so that if we
273 * mistakenly generate reads, they will look obviously wrong.
274 */
275 s->regs[HEX_SREG_PCYCLELO] = INVALID_REG_VAL;
276 s->regs[HEX_SREG_PCYCLEHI] = INVALID_REG_VAL;
277 s->regs[HEX_SREG_TIMERLO] = INVALID_REG_VAL;
278 s->regs[HEX_SREG_TIMERHI] = INVALID_REG_VAL;
279 s->regs[HEX_SREG_PMUCNT0] = INVALID_REG_VAL;
280 s->regs[HEX_SREG_PMUCNT1] = INVALID_REG_VAL;
281 s->regs[HEX_SREG_PMUCNT2] = INVALID_REG_VAL;
282 s->regs[HEX_SREG_PMUCNT3] = INVALID_REG_VAL;
283 s->regs[HEX_SREG_PMUCNT4] = INVALID_REG_VAL;
284 s->regs[HEX_SREG_PMUCNT5] = INVALID_REG_VAL;
285 s->regs[HEX_SREG_PMUCNT6] = INVALID_REG_VAL;
286 s->regs[HEX_SREG_PMUCNT7] = INVALID_REG_VAL;
287 }
288
289 static void hexagon_globalreg_reset_hold(Object *obj, ResetType type)
290 {
291 HexagonGlobalRegState *s = HEXAGON_GLOBALREG(obj);
292 do_hexagon_globalreg_reset(s);
293 }
294
295 static void hexagon_globalreg_realize(DeviceState *dev, Error **errp)
296 {
297 HexagonGlobalRegState *s = HEXAGON_GLOBALREG(dev);
298
299 if (!s->l2vic) {
300 error_setg(errp, "hexagon_globalreg: 'l2vic' link property not set");
301 return;
302 }
303 if (!s->qtimer) {
304 error_setg(errp, "hexagon_globalreg: 'qtimer' link property not set");
305 return;
306 }
307 }
308
309 static const VMStateDescription vmstate_hexagon_globalreg = {
310 .name = "hexagon_globalreg",
311 .version_id = 1,
312 .minimum_version_id = 1,
313 .fields = (const VMStateField[]){
314 VMSTATE_UINT32_ARRAY(regs, HexagonGlobalRegState, NUM_SREGS),
315 VMSTATE_UINT64(g_pcycle_base, HexagonGlobalRegState),
316 VMSTATE_UINT32(boot_evb, HexagonGlobalRegState),
317 VMSTATE_UINT64(config_table_addr, HexagonGlobalRegState),
318 VMSTATE_UINT32(dsp_rev, HexagonGlobalRegState),
319 VMSTATE_BOOL(isdben_etm_enable, HexagonGlobalRegState),
320 VMSTATE_BOOL(isdben_dfd_enable, HexagonGlobalRegState),
321 VMSTATE_BOOL(isdben_trusted, HexagonGlobalRegState),
322 VMSTATE_BOOL(isdben_secure, HexagonGlobalRegState),
323 VMSTATE_END_OF_LIST()
324 }
325 };
326
327 static const Property hexagon_globalreg_properties[] = {
328 DEFINE_PROP_LINK("l2vic", HexagonGlobalRegState, l2vic,
329 TYPE_HEX_L2VIC_INTERFACE, HexL2VicInterface *),
330 DEFINE_PROP_LINK("qtimer", HexagonGlobalRegState, qtimer,
331 TYPE_QCT_QTIMER_INTERFACE, QctQtimerInterface *),
332 DEFINE_PROP_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0),
333 DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState,
334 config_table_addr, 0xffffffffULL),
335 DEFINE_PROP_UINT32("dsp-rev", HexagonGlobalRegState, dsp_rev, 0),
336 DEFINE_PROP_BOOL("isdben-etm-enable", HexagonGlobalRegState,
337 isdben_etm_enable, false),
338 DEFINE_PROP_BOOL("isdben-dfd-enable", HexagonGlobalRegState,
339 isdben_dfd_enable, false),
340 DEFINE_PROP_BOOL("isdben-trusted", HexagonGlobalRegState,
341 isdben_trusted, false),
342 DEFINE_PROP_BOOL("isdben-secure", HexagonGlobalRegState,
343 isdben_secure, false),
344 };
345
346 static void hexagon_globalreg_class_init(ObjectClass *klass, const void *data)
347 {
348 DeviceClass *dc = DEVICE_CLASS(klass);
349 ResettableClass *rc = RESETTABLE_CLASS(klass);
350
351 rc->phases.hold = hexagon_globalreg_reset_hold;
352 dc->realize = hexagon_globalreg_realize;
353 dc->vmsd = &vmstate_hexagon_globalreg;
354 dc->user_creatable = false;
355 device_class_set_props(dc, hexagon_globalreg_properties);
356 }
357
358 static const TypeInfo hexagon_globalreg_info = {
359 .name = TYPE_HEXAGON_GLOBALREG,
360 .parent = TYPE_SYS_BUS_DEVICE,
361 .instance_size = sizeof(HexagonGlobalRegState),
362 .instance_init = hexagon_globalreg_init,
363 .class_init = hexagon_globalreg_class_init,
364 };
365
366 static void hexagon_globalreg_register_types(void)
367 {
368 type_register_static(&hexagon_globalreg_info);
369 }
370
371 type_init(hexagon_globalreg_register_types)