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