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