]>
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 | |
15 | * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html | |
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" |
75750e4d PM |
23 | #include "trace.h" |
24 | #include "qapi/error.h" | |
25 | #include "sysemu/sysemu.h" | |
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" |
0f862986 PM |
31 | #include "target/arm/arm-powerctl.h" |
32 | #include "target/arm/cpu.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) |
04836414 | 47 | REG32(INITSVTOR1, 0x114) |
75750e4d | 48 | REG32(CPUWAIT, 0x118) |
04836414 | 49 | REG32(NMI_ENABLE, 0x11c) /* BUSWAIT in IoTKit */ |
75750e4d | 50 | REG32(WICCTRL, 0x120) |
04836414 PM |
51 | REG32(EWCTRL, 0x124) |
52 | REG32(PDCM_PD_SYS_SENSE, 0x200) | |
53 | REG32(PDCM_PD_SRAM0_SENSE, 0x20c) | |
54 | REG32(PDCM_PD_SRAM1_SENSE, 0x210) | |
55 | REG32(PDCM_PD_SRAM2_SENSE, 0x214) | |
56 | REG32(PDCM_PD_SRAM3_SENSE, 0x218) | |
75750e4d PM |
57 | REG32(PID4, 0xfd0) |
58 | REG32(PID5, 0xfd4) | |
59 | REG32(PID6, 0xfd8) | |
60 | REG32(PID7, 0xfdc) | |
61 | REG32(PID0, 0xfe0) | |
62 | REG32(PID1, 0xfe4) | |
63 | REG32(PID2, 0xfe8) | |
64 | REG32(PID3, 0xfec) | |
65 | REG32(CID0, 0xff0) | |
66 | REG32(CID1, 0xff4) | |
67 | REG32(CID2, 0xff8) | |
68 | REG32(CID3, 0xffc) | |
69 | ||
70 | /* PID/CID values */ | |
71 | static const int sysctl_id[] = { | |
72 | 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */ | |
73 | 0x54, 0xb8, 0x0b, 0x00, /* PID0..PID3 */ | |
74 | 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */ | |
75 | }; | |
76 | ||
0f862986 PM |
77 | /* |
78 | * Set the initial secure vector table offset address for the core. | |
79 | * This will take effect when the CPU next resets. | |
80 | */ | |
81 | static void set_init_vtor(uint64_t cpuid, uint32_t vtor) | |
82 | { | |
83 | Object *cpuobj = OBJECT(arm_get_cpu_by_id(cpuid)); | |
84 | ||
85 | if (cpuobj) { | |
86 | if (object_property_find(cpuobj, "init-svtor", NULL)) { | |
87 | object_property_set_uint(cpuobj, vtor, "init-svtor", &error_abort); | |
88 | } | |
89 | } | |
90 | } | |
91 | ||
75750e4d PM |
92 | static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset, |
93 | unsigned size) | |
94 | { | |
95 | IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque); | |
96 | uint64_t r; | |
97 | ||
98 | switch (offset) { | |
99 | case A_SECDBGSTAT: | |
100 | r = s->secure_debug; | |
101 | break; | |
04836414 PM |
102 | case A_SCSECCTRL: |
103 | if (!s->is_sse200) { | |
104 | goto bad_offset; | |
105 | } | |
106 | r = s->scsecctrl; | |
107 | break; | |
108 | case A_FCLK_DIV: | |
109 | if (!s->is_sse200) { | |
110 | goto bad_offset; | |
111 | } | |
112 | r = s->fclk_div; | |
113 | break; | |
114 | case A_SYSCLK_DIV: | |
115 | if (!s->is_sse200) { | |
116 | goto bad_offset; | |
117 | } | |
118 | r = s->sysclk_div; | |
119 | break; | |
120 | case A_CLOCK_FORCE: | |
121 | if (!s->is_sse200) { | |
122 | goto bad_offset; | |
123 | } | |
124 | r = s->clock_force; | |
125 | break; | |
75750e4d PM |
126 | case A_RESET_SYNDROME: |
127 | r = s->reset_syndrome; | |
128 | break; | |
129 | case A_RESET_MASK: | |
130 | r = s->reset_mask; | |
131 | break; | |
132 | case A_GRETREG: | |
133 | r = s->gretreg; | |
134 | break; | |
394e10d2 PM |
135 | case A_INITSVTOR0: |
136 | r = s->initsvtor0; | |
75750e4d | 137 | break; |
04836414 PM |
138 | case A_INITSVTOR1: |
139 | if (!s->is_sse200) { | |
140 | goto bad_offset; | |
141 | } | |
142 | r = s->initsvtor1; | |
143 | break; | |
75750e4d PM |
144 | case A_CPUWAIT: |
145 | r = s->cpuwait; | |
146 | break; | |
04836414 PM |
147 | case A_NMI_ENABLE: |
148 | /* In IoTKit this is named BUSWAIT but is marked reserved, R/O, zero */ | |
149 | if (!s->is_sse200) { | |
150 | r = 0; | |
151 | break; | |
152 | } | |
153 | r = s->nmi_enable; | |
75750e4d PM |
154 | break; |
155 | case A_WICCTRL: | |
156 | r = s->wicctrl; | |
157 | break; | |
04836414 PM |
158 | case A_EWCTRL: |
159 | if (!s->is_sse200) { | |
160 | goto bad_offset; | |
161 | } | |
162 | r = s->ewctrl; | |
163 | break; | |
164 | case A_PDCM_PD_SYS_SENSE: | |
165 | if (!s->is_sse200) { | |
166 | goto bad_offset; | |
167 | } | |
168 | r = s->pdcm_pd_sys_sense; | |
169 | break; | |
170 | case A_PDCM_PD_SRAM0_SENSE: | |
171 | if (!s->is_sse200) { | |
172 | goto bad_offset; | |
173 | } | |
174 | r = s->pdcm_pd_sram0_sense; | |
175 | break; | |
176 | case A_PDCM_PD_SRAM1_SENSE: | |
177 | if (!s->is_sse200) { | |
178 | goto bad_offset; | |
179 | } | |
180 | r = s->pdcm_pd_sram1_sense; | |
181 | break; | |
182 | case A_PDCM_PD_SRAM2_SENSE: | |
183 | if (!s->is_sse200) { | |
184 | goto bad_offset; | |
185 | } | |
186 | r = s->pdcm_pd_sram2_sense; | |
187 | break; | |
188 | case A_PDCM_PD_SRAM3_SENSE: | |
189 | if (!s->is_sse200) { | |
190 | goto bad_offset; | |
191 | } | |
192 | r = s->pdcm_pd_sram3_sense; | |
193 | break; | |
75750e4d PM |
194 | case A_PID4 ... A_CID3: |
195 | r = sysctl_id[(offset - A_PID4) / 4]; | |
196 | break; | |
197 | case A_SECDBGSET: | |
198 | case A_SECDBGCLR: | |
199 | case A_SWRESET: | |
200 | qemu_log_mask(LOG_GUEST_ERROR, | |
201 | "IoTKit SysCtl read: read of WO offset %x\n", | |
202 | (int)offset); | |
203 | r = 0; | |
204 | break; | |
205 | default: | |
04836414 | 206 | bad_offset: |
75750e4d PM |
207 | qemu_log_mask(LOG_GUEST_ERROR, |
208 | "IoTKit SysCtl read: bad offset %x\n", (int)offset); | |
209 | r = 0; | |
210 | break; | |
211 | } | |
212 | trace_iotkit_sysctl_read(offset, r, size); | |
213 | return r; | |
214 | } | |
215 | ||
216 | static void iotkit_sysctl_write(void *opaque, hwaddr offset, | |
217 | uint64_t value, unsigned size) | |
218 | { | |
219 | IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque); | |
220 | ||
221 | trace_iotkit_sysctl_write(offset, value, size); | |
222 | ||
223 | /* | |
224 | * Most of the state here has to do with control of reset and | |
225 | * similar kinds of power up -- for instance the guest can ask | |
226 | * what the reason for the last reset was, or forbid reset for | |
227 | * some causes (like the non-secure watchdog). Most of this is | |
228 | * not relevant to QEMU, which doesn't really model anything other | |
229 | * than a full power-on reset. | |
230 | * We just model the registers as reads-as-written. | |
231 | */ | |
232 | ||
233 | switch (offset) { | |
234 | case A_RESET_SYNDROME: | |
235 | qemu_log_mask(LOG_UNIMP, | |
236 | "IoTKit SysCtl RESET_SYNDROME unimplemented\n"); | |
237 | s->reset_syndrome = value; | |
238 | break; | |
239 | case A_RESET_MASK: | |
240 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl RESET_MASK unimplemented\n"); | |
241 | s->reset_mask = value; | |
242 | break; | |
243 | case A_GRETREG: | |
244 | /* | |
245 | * General retention register, which is only reset by a power-on | |
246 | * reset. Technically this implementation is complete, since | |
247 | * QEMU only supports power-on resets... | |
248 | */ | |
249 | s->gretreg = value; | |
250 | break; | |
394e10d2 | 251 | case A_INITSVTOR0: |
394e10d2 | 252 | s->initsvtor0 = value; |
0f862986 | 253 | set_init_vtor(0, s->initsvtor0); |
75750e4d PM |
254 | break; |
255 | case A_CPUWAIT: | |
0f862986 PM |
256 | if ((s->cpuwait & 1) && !(value & 1)) { |
257 | /* Powering up CPU 0 */ | |
258 | arm_set_cpu_on_and_reset(0); | |
259 | } | |
260 | if ((s->cpuwait & 2) && !(value & 2)) { | |
261 | /* Powering up CPU 1 */ | |
262 | arm_set_cpu_on_and_reset(1); | |
263 | } | |
75750e4d PM |
264 | s->cpuwait = value; |
265 | break; | |
266 | case A_WICCTRL: | |
267 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl WICCTRL unimplemented\n"); | |
268 | s->wicctrl = value; | |
269 | break; | |
270 | case A_SECDBGSET: | |
271 | /* write-1-to-set */ | |
272 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SECDBGSET unimplemented\n"); | |
273 | s->secure_debug |= value; | |
274 | break; | |
275 | case A_SECDBGCLR: | |
276 | /* write-1-to-clear */ | |
277 | s->secure_debug &= ~value; | |
278 | break; | |
279 | case A_SWRESET: | |
280 | /* One w/o bit to request a reset; all other bits reserved */ | |
281 | if (value & R_SWRESET_SWRESETREQ_MASK) { | |
282 | qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); | |
283 | } | |
284 | break; | |
04836414 PM |
285 | case A_SCSECCTRL: |
286 | if (!s->is_sse200) { | |
287 | goto bad_offset; | |
288 | } | |
289 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SCSECCTRL unimplemented\n"); | |
290 | s->scsecctrl = value; | |
291 | break; | |
292 | case A_FCLK_DIV: | |
293 | if (!s->is_sse200) { | |
294 | goto bad_offset; | |
295 | } | |
296 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl FCLK_DIV unimplemented\n"); | |
297 | s->fclk_div = value; | |
298 | break; | |
299 | case A_SYSCLK_DIV: | |
300 | if (!s->is_sse200) { | |
301 | goto bad_offset; | |
302 | } | |
303 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SYSCLK_DIV unimplemented\n"); | |
304 | s->sysclk_div = value; | |
305 | break; | |
306 | case A_CLOCK_FORCE: | |
307 | if (!s->is_sse200) { | |
308 | goto bad_offset; | |
309 | } | |
310 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl CLOCK_FORCE unimplemented\n"); | |
311 | s->clock_force = value; | |
312 | break; | |
313 | case A_INITSVTOR1: | |
314 | if (!s->is_sse200) { | |
315 | goto bad_offset; | |
316 | } | |
04836414 | 317 | s->initsvtor1 = value; |
0f862986 | 318 | set_init_vtor(1, s->initsvtor1); |
04836414 PM |
319 | break; |
320 | case A_EWCTRL: | |
321 | if (!s->is_sse200) { | |
322 | goto bad_offset; | |
323 | } | |
324 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl EWCTRL unimplemented\n"); | |
325 | s->ewctrl = value; | |
326 | break; | |
327 | case A_PDCM_PD_SYS_SENSE: | |
328 | if (!s->is_sse200) { | |
329 | goto bad_offset; | |
330 | } | |
331 | qemu_log_mask(LOG_UNIMP, | |
332 | "IoTKit SysCtl PDCM_PD_SYS_SENSE unimplemented\n"); | |
333 | s->pdcm_pd_sys_sense = value; | |
334 | break; | |
335 | case A_PDCM_PD_SRAM0_SENSE: | |
336 | if (!s->is_sse200) { | |
337 | goto bad_offset; | |
338 | } | |
339 | qemu_log_mask(LOG_UNIMP, | |
340 | "IoTKit SysCtl PDCM_PD_SRAM0_SENSE unimplemented\n"); | |
341 | s->pdcm_pd_sram0_sense = value; | |
342 | break; | |
343 | case A_PDCM_PD_SRAM1_SENSE: | |
344 | if (!s->is_sse200) { | |
345 | goto bad_offset; | |
346 | } | |
347 | qemu_log_mask(LOG_UNIMP, | |
348 | "IoTKit SysCtl PDCM_PD_SRAM1_SENSE unimplemented\n"); | |
349 | s->pdcm_pd_sram1_sense = value; | |
350 | break; | |
351 | case A_PDCM_PD_SRAM2_SENSE: | |
352 | if (!s->is_sse200) { | |
353 | goto bad_offset; | |
354 | } | |
355 | qemu_log_mask(LOG_UNIMP, | |
356 | "IoTKit SysCtl PDCM_PD_SRAM2_SENSE unimplemented\n"); | |
357 | s->pdcm_pd_sram2_sense = value; | |
358 | break; | |
359 | case A_PDCM_PD_SRAM3_SENSE: | |
360 | if (!s->is_sse200) { | |
361 | goto bad_offset; | |
362 | } | |
363 | qemu_log_mask(LOG_UNIMP, | |
364 | "IoTKit SysCtl PDCM_PD_SRAM3_SENSE unimplemented\n"); | |
365 | s->pdcm_pd_sram3_sense = value; | |
366 | break; | |
367 | case A_NMI_ENABLE: | |
368 | /* In IoTKit this is BUSWAIT: reserved, R/O, zero */ | |
369 | if (!s->is_sse200) { | |
370 | goto ro_offset; | |
371 | } | |
372 | qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl NMI_ENABLE unimplemented\n"); | |
373 | s->nmi_enable = value; | |
374 | break; | |
75750e4d PM |
375 | case A_SECDBGSTAT: |
376 | case A_PID4 ... A_CID3: | |
04836414 | 377 | ro_offset: |
75750e4d PM |
378 | qemu_log_mask(LOG_GUEST_ERROR, |
379 | "IoTKit SysCtl write: write of RO offset %x\n", | |
380 | (int)offset); | |
381 | break; | |
382 | default: | |
04836414 | 383 | bad_offset: |
75750e4d PM |
384 | qemu_log_mask(LOG_GUEST_ERROR, |
385 | "IoTKit SysCtl write: bad offset %x\n", (int)offset); | |
386 | break; | |
387 | } | |
388 | } | |
389 | ||
390 | static const MemoryRegionOps iotkit_sysctl_ops = { | |
391 | .read = iotkit_sysctl_read, | |
392 | .write = iotkit_sysctl_write, | |
393 | .endianness = DEVICE_LITTLE_ENDIAN, | |
394 | /* byte/halfword accesses are just zero-padded on reads and writes */ | |
395 | .impl.min_access_size = 4, | |
396 | .impl.max_access_size = 4, | |
397 | .valid.min_access_size = 1, | |
398 | .valid.max_access_size = 4, | |
399 | }; | |
400 | ||
401 | static void iotkit_sysctl_reset(DeviceState *dev) | |
402 | { | |
403 | IoTKitSysCtl *s = IOTKIT_SYSCTL(dev); | |
404 | ||
405 | trace_iotkit_sysctl_reset(); | |
406 | s->secure_debug = 0; | |
407 | s->reset_syndrome = 1; | |
408 | s->reset_mask = 0; | |
409 | s->gretreg = 0; | |
aab7a378 PM |
410 | s->initsvtor0 = s->initsvtor0_rst; |
411 | s->initsvtor1 = s->initsvtor1_rst; | |
412 | s->cpuwait = s->cpuwait_rst; | |
75750e4d | 413 | s->wicctrl = 0; |
04836414 PM |
414 | s->scsecctrl = 0; |
415 | s->fclk_div = 0; | |
416 | s->sysclk_div = 0; | |
417 | s->clock_force = 0; | |
418 | s->nmi_enable = 0; | |
419 | s->ewctrl = 0; | |
420 | s->pdcm_pd_sys_sense = 0x7f; | |
421 | s->pdcm_pd_sram0_sense = 0; | |
422 | s->pdcm_pd_sram1_sense = 0; | |
423 | s->pdcm_pd_sram2_sense = 0; | |
424 | s->pdcm_pd_sram3_sense = 0; | |
75750e4d PM |
425 | } |
426 | ||
427 | static void iotkit_sysctl_init(Object *obj) | |
428 | { | |
429 | SysBusDevice *sbd = SYS_BUS_DEVICE(obj); | |
430 | IoTKitSysCtl *s = IOTKIT_SYSCTL(obj); | |
431 | ||
432 | memory_region_init_io(&s->iomem, obj, &iotkit_sysctl_ops, | |
433 | s, "iotkit-sysctl", 0x1000); | |
434 | sysbus_init_mmio(sbd, &s->iomem); | |
435 | } | |
436 | ||
04836414 PM |
437 | static void iotkit_sysctl_realize(DeviceState *dev, Error **errp) |
438 | { | |
439 | IoTKitSysCtl *s = IOTKIT_SYSCTL(dev); | |
440 | ||
441 | /* The top 4 bits of the SYS_VERSION register tell us if we're an SSE-200 */ | |
442 | if (extract32(s->sys_version, 28, 4) == 2) { | |
443 | s->is_sse200 = true; | |
444 | } | |
445 | } | |
446 | ||
447 | static bool sse200_needed(void *opaque) | |
448 | { | |
449 | IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque); | |
450 | ||
451 | return s->is_sse200; | |
452 | } | |
453 | ||
454 | static const VMStateDescription iotkit_sysctl_sse200_vmstate = { | |
455 | .name = "iotkit-sysctl/sse-200", | |
456 | .version_id = 1, | |
457 | .minimum_version_id = 1, | |
458 | .needed = sse200_needed, | |
459 | .fields = (VMStateField[]) { | |
460 | VMSTATE_UINT32(scsecctrl, IoTKitSysCtl), | |
461 | VMSTATE_UINT32(fclk_div, IoTKitSysCtl), | |
462 | VMSTATE_UINT32(sysclk_div, IoTKitSysCtl), | |
463 | VMSTATE_UINT32(clock_force, IoTKitSysCtl), | |
464 | VMSTATE_UINT32(initsvtor1, IoTKitSysCtl), | |
465 | VMSTATE_UINT32(nmi_enable, IoTKitSysCtl), | |
466 | VMSTATE_UINT32(pdcm_pd_sys_sense, IoTKitSysCtl), | |
467 | VMSTATE_UINT32(pdcm_pd_sram0_sense, IoTKitSysCtl), | |
468 | VMSTATE_UINT32(pdcm_pd_sram1_sense, IoTKitSysCtl), | |
469 | VMSTATE_UINT32(pdcm_pd_sram2_sense, IoTKitSysCtl), | |
470 | VMSTATE_UINT32(pdcm_pd_sram3_sense, IoTKitSysCtl), | |
471 | VMSTATE_END_OF_LIST() | |
472 | } | |
473 | }; | |
474 | ||
75750e4d PM |
475 | static const VMStateDescription iotkit_sysctl_vmstate = { |
476 | .name = "iotkit-sysctl", | |
477 | .version_id = 1, | |
478 | .minimum_version_id = 1, | |
479 | .fields = (VMStateField[]) { | |
480 | VMSTATE_UINT32(secure_debug, IoTKitSysCtl), | |
481 | VMSTATE_UINT32(reset_syndrome, IoTKitSysCtl), | |
482 | VMSTATE_UINT32(reset_mask, IoTKitSysCtl), | |
483 | VMSTATE_UINT32(gretreg, IoTKitSysCtl), | |
394e10d2 | 484 | VMSTATE_UINT32(initsvtor0, IoTKitSysCtl), |
75750e4d PM |
485 | VMSTATE_UINT32(cpuwait, IoTKitSysCtl), |
486 | VMSTATE_UINT32(wicctrl, IoTKitSysCtl), | |
487 | VMSTATE_END_OF_LIST() | |
04836414 PM |
488 | }, |
489 | .subsections = (const VMStateDescription*[]) { | |
490 | &iotkit_sysctl_sse200_vmstate, | |
491 | NULL | |
75750e4d PM |
492 | } |
493 | }; | |
494 | ||
04836414 PM |
495 | static Property iotkit_sysctl_props[] = { |
496 | DEFINE_PROP_UINT32("SYS_VERSION", IoTKitSysCtl, sys_version, 0), | |
aab7a378 PM |
497 | DEFINE_PROP_UINT32("CPUWAIT_RST", IoTKitSysCtl, cpuwait_rst, 0), |
498 | DEFINE_PROP_UINT32("INITSVTOR0_RST", IoTKitSysCtl, initsvtor0_rst, | |
499 | 0x10000000), | |
500 | DEFINE_PROP_UINT32("INITSVTOR1_RST", IoTKitSysCtl, initsvtor1_rst, | |
501 | 0x10000000), | |
04836414 PM |
502 | DEFINE_PROP_END_OF_LIST() |
503 | }; | |
504 | ||
75750e4d PM |
505 | static void iotkit_sysctl_class_init(ObjectClass *klass, void *data) |
506 | { | |
507 | DeviceClass *dc = DEVICE_CLASS(klass); | |
508 | ||
509 | dc->vmsd = &iotkit_sysctl_vmstate; | |
510 | dc->reset = iotkit_sysctl_reset; | |
04836414 PM |
511 | dc->props = iotkit_sysctl_props; |
512 | dc->realize = iotkit_sysctl_realize; | |
75750e4d PM |
513 | } |
514 | ||
515 | static const TypeInfo iotkit_sysctl_info = { | |
516 | .name = TYPE_IOTKIT_SYSCTL, | |
517 | .parent = TYPE_SYS_BUS_DEVICE, | |
518 | .instance_size = sizeof(IoTKitSysCtl), | |
519 | .instance_init = iotkit_sysctl_init, | |
520 | .class_init = iotkit_sysctl_class_init, | |
521 | }; | |
522 | ||
523 | static void iotkit_sysctl_register_types(void) | |
524 | { | |
525 | type_register_static(&iotkit_sysctl_info); | |
526 | } | |
527 | ||
528 | type_init(iotkit_sysctl_register_types); |