]> git.ipfire.org Git - thirdparty/qemu.git/blame - hw/misc/arm_sysctl.c
Include hw/hw.h exactly where needed
[thirdparty/qemu.git] / hw / misc / arm_sysctl.c
CommitLineData
5fafdf24 1/*
e69954b9
PB
2 * Status and system control registers for ARM RealView/Versatile boards.
3 *
9ee6e8bb 4 * Copyright (c) 2006-2007 CodeSourcery.
e69954b9
PB
5 * Written by Paul Brook
6 *
8e31bf38 7 * This code is licensed under the GPL.
e69954b9
PB
8 */
9
0d1c9782 10#include "qemu/osdep.h"
64552b6b 11#include "hw/irq.h"
1de7afc9 12#include "qemu/timer.h"
71538323 13#include "qemu/bitops.h"
83c9f4ca 14#include "hw/sysbus.h"
d6454270 15#include "migration/vmstate.h"
0d09e41a 16#include "hw/arm/primecell.h"
9c17d615 17#include "sysemu/sysemu.h"
03dd024f 18#include "qemu/log.h"
0b8fa32f 19#include "qemu/module.h"
e69954b9
PB
20
21#define LOCK_VALUE 0xa05f
22
ba4ea5bd
AF
23#define TYPE_ARM_SYSCTL "realview_sysctl"
24#define ARM_SYSCTL(obj) \
25 OBJECT_CHECK(arm_sysctl_state, (obj), TYPE_ARM_SYSCTL)
26
e69954b9 27typedef struct {
ba4ea5bd
AF
28 SysBusDevice parent_obj;
29
460d7c53 30 MemoryRegion iomem;
242ea2c6
PM
31 qemu_irq pl110_mux_ctrl;
32
e69954b9
PB
33 uint32_t sys_id;
34 uint32_t leds;
35 uint16_t lockval;
36 uint32_t cfgdata1;
37 uint32_t cfgdata2;
38 uint32_t flags;
39 uint32_t nvflags;
40 uint32_t resetlevel;
26e92f65 41 uint32_t proc_id;
b50ff6f5 42 uint32_t sys_mci;
34933c8c
PM
43 uint32_t sys_cfgdata;
44 uint32_t sys_cfgctrl;
45 uint32_t sys_cfgstat;
242ea2c6 46 uint32_t sys_clcd;
1f81f94b
PM
47 uint32_t mb_clock[6];
48 uint32_t *db_clock;
8bd4824a
PM
49 uint32_t db_num_vsensors;
50 uint32_t *db_voltage;
1f81f94b
PM
51 uint32_t db_num_clocks;
52 uint32_t *db_clock_reset;
e69954b9
PB
53} arm_sysctl_state;
54
b5ad0ae7
PM
55static const VMStateDescription vmstate_arm_sysctl = {
56 .name = "realview_sysctl",
1f81f94b 57 .version_id = 4,
b5ad0ae7
PM
58 .minimum_version_id = 1,
59 .fields = (VMStateField[]) {
60 VMSTATE_UINT32(leds, arm_sysctl_state),
61 VMSTATE_UINT16(lockval, arm_sysctl_state),
62 VMSTATE_UINT32(cfgdata1, arm_sysctl_state),
63 VMSTATE_UINT32(cfgdata2, arm_sysctl_state),
64 VMSTATE_UINT32(flags, arm_sysctl_state),
65 VMSTATE_UINT32(nvflags, arm_sysctl_state),
66 VMSTATE_UINT32(resetlevel, arm_sysctl_state),
34933c8c
PM
67 VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2),
68 VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2),
69 VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2),
70 VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2),
242ea2c6 71 VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3),
1f81f94b
PM
72 VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4),
73 VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks,
74 4, vmstate_info_uint32, uint32_t),
b5ad0ae7
PM
75 VMSTATE_END_OF_LIST()
76 }
77};
78
b50ff6f5
PM
79/* The PB926 actually uses a different format for
80 * its SYS_ID register. Fortunately the bits which are
81 * board type on later boards are distinct.
82 */
83#define BOARD_ID_PB926 0x100
84#define BOARD_ID_EB 0x140
85#define BOARD_ID_PBA8 0x178
86#define BOARD_ID_PBX 0x182
34933c8c 87#define BOARD_ID_VEXPRESS 0x190
b50ff6f5
PM
88
89static int board_id(arm_sysctl_state *s)
90{
91 /* Extract the board ID field from the SYS_ID register value */
92 return (s->sys_id >> 16) & 0xfff;
93}
94
be0f204a
PB
95static void arm_sysctl_reset(DeviceState *d)
96{
ba4ea5bd 97 arm_sysctl_state *s = ARM_SYSCTL(d);
1f81f94b 98 int i;
be0f204a
PB
99
100 s->leds = 0;
101 s->lockval = 0;
102 s->cfgdata1 = 0;
103 s->cfgdata2 = 0;
104 s->flags = 0;
105 s->resetlevel = 0;
1f81f94b
PM
106 /* Motherboard oscillators (in Hz) */
107 s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */
108 s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */
109 s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */
110 s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */
111 s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */
112 s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */
113 /* Daughterboard oscillators: reset from property values */
114 for (i = 0; i < s->db_num_clocks; i++) {
115 s->db_clock[i] = s->db_clock_reset[i];
116 }
242ea2c6
PM
117 if (board_id(s) == BOARD_ID_VEXPRESS) {
118 /* On VExpress this register will RAZ/WI */
119 s->sys_clcd = 0;
120 } else {
121 /* All others: CLCDID 0x1f, indicating VGA */
122 s->sys_clcd = 0x1f00;
123 }
be0f204a
PB
124}
125
a8170e5e 126static uint64_t arm_sysctl_read(void *opaque, hwaddr offset,
460d7c53 127 unsigned size)
e69954b9
PB
128{
129 arm_sysctl_state *s = (arm_sysctl_state *)opaque;
130
e69954b9
PB
131 switch (offset) {
132 case 0x00: /* ID */
133 return s->sys_id;
134 case 0x04: /* SW */
135 /* General purpose hardware switches.
136 We don't have a useful way of exposing these to the user. */
137 return 0;
138 case 0x08: /* LED */
139 return s->leds;
140 case 0x20: /* LOCK */
141 return s->lockval;
142 case 0x0c: /* OSC0 */
143 case 0x10: /* OSC1 */
144 case 0x14: /* OSC2 */
145 case 0x18: /* OSC3 */
146 case 0x1c: /* OSC4 */
147 case 0x24: /* 100HZ */
148 /* ??? Implement these. */
149 return 0;
150 case 0x28: /* CFGDATA1 */
151 return s->cfgdata1;
152 case 0x2c: /* CFGDATA2 */
153 return s->cfgdata2;
154 case 0x30: /* FLAGS */
155 return s->flags;
156 case 0x38: /* NVFLAGS */
157 return s->nvflags;
158 case 0x40: /* RESETCTL */
34933c8c
PM
159 if (board_id(s) == BOARD_ID_VEXPRESS) {
160 /* reserved: RAZ/WI */
161 return 0;
162 }
e69954b9
PB
163 return s->resetlevel;
164 case 0x44: /* PCICTL */
165 return 1;
166 case 0x48: /* MCI */
b50ff6f5 167 return s->sys_mci;
e69954b9
PB
168 case 0x4c: /* FLASH */
169 return 0;
170 case 0x50: /* CLCD */
242ea2c6 171 return s->sys_clcd;
e69954b9
PB
172 case 0x54: /* CLCDSER */
173 return 0;
174 case 0x58: /* BOOTCS */
175 return 0;
176 case 0x5c: /* 24MHz */
73bcb24d
RS
177 return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24000000,
178 NANOSECONDS_PER_SECOND);
e69954b9
PB
179 case 0x60: /* MISC */
180 return 0;
181 case 0x84: /* PROCID0 */
26e92f65 182 return s->proc_id;
e69954b9
PB
183 case 0x88: /* PROCID1 */
184 return 0xff000000;
185 case 0x64: /* DMAPSR0 */
186 case 0x68: /* DMAPSR1 */
187 case 0x6c: /* DMAPSR2 */
188 case 0x70: /* IOSEL */
189 case 0x74: /* PLDCTL */
190 case 0x80: /* BUSID */
191 case 0x8c: /* OSCRESET0 */
192 case 0x90: /* OSCRESET1 */
193 case 0x94: /* OSCRESET2 */
194 case 0x98: /* OSCRESET3 */
195 case 0x9c: /* OSCRESET4 */
196 case 0xc0: /* SYS_TEST_OSC0 */
197 case 0xc4: /* SYS_TEST_OSC1 */
198 case 0xc8: /* SYS_TEST_OSC2 */
199 case 0xcc: /* SYS_TEST_OSC3 */
200 case 0xd0: /* SYS_TEST_OSC4 */
201 return 0;
34933c8c
PM
202 case 0xa0: /* SYS_CFGDATA */
203 if (board_id(s) != BOARD_ID_VEXPRESS) {
204 goto bad_reg;
205 }
206 return s->sys_cfgdata;
207 case 0xa4: /* SYS_CFGCTRL */
208 if (board_id(s) != BOARD_ID_VEXPRESS) {
209 goto bad_reg;
210 }
211 return s->sys_cfgctrl;
212 case 0xa8: /* SYS_CFGSTAT */
213 if (board_id(s) != BOARD_ID_VEXPRESS) {
214 goto bad_reg;
215 }
216 return s->sys_cfgstat;
e69954b9 217 default:
34933c8c 218 bad_reg:
0c896f06
PM
219 qemu_log_mask(LOG_GUEST_ERROR,
220 "arm_sysctl_read: Bad register offset 0x%x\n",
221 (int)offset);
e69954b9
PB
222 return 0;
223 }
224}
225
71538323
PM
226/* SYS_CFGCTRL functions */
227#define SYS_CFG_OSC 1
228#define SYS_CFG_VOLT 2
229#define SYS_CFG_AMP 3
230#define SYS_CFG_TEMP 4
231#define SYS_CFG_RESET 5
232#define SYS_CFG_SCC 6
233#define SYS_CFG_MUXFPGA 7
234#define SYS_CFG_SHUTDOWN 8
235#define SYS_CFG_REBOOT 9
236#define SYS_CFG_DVIMODE 11
237#define SYS_CFG_POWER 12
238#define SYS_CFG_ENERGY 13
239
240/* SYS_CFGCTRL site field values */
241#define SYS_CFG_SITE_MB 0
242#define SYS_CFG_SITE_DB1 1
243#define SYS_CFG_SITE_DB2 2
244
245/**
246 * vexpress_cfgctrl_read:
247 * @s: arm_sysctl_state pointer
248 * @dcc, @function, @site, @position, @device: split out values from
249 * SYS_CFGCTRL register
250 * @val: pointer to where to put the read data on success
251 *
252 * Handle a VExpress SYS_CFGCTRL register read. On success, return true and
253 * write the read value to *val. On failure, return false (and val may
254 * or may not be written to).
255 */
256static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
257 unsigned int function, unsigned int site,
258 unsigned int position, unsigned int device,
259 uint32_t *val)
260{
261 /* We don't support anything other than DCC 0, board stack position 0
262 * or sites other than motherboard/daughterboard:
263 */
264 if (dcc != 0 || position != 0 ||
265 (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
266 goto cfgctrl_unimp;
267 }
268
269 switch (function) {
8bd4824a
PM
270 case SYS_CFG_VOLT:
271 if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) {
272 *val = s->db_voltage[device];
273 return true;
274 }
275 if (site == SYS_CFG_SITE_MB && device == 0) {
276 /* There is only one motherboard voltage sensor:
277 * VIO : 3.3V : bus voltage between mother and daughterboard
278 */
279 *val = 3300000;
280 return true;
281 }
282 break;
1f81f94b 283 case SYS_CFG_OSC:
ec1efab9 284 if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
1f81f94b
PM
285 /* motherboard clock */
286 *val = s->mb_clock[device];
287 return true;
288 }
289 if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {
290 /* daughterboard clock */
291 *val = s->db_clock[device];
292 return true;
293 }
294 break;
71538323
PM
295 default:
296 break;
297 }
298
299cfgctrl_unimp:
300 qemu_log_mask(LOG_UNIMP,
301 "arm_sysctl: Unimplemented SYS_CFGCTRL read of function "
302 "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
303 function, dcc, site, position, device);
304 return false;
305}
306
307/**
308 * vexpress_cfgctrl_write:
309 * @s: arm_sysctl_state pointer
310 * @dcc, @function, @site, @position, @device: split out values from
311 * SYS_CFGCTRL register
312 * @val: data to write
313 *
314 * Handle a VExpress SYS_CFGCTRL register write. On success, return true.
315 * On failure, return false.
316 */
317static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
318 unsigned int function, unsigned int site,
319 unsigned int position, unsigned int device,
320 uint32_t val)
321{
322 /* We don't support anything other than DCC 0, board stack position 0
323 * or sites other than motherboard/daughterboard:
324 */
325 if (dcc != 0 || position != 0 ||
326 (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
327 goto cfgctrl_unimp;
328 }
329
330 switch (function) {
1f81f94b 331 case SYS_CFG_OSC:
ec1efab9 332 if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
1f81f94b
PM
333 /* motherboard clock */
334 s->mb_clock[device] = val;
335 return true;
336 }
337 if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {
338 /* daughterboard clock */
339 s->db_clock[device] = val;
340 return true;
341 }
342 break;
8ff05c98
PM
343 case SYS_CFG_MUXFPGA:
344 if (site == SYS_CFG_SITE_MB && device == 0) {
345 /* Select whether video output comes from motherboard
346 * or daughterboard: log and ignore as QEMU doesn't
347 * support this.
348 */
349 qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output "
350 "not supported, ignoring\n");
351 return true;
352 }
353 break;
71538323
PM
354 case SYS_CFG_SHUTDOWN:
355 if (site == SYS_CFG_SITE_MB && device == 0) {
cf83f140 356 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
71538323
PM
357 return true;
358 }
359 break;
360 case SYS_CFG_REBOOT:
361 if (site == SYS_CFG_SITE_MB && device == 0) {
cf83f140 362 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
71538323
PM
363 return true;
364 }
365 break;
291155cb
PM
366 case SYS_CFG_DVIMODE:
367 if (site == SYS_CFG_SITE_MB && device == 0) {
368 /* Selecting DVI mode is meaningless for QEMU: we will
369 * always display the output correctly according to the
370 * pixel height/width programmed into the CLCD controller.
371 */
372 return true;
373 }
71538323
PM
374 default:
375 break;
376 }
377
378cfgctrl_unimp:
379 qemu_log_mask(LOG_UNIMP,
380 "arm_sysctl: Unimplemented SYS_CFGCTRL write of function "
381 "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
382 function, dcc, site, position, device);
383 return false;
384}
385
a8170e5e 386static void arm_sysctl_write(void *opaque, hwaddr offset,
460d7c53 387 uint64_t val, unsigned size)
e69954b9
PB
388{
389 arm_sysctl_state *s = (arm_sysctl_state *)opaque;
e69954b9
PB
390
391 switch (offset) {
392 case 0x08: /* LED */
393 s->leds = val;
bf4229d3 394 break;
e69954b9
PB
395 case 0x0c: /* OSC0 */
396 case 0x10: /* OSC1 */
397 case 0x14: /* OSC2 */
398 case 0x18: /* OSC3 */
399 case 0x1c: /* OSC4 */
400 /* ??? */
401 break;
402 case 0x20: /* LOCK */
403 if (val == LOCK_VALUE)
404 s->lockval = val;
405 else
406 s->lockval = val & 0x7fff;
407 break;
408 case 0x28: /* CFGDATA1 */
409 /* ??? Need to implement this. */
410 s->cfgdata1 = val;
411 break;
412 case 0x2c: /* CFGDATA2 */
413 /* ??? Need to implement this. */
414 s->cfgdata2 = val;
415 break;
416 case 0x30: /* FLAGSSET */
417 s->flags |= val;
418 break;
419 case 0x34: /* FLAGSCLR */
420 s->flags &= ~val;
421 break;
422 case 0x38: /* NVFLAGSSET */
423 s->nvflags |= val;
424 break;
425 case 0x3c: /* NVFLAGSCLR */
426 s->nvflags &= ~val;
427 break;
428 case 0x40: /* RESETCTL */
b2887c43
JCD
429 switch (board_id(s)) {
430 case BOARD_ID_PB926:
431 if (s->lockval == LOCK_VALUE) {
432 s->resetlevel = val;
433 if (val & 0x100) {
cf83f140 434 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
b2887c43
JCD
435 }
436 }
437 break;
438 case BOARD_ID_PBX:
439 case BOARD_ID_PBA8:
440 if (s->lockval == LOCK_VALUE) {
441 s->resetlevel = val;
442 if (val & 0x04) {
cf83f140 443 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
b2887c43
JCD
444 }
445 }
446 break;
447 case BOARD_ID_VEXPRESS:
448 case BOARD_ID_EB:
449 default:
34933c8c
PM
450 /* reserved: RAZ/WI */
451 break;
452 }
e69954b9
PB
453 break;
454 case 0x44: /* PCICTL */
455 /* nothing to do. */
456 break;
457 case 0x4c: /* FLASH */
242ea2c6 458 break;
e69954b9 459 case 0x50: /* CLCD */
242ea2c6
PM
460 switch (board_id(s)) {
461 case BOARD_ID_PB926:
462 /* On 926 bits 13:8 are R/O, bits 1:0 control
463 * the mux that defines how to interpret the PL110
464 * graphics format, and other bits are r/w but we
465 * don't implement them to do anything.
466 */
467 s->sys_clcd &= 0x3f00;
468 s->sys_clcd |= val & ~0x3f00;
469 qemu_set_irq(s->pl110_mux_ctrl, val & 3);
470 break;
471 case BOARD_ID_EB:
472 /* The EB is the same except that there is no mux since
473 * the EB has a PL111.
474 */
475 s->sys_clcd &= 0x3f00;
476 s->sys_clcd |= val & ~0x3f00;
477 break;
478 case BOARD_ID_PBA8:
479 case BOARD_ID_PBX:
480 /* On PBA8 and PBX bit 7 is r/w and all other bits
481 * are either r/o or RAZ/WI.
482 */
483 s->sys_clcd &= (1 << 7);
484 s->sys_clcd |= val & ~(1 << 7);
485 break;
486 case BOARD_ID_VEXPRESS:
487 default:
488 /* On VExpress this register is unimplemented and will RAZ/WI */
489 break;
490 }
bf4229d3 491 break;
e69954b9
PB
492 case 0x54: /* CLCDSER */
493 case 0x64: /* DMAPSR0 */
494 case 0x68: /* DMAPSR1 */
495 case 0x6c: /* DMAPSR2 */
496 case 0x70: /* IOSEL */
497 case 0x74: /* PLDCTL */
498 case 0x80: /* BUSID */
499 case 0x84: /* PROCID0 */
500 case 0x88: /* PROCID1 */
501 case 0x8c: /* OSCRESET0 */
502 case 0x90: /* OSCRESET1 */
503 case 0x94: /* OSCRESET2 */
504 case 0x98: /* OSCRESET3 */
505 case 0x9c: /* OSCRESET4 */
506 break;
34933c8c
PM
507 case 0xa0: /* SYS_CFGDATA */
508 if (board_id(s) != BOARD_ID_VEXPRESS) {
509 goto bad_reg;
510 }
511 s->sys_cfgdata = val;
512 return;
513 case 0xa4: /* SYS_CFGCTRL */
514 if (board_id(s) != BOARD_ID_VEXPRESS) {
515 goto bad_reg;
516 }
71538323
PM
517 /* Undefined bits [19:18] are RAZ/WI, and writing to
518 * the start bit just triggers the action; it always reads
519 * as zero.
520 */
521 s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31));
522 if (val & (1 << 31)) {
523 /* Start bit set -- actually do something */
524 unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4);
525 unsigned int function = extract32(s->sys_cfgctrl, 20, 6);
526 unsigned int site = extract32(s->sys_cfgctrl, 16, 2);
527 unsigned int position = extract32(s->sys_cfgctrl, 12, 4);
528 unsigned int device = extract32(s->sys_cfgctrl, 0, 12);
529 s->sys_cfgstat = 1; /* complete */
530 if (s->sys_cfgctrl & (1 << 30)) {
531 if (!vexpress_cfgctrl_write(s, dcc, function, site, position,
532 device, s->sys_cfgdata)) {
533 s->sys_cfgstat |= 2; /* error */
534 }
535 } else {
536 uint32_t val;
537 if (!vexpress_cfgctrl_read(s, dcc, function, site, position,
538 device, &val)) {
539 s->sys_cfgstat |= 2; /* error */
540 } else {
541 s->sys_cfgdata = val;
542 }
543 }
34933c8c 544 }
706872a5 545 s->sys_cfgctrl &= ~(1 << 31);
34933c8c
PM
546 return;
547 case 0xa8: /* SYS_CFGSTAT */
548 if (board_id(s) != BOARD_ID_VEXPRESS) {
549 goto bad_reg;
550 }
551 s->sys_cfgstat = val & 3;
552 return;
e69954b9 553 default:
34933c8c 554 bad_reg:
0c896f06
PM
555 qemu_log_mask(LOG_GUEST_ERROR,
556 "arm_sysctl_write: Bad register offset 0x%x\n",
557 (int)offset);
e69954b9
PB
558 return;
559 }
560}
561
460d7c53
AK
562static const MemoryRegionOps arm_sysctl_ops = {
563 .read = arm_sysctl_read,
564 .write = arm_sysctl_write,
565 .endianness = DEVICE_NATIVE_ENDIAN,
e69954b9
PB
566};
567
b50ff6f5
PM
568static void arm_sysctl_gpio_set(void *opaque, int line, int level)
569{
570 arm_sysctl_state *s = (arm_sysctl_state *)opaque;
571 switch (line) {
572 case ARM_SYSCTL_GPIO_MMC_WPROT:
573 {
574 /* For PB926 and EB write-protect is bit 2 of SYS_MCI;
575 * for all later boards it is bit 1.
576 */
577 int bit = 2;
578 if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) {
579 bit = 4;
580 }
581 s->sys_mci &= ~bit;
582 if (level) {
583 s->sys_mci |= bit;
584 }
585 break;
586 }
587 case ARM_SYSCTL_GPIO_MMC_CARDIN:
588 s->sys_mci &= ~1;
589 if (level) {
590 s->sys_mci |= 1;
591 }
592 break;
593 }
594}
595
1f56f50a 596static void arm_sysctl_init(Object *obj)
e69954b9 597{
1f56f50a
PM
598 DeviceState *dev = DEVICE(obj);
599 SysBusDevice *sd = SYS_BUS_DEVICE(obj);
ba4ea5bd 600 arm_sysctl_state *s = ARM_SYSCTL(obj);
e69954b9 601
3c161542
PB
602 memory_region_init_io(&s->iomem, OBJECT(dev), &arm_sysctl_ops, s,
603 "arm-sysctl", 0x1000);
1f56f50a
PM
604 sysbus_init_mmio(sd, &s->iomem);
605 qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2);
606 qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1);
e69954b9 607}
82634c2d 608
1f81f94b
PM
609static void arm_sysctl_realize(DeviceState *d, Error **errp)
610{
ba4ea5bd
AF
611 arm_sysctl_state *s = ARM_SYSCTL(d);
612
1f81f94b
PM
613 s->db_clock = g_new0(uint32_t, s->db_num_clocks);
614}
615
8bd4824a
PM
616static void arm_sysctl_finalize(Object *obj)
617{
ba4ea5bd
AF
618 arm_sysctl_state *s = ARM_SYSCTL(obj);
619
8bd4824a 620 g_free(s->db_voltage);
1f81f94b
PM
621 g_free(s->db_clock);
622 g_free(s->db_clock_reset);
8bd4824a
PM
623}
624
999e12bb
AL
625static Property arm_sysctl_properties[] = {
626 DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
627 DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
8bd4824a
PM
628 /* Daughterboard power supply voltages (as reported via SYS_CFG) */
629 DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors,
630 db_voltage, qdev_prop_uint32, uint32_t),
1f81f94b
PM
631 /* Daughterboard clock reset values (as reported via SYS_CFG) */
632 DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks,
633 db_clock_reset, qdev_prop_uint32, uint32_t),
999e12bb
AL
634 DEFINE_PROP_END_OF_LIST(),
635};
636
637static void arm_sysctl_class_init(ObjectClass *klass, void *data)
638{
39bffca2 639 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb 640
1f81f94b 641 dc->realize = arm_sysctl_realize;
39bffca2
AL
642 dc->reset = arm_sysctl_reset;
643 dc->vmsd = &vmstate_arm_sysctl;
644 dc->props = arm_sysctl_properties;
999e12bb
AL
645}
646
8c43a6f0 647static const TypeInfo arm_sysctl_info = {
ba4ea5bd 648 .name = TYPE_ARM_SYSCTL,
39bffca2
AL
649 .parent = TYPE_SYS_BUS_DEVICE,
650 .instance_size = sizeof(arm_sysctl_state),
1f56f50a 651 .instance_init = arm_sysctl_init,
8bd4824a 652 .instance_finalize = arm_sysctl_finalize,
39bffca2 653 .class_init = arm_sysctl_class_init,
ee6847d1
GH
654};
655
83f7d43a 656static void arm_sysctl_register_types(void)
82634c2d 657{
39bffca2 658 type_register_static(&arm_sysctl_info);
82634c2d
PB
659}
660
83f7d43a 661type_init(arm_sysctl_register_types)