]>
Commit | Line | Data |
---|---|---|
75750e4d PM |
1 | /* |
2 | * ARM IoTKit system control element | |
3 | * | |
4 | * Copyright (c) 2018 Linaro Limited | |
5 | * Written by Peter Maydell | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 or | |
9 | * (at your option) any later version. | |
10 | */ | |
11 | ||
12 | /* | |
13 | * This is a model of the "system control element" which is part of the | |
14 | * Arm IoTKit and documented in | |
50b52b18 | 15 | * https://developer.arm.com/documentation/ecm0601256/latest |
75750e4d PM |
16 | * Specifically, it implements the "system control register" blocks. |
17 | */ | |
18 | ||
19 | #include "qemu/osdep.h" | |
04836414 | 20 | #include "qemu/bitops.h" |
75750e4d | 21 | #include "qemu/log.h" |
0b8fa32f | 22 | #include "qemu/module.h" |
54d31236 | 23 | #include "sysemu/runstate.h" |
75750e4d PM |
24 | #include "trace.h" |
25 | #include "qapi/error.h" | |
75750e4d | 26 | #include "hw/sysbus.h" |
d6454270 | 27 | #include "migration/vmstate.h" |
75750e4d PM |
28 | #include "hw/registerfields.h" |
29 | #include "hw/misc/iotkit-sysctl.h" | |
a27bd6c7 | 30 | #include "hw/qdev-properties.h" |
419a7f80 | 31 | #include "hw/arm/armsse-version.h" |
0f862986 | 32 | #include "target/arm/arm-powerctl.h" |
75750e4d PM |
33 | |
34 | REG32(SECDBGSTAT, 0x0) | |
35 | REG32(SECDBGSET, 0x4) | |
36 | REG32(SECDBGCLR, 0x8) | |
04836414 PM |
37 | REG32(SCSECCTRL, 0xc) |
38 | REG32(FCLK_DIV, 0x10) | |
39 | REG32(SYSCLK_DIV, 0x14) | |
40 | REG32(CLOCK_FORCE, 0x18) | |
75750e4d PM |
41 | REG32(RESET_SYNDROME, 0x100) |
42 | REG32(RESET_MASK, 0x104) | |
43 | REG32(SWRESET, 0x108) | |
44 | FIELD(SWRESET, SWRESETREQ, 9, 1) | |
45 | REG32(GRETREG, 0x10c) | |
394e10d2 | 46 | REG32(INITSVTOR0, 0x110) |
246dbeb7 PM |
47 | FIELD(INITSVTOR0, LOCK, 0, 1) |
48 | FIELD(INITSVTOR0, VTOR, 7, 25) | |
04836414 | 49 | REG32(INITSVTOR1, 0x114) |
75750e4d | 50 | REG32(CPUWAIT, 0x118) |
04836414 | 51 | REG32(NMI_ENABLE, 0x11c) /* BUSWAIT in IoTKit */ |
75750e4d | 52 | REG32(WICCTRL, 0x120) |
04836414 | 53 | REG32(EWCTRL, 0x124) |
2672a6ca PM |
54 | REG32(PWRCTRL, 0x1fc) |
55 | FIELD(PWRCTRL, PPU_ACCESS_UNLOCK, 0, 1) | |
56 | FIELD(PWRCTRL, PPU_ACCESS_FILTER, 1, 1) | |
04836414 | 57 | REG32(PDCM_PD_SYS_SENSE, 0x200) |
c5ffe6c8 | 58 | REG32(PDCM_PD_CPU0_SENSE, 0x204) |
04836414 PM |
59 | REG32(PDCM_PD_SRAM0_SENSE, 0x20c) |
60 | REG32(PDCM_PD_SRAM1_SENSE, 0x210) | |
c5ffe6c8 PM |
61 | REG32(PDCM_PD_SRAM2_SENSE, 0x214) /* PDCM_PD_VMR0_SENSE on SSE300 */ |
62 | REG32(PDCM_PD_SRAM3_SENSE, 0x218) /* PDCM_PD_VMR1_SENSE on SSE300 */ | |
75750e4d PM |
63 | REG32(PID4, 0xfd0) |
64 | REG32(PID5, 0xfd4) | |
65 | REG32(PID6, 0xfd8) | |
66 | REG32(PID7, 0xfdc) | |
67 | REG32(PID0, 0xfe0) | |
68 | REG32(PID1, 0xfe4) | |
69 | REG32(PID2, 0xfe8) | |
70 | REG32(PID3, 0xfec) | |
71 | REG32(CID0, 0xff0) | |
72 | REG32(CID1, 0xff4) | |
73 | REG32(CID2, 0xff8) | |
74 | REG32(CID3, 0xffc) | |
75 | ||
76 | /* PID/CID values */ | |
6069bbc9 | 77 | static const int iotkit_sysctl_id[] = { |
75750e4d PM |
78 | 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */ |
79 | 0x54, 0xb8, 0x0b, 0x00, /* PID0..PID3 */ | |
80 | 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */ | |
81 | }; | |
82 | ||
6069bbc9 PM |
83 | /* Also used by the SSE300 */ |
84 | static const int sse200_sysctl_id[] = { | |
85 | 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */ | |
86 | 0x54, 0xb8, 0x1b, 0x00, /* PID0..PID3 */ | |
87 | 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */ | |
88 | }; | |
89 | ||
0f862986 PM |
90 | /* |
91 | * Set the initial secure vector table offset address for the core. | |
92 | * This will take effect when the CPU next resets. | |
93 | */ | |
94 | static void set_init_vtor(uint64_t cpuid, uint32_t vtor) | |
95 | { | |
96 | Object *cpuobj = OBJECT(arm_get_cpu_by_id(cpuid)); | |
97 | ||
98 | if (cpuobj) { | |
efba1595 | 99 | if (object_property_find(cpuobj, "init-svtor")) { |
5325cc34 | 100 | object_property_set_uint(cpuobj, "init-svtor", vtor, &error_abort); |
0f862986 PM |
101 | } |
102 | } | |
103 | } | |
104 | ||
75750e4d PM |
105 | static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset, |
106 | unsigned size) | |
107 | { | |
108 | IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque); | |
109 | uint64_t r; | |
110 | ||
111 | switch (offset) { | |
112 | case A_SECDBGSTAT: | |
113 | r = s->secure_debug; | |
114 | break; | |
04836414 | 115 | case A_SCSECCTRL: |
1cbd6fe4 PM |
116 | switch (s->sse_version) { |
117 | case ARMSSE_IOTKIT: | |
04836414 | 118 | goto bad_offset; |
1cbd6fe4 | 119 | case ARMSSE_SSE200: |
31b0c6b1 | 120 | case ARMSSE_SSE300: |
1cbd6fe4 PM |
121 | r = s->scsecctrl; |
122 | break; | |
123 | default: | |
124 | g_assert_not_reached(); | |
04836414 | 125 | } |
04836414 PM |
126 | break; |
127 | case A_FCLK_DIV: | |
1cbd6fe4 PM |
128 | switch (s->sse_version) { |
129 | case ARMSSE_IOTKIT: | |
04836414 | 130 | goto bad_offset; |
1cbd6fe4 | 131 | case ARMSSE_SSE200: |
31b0c6b1 | 132 | case ARMSSE_SSE300: |
1cbd6fe4 PM |
133 | r = s->fclk_div; |
134 | break; | |
135 | default: | |
136 | g_assert_not_reached(); | |
04836414 | 137 | } |
04836414 PM |
138 | break; |
139 | case A_SYSCLK_DIV: | |
1cbd6fe4 PM |
140 | switch (s->sse_version) { |
141 | case ARMSSE_IOTKIT: | |
04836414 | 142 | goto bad_offset; |
1cbd6fe4 | 143 | case ARMSSE_SSE200: |
31b0c6b1 | 144 | case ARMSSE_SSE300: |
1cbd6fe4 PM |
145 | r = s->sysclk_div; |
146 | break; | |
147 | default: | |
148 | g_assert_not_reached(); | |
04836414 | 149 | } |
04836414 PM |
150 | break; |
151 | case A_CLOCK_FORCE: | |
1cbd6fe4 PM |
152 | switch (s->sse_version) { |
153 | case ARMSSE_IOTKIT: | |
04836414 | 154 | goto bad_offset; |
1cbd6fe4 | 155 | case ARMSSE_SSE200: |
31b0c6b1 | 156 | case ARMSSE_SSE300: |
1cbd6fe4 PM |
157 | r = s->clock_force; |
158 | break; | |
159 | default: | |
160 | g_assert_not_reached(); | |
04836414 | 161 | } |
04836414 | 162 | break; |
75750e4d PM |
163 | case A_RESET_SYNDROME: |
164 | r = s->reset_syndrome; | |
165 | break; | |
166 | case A_RESET_MASK: | |
167 | r = s->reset_mask; | |
168 | break; | |
169 | case A_GRETREG: | |
170 | r = s->gretreg; | |
171 | break; | |
394e10d2 PM |
172 | case A_INITSVTOR0: |
173 | r = s->initsvtor0; | |
75750e4d | 174 | break; |
04836414 | 175 | case A_INITSVTOR1: |
1cbd6fe4 PM |
176 | switch (s->sse_version) { |
177 | case ARMSSE_IOTKIT: | |
04836414 | 178 | goto bad_offset; |
1cbd6fe4 PM |
179 | case ARMSSE_SSE200: |
180 | r = s->initsvtor1; | |
181 | break; | |
246dbeb7 PM |
182 | case ARMSSE_SSE300: |
183 | goto bad_offset; | |
1cbd6fe4 PM |
184 | default: |
185 | g_assert_not_reached(); | |
04836414 | 186 | } |
04836414 | 187 | break; |
75750e4d | 188 | case A_CPUWAIT: |
92ecf2d5 PM |
189 | switch (s->sse_version) { |
190 | case ARMSSE_IOTKIT: | |
191 | case ARMSSE_SSE200: | |
192 | r = s->cpuwait; | |
193 | break; | |
194 | case ARMSSE_SSE300: | |
195 | /* In SSE300 this is reserved (for INITSVTOR2) */ | |
196 | goto bad_offset; | |
197 | default: | |
198 | g_assert_not_reached(); | |
199 | } | |
75750e4d | 200 | break; |
04836414 | 201 | case A_NMI_ENABLE: |
1cbd6fe4 PM |
202 | switch (s->sse_version) { |
203 | case ARMSSE_IOTKIT: | |
204 | /* In IoTKit this is named BUSWAIT but marked reserved, R/O, zero */ | |
04836414 PM |
205 | r = 0; |
206 | break; | |
1cbd6fe4 PM |
207 | case ARMSSE_SSE200: |
208 | r = s->nmi_enable; | |
209 | break; | |
92ecf2d5 PM |
210 | case ARMSSE_SSE300: |
211 | /* In SSE300 this is reserved (for INITSVTOR3) */ | |
212 | goto bad_offset; | |
1cbd6fe4 PM |
213 | default: |
214 | g_assert_not_reached(); | |
04836414 | 215 | } |
75750e4d PM |
216 | break; |
217 | case A_WICCTRL: | |
92ecf2d5 PM |
218 | switch (s->sse_version) { |
219 | case ARMSSE_IOTKIT: | |
220 | case ARMSSE_SSE200: | |
221 | r = s->wicctrl; | |
222 | break; | |
223 | case ARMSSE_SSE300: | |
224 | /* In SSE300 this offset is CPUWAIT */ | |
225 | r = s->cpuwait; | |
226 | break; | |
227 | default: | |
228 | g_assert_not_reached(); | |
229 | } | |
75750e4d | 230 | break; |
04836414 | 231 | case A_EWCTRL: |
1cbd6fe4 PM |
232 | switch (s->sse_version) { |
233 | case ARMSSE_IOTKIT: | |
04836414 | 234 | goto bad_offset; |
1cbd6fe4 PM |
235 | case ARMSSE_SSE200: |
236 | r = s->ewctrl; | |
237 | break; | |
92ecf2d5 | 238 | case ARMSSE_SSE300: |
7a21bee2 | 239 | /* In SSE300 this offset is NMI_ENABLE */ |
92ecf2d5 PM |
240 | r = s->nmi_enable; |
241 | break; | |
1cbd6fe4 PM |
242 | default: |
243 | g_assert_not_reached(); | |
04836414 | 244 | } |
04836414 | 245 | break; |
2672a6ca PM |
246 | case A_PWRCTRL: |
247 | switch (s->sse_version) { | |
248 | case ARMSSE_IOTKIT: | |
249 | case ARMSSE_SSE200: | |
250 | goto bad_offset; | |
251 | case ARMSSE_SSE300: | |
252 | r = s->pwrctrl; | |
253 | break; | |
254 | default: | |
255 | g_assert_not_reached(); | |
256 | } | |
257 | break; | |
04836414 | 258 | case A_PDCM_PD_SYS_SENSE: |
1cbd6fe4 PM |
259 | switch (s->sse_version) { |
260 | case ARMSSE_IOTKIT: | |
04836414 | 261 | goto bad_offset; |
1cbd6fe4 | 262 | case ARMSSE_SSE200: |
31b0c6b1 | 263 | case ARMSSE_SSE300: |
1cbd6fe4 PM |
264 | r = s->pdcm_pd_sys_sense; |
265 | break; | |
266 | default: | |
267 | g_assert_not_reached(); | |
04836414 | 268 | } |
04836414 | 269 | break; |
c5ffe6c8 PM |
270 | case A_PDCM_PD_CPU0_SENSE: |
271 | switch (s->sse_version) { | |
272 | case ARMSSE_IOTKIT: | |
273 | case ARMSSE_SSE200: | |
274 | goto bad_offset; | |
275 | case ARMSSE_SSE300: | |
276 | r = s->pdcm_pd_cpu0_sense; | |
277 | break; | |
278 | default: | |
279 | g_assert_not_reached(); | |
280 | } | |
281 | break; | |
04836414 | 282 | case A_PDCM_PD_SRAM0_SENSE: |
1cbd6fe4 PM |
283 | switch (s->sse_version) { |
284 | case ARMSSE_IOTKIT: | |
04836414 | 285 | goto bad_offset; |
1cbd6fe4 PM |
286 | case ARMSSE_SSE200: |
287 | r = s->pdcm_pd_sram0_sense; | |
288 | break; | |
c5ffe6c8 PM |
289 | case ARMSSE_SSE300: |
290 | goto bad_offset; | |
1cbd6fe4 PM |
291 | default: |
292 | g_assert_not_reached(); | |
04836414 | 293 | } |
04836414 PM |
294 | break; |
295 | case A_PDCM_PD_SRAM1_SENSE: | |
1cbd6fe4 PM |
296 | switch (s->sse_version) { |
297 | case ARMSSE_IOTKIT: | |
04836414 | 298 | goto bad_offset; |
1cbd6fe4 PM |
299 | case ARMSSE_SSE200: |
300 | r = s->pdcm_pd_sram1_sense; | |
301 | break; | |
c5ffe6c8 PM |
302 | case ARMSSE_SSE300: |
303 | goto bad_offset; | |
1cbd6fe4 PM |
304 | default: |
305 | g_assert_not_reached(); | |
04836414 | 306 | } |
04836414 PM |
307 | break; |
308 | case A_PDCM_PD_SRAM2_SENSE: | |
1cbd6fe4 PM |
309 | switch (s->sse_version) { |
310 | case ARMSSE_IOTKIT: | |
04836414 | 311 | goto bad_offset; |
1cbd6fe4 PM |
312 | case ARMSSE_SSE200: |
313 | r = s->pdcm_pd_sram2_sense; | |
314 | break; | |
c5ffe6c8 PM |
315 | case ARMSSE_SSE300: |
316 | r = s->pdcm_pd_vmr0_sense; | |
317 | break; | |
1cbd6fe4 PM |
318 | default: |
319 | g_assert_not_reached(); | |
04836414 | 320 | } |
04836414 PM |
321 | break; |
322 | case A_PDCM_PD_SRAM3_SENSE: | |
1cbd6fe4 PM |
323 | switch (s->sse_version) { |
324 | case ARMSSE_IOTKIT: | |
04836414 | 325 | goto bad_offset; |
1cbd6fe4 PM |
326 | case ARMSSE_SSE200: |
327 | r = s->pdcm_pd_sram3_sense; | |
328 | break; | |
c5ffe6c8 PM |
329 | case ARMSSE_SSE300: |
330 | r = s->pdcm_pd_vmr1_sense; | |
331 | break; | |
1cbd6fe4 PM |
332 | default: |
333 | g_assert_not_reached(); | |
04836414 | 334 | } |
04836414 | 335 | break; |
75750e4d | 336 | case A_PID4 ... A_CID3: |
6069bbc9 PM |
337 | switch (s->sse_version) { |
338 | case ARMSSE_IOTKIT: | |
339 | r = iotkit_sysctl_id[(offset - A_PID4) / 4]; | |
340 | break; | |
341 | case ARMSSE_SSE200: | |
342 | case ARMSSE_SSE300: | |
343 | r = sse200_sysctl_id[(offset - A_PID4) / 4]; | |
344 | break; | |
345 | default: | |
346 | g_assert_not_reached(); | |
347 | } | |
75750e4d PM |
348 | break; |
349 | case A_SECDBGSET: | |
350 | case A_SECDBGCLR: | |
351 | case A_SWRESET: | |
352 | qemu_log_mask(LOG_GUEST_ERROR, | |
353 | "IoTKit SysCtl read: read of WO offset %x\n", | |
354 | (int)offset); | |
355 | r = 0; | |
356 | break; | |
357 | default: | |
04836414 | 358 | bad_offset: |
75750e4d PM |
359 | qemu_log_mask(LOG_GUEST_ERROR, |
360 | "IoTKit SysCtl read: bad offset %x\n", (int)offset); | |
361 | r = 0; | |
362 | break; | |
363 | } | |
364 | trace_iotkit_sysctl_read(offset, r, size); | |
365 | return r; | |
366 | } | |
367 | ||
92ecf2d5 PM |
368 | static void cpuwait_write(IoTKitSysCtl *s, uint32_t value) |
369 | { | |
370 | int num_cpus = (s->sse_version == ARMSSE_SSE300) ? 1 : 2; | |
371 | int i; | |
372 | ||
373 | for (i = 0; i < num_cpus; i++) { | |
374 | uint32_t mask = 1 << i; | |
375 | if ((s->cpuwait & mask) && !(value & mask)) { | |
376 | /* Powering up CPU 0 */ | |
377 | arm_set_cpu_on_and_reset(i); | |
378 | } | |
379 | } | |
380 | s->cpuwait = value; | |
381 | } | |
382 | ||
75750e4d PM |
383 | static void iotkit_sysctl_write(void *opaque, hwaddr offset, |
384 | uint64_t value, unsigned size) | |
385 | { | |
386 | IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque); | |
387 | ||
388 | trace_iotkit_sysctl_write(offset, value, size); | |
389 | ||
390 | /* | |
391 | * Most of the state here has to do with control of reset and | |
392 | * similar kinds of power up -- for instance the guest can ask | |
393 | * what the reason for the last reset was, or forbid reset for | |
394 | * some causes (like the non-secure watchdog). Most of this is | |
395 | * not relevant to QEMU, which doesn't really model anything other | |
396 | * than a full power-on reset. | |
397 | * We just model the registers as reads-as-written. | |
398 | */ | |
399 | ||
400 | switch (offset) { | |
401 | case A_RESET_SYNDROME: | |
402 | qemu_log_mask(LOG_UNIMP, | |
403 | "IoTKit SysCtl RESET_SYNDROME unimplemented\n"); | |
404 | s->reset_syndrome = value; | |
405 | break; | |
406 | case A_RESET_MASK: | |
407 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl RESET_MASK unimplemented\n"); | |
408 | s->reset_mask = value; | |
409 | break; | |
410 | case A_GRETREG: | |
411 | /* | |
412 | * General retention register, which is only reset by a power-on | |
413 | * reset. Technically this implementation is complete, since | |
414 | * QEMU only supports power-on resets... | |
415 | */ | |
416 | s->gretreg = value; | |
417 | break; | |
394e10d2 | 418 | case A_INITSVTOR0: |
246dbeb7 PM |
419 | switch (s->sse_version) { |
420 | case ARMSSE_SSE300: | |
421 | /* SSE300 has a LOCK bit which prevents further writes when set */ | |
422 | if (s->initsvtor0 & R_INITSVTOR0_LOCK_MASK) { | |
423 | qemu_log_mask(LOG_GUEST_ERROR, | |
424 | "IoTKit INITSVTOR0 write when register locked\n"); | |
425 | break; | |
426 | } | |
427 | s->initsvtor0 = value; | |
428 | set_init_vtor(0, s->initsvtor0 & R_INITSVTOR0_VTOR_MASK); | |
429 | break; | |
430 | case ARMSSE_IOTKIT: | |
431 | case ARMSSE_SSE200: | |
432 | s->initsvtor0 = value; | |
433 | set_init_vtor(0, s->initsvtor0); | |
434 | break; | |
435 | default: | |
436 | g_assert_not_reached(); | |
437 | } | |
75750e4d PM |
438 | break; |
439 | case A_CPUWAIT: | |
92ecf2d5 PM |
440 | switch (s->sse_version) { |
441 | case ARMSSE_IOTKIT: | |
442 | case ARMSSE_SSE200: | |
443 | cpuwait_write(s, value); | |
444 | break; | |
445 | case ARMSSE_SSE300: | |
446 | /* In SSE300 this is reserved (for INITSVTOR2) */ | |
447 | goto bad_offset; | |
448 | default: | |
449 | g_assert_not_reached(); | |
0f862986 | 450 | } |
75750e4d PM |
451 | break; |
452 | case A_WICCTRL: | |
92ecf2d5 PM |
453 | switch (s->sse_version) { |
454 | case ARMSSE_IOTKIT: | |
455 | case ARMSSE_SSE200: | |
456 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl WICCTRL unimplemented\n"); | |
457 | s->wicctrl = value; | |
458 | break; | |
459 | case ARMSSE_SSE300: | |
460 | /* In SSE300 this offset is CPUWAIT */ | |
461 | cpuwait_write(s, value); | |
462 | break; | |
463 | default: | |
464 | g_assert_not_reached(); | |
465 | } | |
75750e4d PM |
466 | break; |
467 | case A_SECDBGSET: | |
468 | /* write-1-to-set */ | |
469 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SECDBGSET unimplemented\n"); | |
470 | s->secure_debug |= value; | |
471 | break; | |
472 | case A_SECDBGCLR: | |
473 | /* write-1-to-clear */ | |
474 | s->secure_debug &= ~value; | |
475 | break; | |
476 | case A_SWRESET: | |
477 | /* One w/o bit to request a reset; all other bits reserved */ | |
478 | if (value & R_SWRESET_SWRESETREQ_MASK) { | |
479 | qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); | |
480 | } | |
481 | break; | |
04836414 | 482 | case A_SCSECCTRL: |
1cbd6fe4 PM |
483 | switch (s->sse_version) { |
484 | case ARMSSE_IOTKIT: | |
04836414 | 485 | goto bad_offset; |
1cbd6fe4 | 486 | case ARMSSE_SSE200: |
31b0c6b1 | 487 | case ARMSSE_SSE300: |
1cbd6fe4 PM |
488 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SCSECCTRL unimplemented\n"); |
489 | s->scsecctrl = value; | |
490 | break; | |
491 | default: | |
492 | g_assert_not_reached(); | |
04836414 | 493 | } |
04836414 PM |
494 | break; |
495 | case A_FCLK_DIV: | |
1cbd6fe4 PM |
496 | switch (s->sse_version) { |
497 | case ARMSSE_IOTKIT: | |
04836414 | 498 | goto bad_offset; |
1cbd6fe4 | 499 | case ARMSSE_SSE200: |
31b0c6b1 | 500 | case ARMSSE_SSE300: |
1cbd6fe4 PM |
501 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl FCLK_DIV unimplemented\n"); |
502 | s->fclk_div = value; | |
503 | break; | |
504 | default: | |
505 | g_assert_not_reached(); | |
04836414 | 506 | } |
04836414 PM |
507 | break; |
508 | case A_SYSCLK_DIV: | |
1cbd6fe4 PM |
509 | switch (s->sse_version) { |
510 | case ARMSSE_IOTKIT: | |
04836414 | 511 | goto bad_offset; |
1cbd6fe4 | 512 | case ARMSSE_SSE200: |
31b0c6b1 | 513 | case ARMSSE_SSE300: |
1cbd6fe4 PM |
514 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SYSCLK_DIV unimplemented\n"); |
515 | s->sysclk_div = value; | |
516 | break; | |
517 | default: | |
518 | g_assert_not_reached(); | |
04836414 | 519 | } |
04836414 PM |
520 | break; |
521 | case A_CLOCK_FORCE: | |
1cbd6fe4 PM |
522 | switch (s->sse_version) { |
523 | case ARMSSE_IOTKIT: | |
04836414 | 524 | goto bad_offset; |
1cbd6fe4 | 525 | case ARMSSE_SSE200: |
31b0c6b1 | 526 | case ARMSSE_SSE300: |
1cbd6fe4 PM |
527 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl CLOCK_FORCE unimplemented\n"); |
528 | s->clock_force = value; | |
529 | break; | |
530 | default: | |
531 | g_assert_not_reached(); | |
04836414 | 532 | } |
04836414 PM |
533 | break; |
534 | case A_INITSVTOR1: | |
1cbd6fe4 PM |
535 | switch (s->sse_version) { |
536 | case ARMSSE_IOTKIT: | |
04836414 | 537 | goto bad_offset; |
1cbd6fe4 PM |
538 | case ARMSSE_SSE200: |
539 | s->initsvtor1 = value; | |
540 | set_init_vtor(1, s->initsvtor1); | |
541 | break; | |
246dbeb7 PM |
542 | case ARMSSE_SSE300: |
543 | goto bad_offset; | |
1cbd6fe4 PM |
544 | default: |
545 | g_assert_not_reached(); | |
04836414 | 546 | } |
04836414 PM |
547 | break; |
548 | case A_EWCTRL: | |
1cbd6fe4 PM |
549 | switch (s->sse_version) { |
550 | case ARMSSE_IOTKIT: | |
04836414 | 551 | goto bad_offset; |
1cbd6fe4 PM |
552 | case ARMSSE_SSE200: |
553 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl EWCTRL unimplemented\n"); | |
554 | s->ewctrl = value; | |
555 | break; | |
92ecf2d5 | 556 | case ARMSSE_SSE300: |
7a21bee2 | 557 | /* In SSE300 this offset is NMI_ENABLE */ |
92ecf2d5 PM |
558 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl NMI_ENABLE unimplemented\n"); |
559 | s->nmi_enable = value; | |
560 | break; | |
1cbd6fe4 PM |
561 | default: |
562 | g_assert_not_reached(); | |
04836414 | 563 | } |
04836414 | 564 | break; |
2672a6ca PM |
565 | case A_PWRCTRL: |
566 | switch (s->sse_version) { | |
567 | case ARMSSE_IOTKIT: | |
568 | case ARMSSE_SSE200: | |
569 | goto bad_offset; | |
570 | case ARMSSE_SSE300: | |
571 | if (!(s->pwrctrl & R_PWRCTRL_PPU_ACCESS_UNLOCK_MASK)) { | |
572 | qemu_log_mask(LOG_GUEST_ERROR, | |
573 | "IoTKit PWRCTRL write when register locked\n"); | |
574 | break; | |
575 | } | |
576 | s->pwrctrl = value; | |
577 | break; | |
578 | default: | |
579 | g_assert_not_reached(); | |
580 | } | |
581 | break; | |
04836414 | 582 | case A_PDCM_PD_SYS_SENSE: |
1cbd6fe4 PM |
583 | switch (s->sse_version) { |
584 | case ARMSSE_IOTKIT: | |
04836414 | 585 | goto bad_offset; |
1cbd6fe4 | 586 | case ARMSSE_SSE200: |
31b0c6b1 | 587 | case ARMSSE_SSE300: |
1cbd6fe4 PM |
588 | qemu_log_mask(LOG_UNIMP, |
589 | "IoTKit SysCtl PDCM_PD_SYS_SENSE unimplemented\n"); | |
590 | s->pdcm_pd_sys_sense = value; | |
591 | break; | |
592 | default: | |
593 | g_assert_not_reached(); | |
04836414 | 594 | } |
04836414 | 595 | break; |
c5ffe6c8 PM |
596 | case A_PDCM_PD_CPU0_SENSE: |
597 | switch (s->sse_version) { | |
598 | case ARMSSE_IOTKIT: | |
599 | case ARMSSE_SSE200: | |
600 | goto bad_offset; | |
601 | case ARMSSE_SSE300: | |
602 | qemu_log_mask(LOG_UNIMP, | |
603 | "IoTKit SysCtl PDCM_PD_CPU0_SENSE unimplemented\n"); | |
604 | s->pdcm_pd_cpu0_sense = value; | |
605 | break; | |
606 | default: | |
607 | g_assert_not_reached(); | |
608 | } | |
609 | break; | |
04836414 | 610 | case A_PDCM_PD_SRAM0_SENSE: |
1cbd6fe4 PM |
611 | switch (s->sse_version) { |
612 | case ARMSSE_IOTKIT: | |
04836414 | 613 | goto bad_offset; |
1cbd6fe4 PM |
614 | case ARMSSE_SSE200: |
615 | qemu_log_mask(LOG_UNIMP, | |
616 | "IoTKit SysCtl PDCM_PD_SRAM0_SENSE unimplemented\n"); | |
617 | s->pdcm_pd_sram0_sense = value; | |
618 | break; | |
c5ffe6c8 PM |
619 | case ARMSSE_SSE300: |
620 | goto bad_offset; | |
1cbd6fe4 PM |
621 | default: |
622 | g_assert_not_reached(); | |
04836414 | 623 | } |
04836414 PM |
624 | break; |
625 | case A_PDCM_PD_SRAM1_SENSE: | |
1cbd6fe4 PM |
626 | switch (s->sse_version) { |
627 | case ARMSSE_IOTKIT: | |
04836414 | 628 | goto bad_offset; |
1cbd6fe4 PM |
629 | case ARMSSE_SSE200: |
630 | qemu_log_mask(LOG_UNIMP, | |
631 | "IoTKit SysCtl PDCM_PD_SRAM1_SENSE unimplemented\n"); | |
632 | s->pdcm_pd_sram1_sense = value; | |
633 | break; | |
c5ffe6c8 PM |
634 | case ARMSSE_SSE300: |
635 | goto bad_offset; | |
1cbd6fe4 PM |
636 | default: |
637 | g_assert_not_reached(); | |
04836414 | 638 | } |
04836414 PM |
639 | break; |
640 | case A_PDCM_PD_SRAM2_SENSE: | |
1cbd6fe4 PM |
641 | switch (s->sse_version) { |
642 | case ARMSSE_IOTKIT: | |
04836414 | 643 | goto bad_offset; |
1cbd6fe4 PM |
644 | case ARMSSE_SSE200: |
645 | qemu_log_mask(LOG_UNIMP, | |
646 | "IoTKit SysCtl PDCM_PD_SRAM2_SENSE unimplemented\n"); | |
647 | s->pdcm_pd_sram2_sense = value; | |
648 | break; | |
c5ffe6c8 PM |
649 | case ARMSSE_SSE300: |
650 | qemu_log_mask(LOG_UNIMP, | |
651 | "IoTKit SysCtl PDCM_PD_VMR0_SENSE unimplemented\n"); | |
652 | s->pdcm_pd_vmr0_sense = value; | |
653 | break; | |
1cbd6fe4 PM |
654 | default: |
655 | g_assert_not_reached(); | |
04836414 | 656 | } |
04836414 PM |
657 | break; |
658 | case A_PDCM_PD_SRAM3_SENSE: | |
1cbd6fe4 PM |
659 | switch (s->sse_version) { |
660 | case ARMSSE_IOTKIT: | |
04836414 | 661 | goto bad_offset; |
1cbd6fe4 PM |
662 | case ARMSSE_SSE200: |
663 | qemu_log_mask(LOG_UNIMP, | |
664 | "IoTKit SysCtl PDCM_PD_SRAM3_SENSE unimplemented\n"); | |
665 | s->pdcm_pd_sram3_sense = value; | |
666 | break; | |
c5ffe6c8 PM |
667 | case ARMSSE_SSE300: |
668 | qemu_log_mask(LOG_UNIMP, | |
669 | "IoTKit SysCtl PDCM_PD_VMR1_SENSE unimplemented\n"); | |
670 | s->pdcm_pd_vmr1_sense = value; | |
671 | break; | |
1cbd6fe4 PM |
672 | default: |
673 | g_assert_not_reached(); | |
04836414 | 674 | } |
04836414 PM |
675 | break; |
676 | case A_NMI_ENABLE: | |
677 | /* In IoTKit this is BUSWAIT: reserved, R/O, zero */ | |
1cbd6fe4 PM |
678 | switch (s->sse_version) { |
679 | case ARMSSE_IOTKIT: | |
04836414 | 680 | goto ro_offset; |
1cbd6fe4 PM |
681 | case ARMSSE_SSE200: |
682 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl NMI_ENABLE unimplemented\n"); | |
683 | s->nmi_enable = value; | |
684 | break; | |
92ecf2d5 PM |
685 | case ARMSSE_SSE300: |
686 | /* In SSE300 this is reserved (for INITSVTOR3) */ | |
687 | goto bad_offset; | |
1cbd6fe4 PM |
688 | default: |
689 | g_assert_not_reached(); | |
04836414 | 690 | } |
04836414 | 691 | break; |
75750e4d PM |
692 | case A_SECDBGSTAT: |
693 | case A_PID4 ... A_CID3: | |
04836414 | 694 | ro_offset: |
75750e4d PM |
695 | qemu_log_mask(LOG_GUEST_ERROR, |
696 | "IoTKit SysCtl write: write of RO offset %x\n", | |
697 | (int)offset); | |
698 | break; | |
699 | default: | |
04836414 | 700 | bad_offset: |
75750e4d PM |
701 | qemu_log_mask(LOG_GUEST_ERROR, |
702 | "IoTKit SysCtl write: bad offset %x\n", (int)offset); | |
703 | break; | |
704 | } | |
705 | } | |
706 | ||
707 | static const MemoryRegionOps iotkit_sysctl_ops = { | |
708 | .read = iotkit_sysctl_read, | |
709 | .write = iotkit_sysctl_write, | |
710 | .endianness = DEVICE_LITTLE_ENDIAN, | |
711 | /* byte/halfword accesses are just zero-padded on reads and writes */ | |
712 | .impl.min_access_size = 4, | |
713 | .impl.max_access_size = 4, | |
714 | .valid.min_access_size = 1, | |
715 | .valid.max_access_size = 4, | |
716 | }; | |
717 | ||
718 | static void iotkit_sysctl_reset(DeviceState *dev) | |
719 | { | |
720 | IoTKitSysCtl *s = IOTKIT_SYSCTL(dev); | |
721 | ||
722 | trace_iotkit_sysctl_reset(); | |
723 | s->secure_debug = 0; | |
724 | s->reset_syndrome = 1; | |
725 | s->reset_mask = 0; | |
726 | s->gretreg = 0; | |
aab7a378 PM |
727 | s->initsvtor0 = s->initsvtor0_rst; |
728 | s->initsvtor1 = s->initsvtor1_rst; | |
729 | s->cpuwait = s->cpuwait_rst; | |
75750e4d | 730 | s->wicctrl = 0; |
04836414 PM |
731 | s->scsecctrl = 0; |
732 | s->fclk_div = 0; | |
733 | s->sysclk_div = 0; | |
734 | s->clock_force = 0; | |
735 | s->nmi_enable = 0; | |
736 | s->ewctrl = 0; | |
2672a6ca | 737 | s->pwrctrl = 0x3; |
04836414 PM |
738 | s->pdcm_pd_sys_sense = 0x7f; |
739 | s->pdcm_pd_sram0_sense = 0; | |
740 | s->pdcm_pd_sram1_sense = 0; | |
741 | s->pdcm_pd_sram2_sense = 0; | |
742 | s->pdcm_pd_sram3_sense = 0; | |
c5ffe6c8 PM |
743 | s->pdcm_pd_cpu0_sense = 0; |
744 | s->pdcm_pd_vmr0_sense = 0; | |
745 | s->pdcm_pd_vmr1_sense = 0; | |
75750e4d PM |
746 | } |
747 | ||
748 | static void iotkit_sysctl_init(Object *obj) | |
749 | { | |
750 | SysBusDevice *sbd = SYS_BUS_DEVICE(obj); | |
751 | IoTKitSysCtl *s = IOTKIT_SYSCTL(obj); | |
752 | ||
753 | memory_region_init_io(&s->iomem, obj, &iotkit_sysctl_ops, | |
754 | s, "iotkit-sysctl", 0x1000); | |
755 | sysbus_init_mmio(sbd, &s->iomem); | |
756 | } | |
757 | ||
04836414 PM |
758 | static void iotkit_sysctl_realize(DeviceState *dev, Error **errp) |
759 | { | |
760 | IoTKitSysCtl *s = IOTKIT_SYSCTL(dev); | |
761 | ||
419a7f80 PM |
762 | if (!armsse_version_valid(s->sse_version)) { |
763 | error_setg(errp, "invalid sse-version value %d", s->sse_version); | |
764 | return; | |
04836414 PM |
765 | } |
766 | } | |
767 | ||
2672a6ca PM |
768 | static bool sse300_needed(void *opaque) |
769 | { | |
770 | IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque); | |
771 | ||
772 | return s->sse_version == ARMSSE_SSE300; | |
773 | } | |
774 | ||
775 | static const VMStateDescription iotkit_sysctl_sse300_vmstate = { | |
776 | .name = "iotkit-sysctl/sse-300", | |
777 | .version_id = 1, | |
778 | .minimum_version_id = 1, | |
779 | .needed = sse300_needed, | |
780 | .fields = (VMStateField[]) { | |
781 | VMSTATE_UINT32(pwrctrl, IoTKitSysCtl), | |
c5ffe6c8 PM |
782 | VMSTATE_UINT32(pdcm_pd_cpu0_sense, IoTKitSysCtl), |
783 | VMSTATE_UINT32(pdcm_pd_vmr0_sense, IoTKitSysCtl), | |
784 | VMSTATE_UINT32(pdcm_pd_vmr1_sense, IoTKitSysCtl), | |
2672a6ca PM |
785 | VMSTATE_END_OF_LIST() |
786 | } | |
787 | }; | |
788 | ||
04836414 PM |
789 | static bool sse200_needed(void *opaque) |
790 | { | |
791 | IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque); | |
792 | ||
31b0c6b1 | 793 | return s->sse_version != ARMSSE_IOTKIT; |
04836414 PM |
794 | } |
795 | ||
796 | static const VMStateDescription iotkit_sysctl_sse200_vmstate = { | |
797 | .name = "iotkit-sysctl/sse-200", | |
798 | .version_id = 1, | |
799 | .minimum_version_id = 1, | |
800 | .needed = sse200_needed, | |
801 | .fields = (VMStateField[]) { | |
802 | VMSTATE_UINT32(scsecctrl, IoTKitSysCtl), | |
803 | VMSTATE_UINT32(fclk_div, IoTKitSysCtl), | |
804 | VMSTATE_UINT32(sysclk_div, IoTKitSysCtl), | |
805 | VMSTATE_UINT32(clock_force, IoTKitSysCtl), | |
806 | VMSTATE_UINT32(initsvtor1, IoTKitSysCtl), | |
807 | VMSTATE_UINT32(nmi_enable, IoTKitSysCtl), | |
808 | VMSTATE_UINT32(pdcm_pd_sys_sense, IoTKitSysCtl), | |
809 | VMSTATE_UINT32(pdcm_pd_sram0_sense, IoTKitSysCtl), | |
810 | VMSTATE_UINT32(pdcm_pd_sram1_sense, IoTKitSysCtl), | |
811 | VMSTATE_UINT32(pdcm_pd_sram2_sense, IoTKitSysCtl), | |
812 | VMSTATE_UINT32(pdcm_pd_sram3_sense, IoTKitSysCtl), | |
813 | VMSTATE_END_OF_LIST() | |
814 | } | |
815 | }; | |
816 | ||
75750e4d PM |
817 | static const VMStateDescription iotkit_sysctl_vmstate = { |
818 | .name = "iotkit-sysctl", | |
819 | .version_id = 1, | |
820 | .minimum_version_id = 1, | |
821 | .fields = (VMStateField[]) { | |
822 | VMSTATE_UINT32(secure_debug, IoTKitSysCtl), | |
823 | VMSTATE_UINT32(reset_syndrome, IoTKitSysCtl), | |
824 | VMSTATE_UINT32(reset_mask, IoTKitSysCtl), | |
825 | VMSTATE_UINT32(gretreg, IoTKitSysCtl), | |
394e10d2 | 826 | VMSTATE_UINT32(initsvtor0, IoTKitSysCtl), |
75750e4d PM |
827 | VMSTATE_UINT32(cpuwait, IoTKitSysCtl), |
828 | VMSTATE_UINT32(wicctrl, IoTKitSysCtl), | |
829 | VMSTATE_END_OF_LIST() | |
04836414 PM |
830 | }, |
831 | .subsections = (const VMStateDescription*[]) { | |
832 | &iotkit_sysctl_sse200_vmstate, | |
2672a6ca | 833 | &iotkit_sysctl_sse300_vmstate, |
04836414 | 834 | NULL |
75750e4d PM |
835 | } |
836 | }; | |
837 | ||
04836414 | 838 | static Property iotkit_sysctl_props[] = { |
419a7f80 | 839 | DEFINE_PROP_UINT32("sse-version", IoTKitSysCtl, sse_version, 0), |
aab7a378 PM |
840 | DEFINE_PROP_UINT32("CPUWAIT_RST", IoTKitSysCtl, cpuwait_rst, 0), |
841 | DEFINE_PROP_UINT32("INITSVTOR0_RST", IoTKitSysCtl, initsvtor0_rst, | |
842 | 0x10000000), | |
843 | DEFINE_PROP_UINT32("INITSVTOR1_RST", IoTKitSysCtl, initsvtor1_rst, | |
844 | 0x10000000), | |
04836414 PM |
845 | DEFINE_PROP_END_OF_LIST() |
846 | }; | |
847 | ||
75750e4d PM |
848 | static void iotkit_sysctl_class_init(ObjectClass *klass, void *data) |
849 | { | |
850 | DeviceClass *dc = DEVICE_CLASS(klass); | |
851 | ||
852 | dc->vmsd = &iotkit_sysctl_vmstate; | |
853 | dc->reset = iotkit_sysctl_reset; | |
4f67d30b | 854 | device_class_set_props(dc, iotkit_sysctl_props); |
04836414 | 855 | dc->realize = iotkit_sysctl_realize; |
75750e4d PM |
856 | } |
857 | ||
858 | static const TypeInfo iotkit_sysctl_info = { | |
859 | .name = TYPE_IOTKIT_SYSCTL, | |
860 | .parent = TYPE_SYS_BUS_DEVICE, | |
861 | .instance_size = sizeof(IoTKitSysCtl), | |
862 | .instance_init = iotkit_sysctl_init, | |
863 | .class_init = iotkit_sysctl_class_init, | |
864 | }; | |
865 | ||
866 | static void iotkit_sysctl_register_types(void) | |
867 | { | |
868 | type_register_static(&iotkit_sysctl_info); | |
869 | } | |
870 | ||
871 | type_init(iotkit_sysctl_register_types); |