xref: /openbmc/qemu/hw/misc/iotkit-secctl.c (revision dc5bd18f)
1 /*
2  * Arm IoT Kit security controller
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 #include "qemu/osdep.h"
13 #include "qemu/log.h"
14 #include "qapi/error.h"
15 #include "trace.h"
16 #include "hw/sysbus.h"
17 #include "hw/registerfields.h"
18 #include "hw/misc/iotkit-secctl.h"
19 
20 /* Registers in the secure privilege control block */
21 REG32(SECRESPCFG, 0x10)
22 REG32(NSCCFG, 0x14)
23 REG32(SECMPCINTSTATUS, 0x1c)
24 REG32(SECPPCINTSTAT, 0x20)
25 REG32(SECPPCINTCLR, 0x24)
26 REG32(SECPPCINTEN, 0x28)
27 REG32(SECMSCINTSTAT, 0x30)
28 REG32(SECMSCINTCLR, 0x34)
29 REG32(SECMSCINTEN, 0x38)
30 REG32(BRGINTSTAT, 0x40)
31 REG32(BRGINTCLR, 0x44)
32 REG32(BRGINTEN, 0x48)
33 REG32(AHBNSPPC0, 0x50)
34 REG32(AHBNSPPCEXP0, 0x60)
35 REG32(AHBNSPPCEXP1, 0x64)
36 REG32(AHBNSPPCEXP2, 0x68)
37 REG32(AHBNSPPCEXP3, 0x6c)
38 REG32(APBNSPPC0, 0x70)
39 REG32(APBNSPPC1, 0x74)
40 REG32(APBNSPPCEXP0, 0x80)
41 REG32(APBNSPPCEXP1, 0x84)
42 REG32(APBNSPPCEXP2, 0x88)
43 REG32(APBNSPPCEXP3, 0x8c)
44 REG32(AHBSPPPC0, 0x90)
45 REG32(AHBSPPPCEXP0, 0xa0)
46 REG32(AHBSPPPCEXP1, 0xa4)
47 REG32(AHBSPPPCEXP2, 0xa8)
48 REG32(AHBSPPPCEXP3, 0xac)
49 REG32(APBSPPPC0, 0xb0)
50 REG32(APBSPPPC1, 0xb4)
51 REG32(APBSPPPCEXP0, 0xc0)
52 REG32(APBSPPPCEXP1, 0xc4)
53 REG32(APBSPPPCEXP2, 0xc8)
54 REG32(APBSPPPCEXP3, 0xcc)
55 REG32(NSMSCEXP, 0xd0)
56 REG32(PID4, 0xfd0)
57 REG32(PID5, 0xfd4)
58 REG32(PID6, 0xfd8)
59 REG32(PID7, 0xfdc)
60 REG32(PID0, 0xfe0)
61 REG32(PID1, 0xfe4)
62 REG32(PID2, 0xfe8)
63 REG32(PID3, 0xfec)
64 REG32(CID0, 0xff0)
65 REG32(CID1, 0xff4)
66 REG32(CID2, 0xff8)
67 REG32(CID3, 0xffc)
68 
69 /* Registers in the non-secure privilege control block */
70 REG32(AHBNSPPPC0, 0x90)
71 REG32(AHBNSPPPCEXP0, 0xa0)
72 REG32(AHBNSPPPCEXP1, 0xa4)
73 REG32(AHBNSPPPCEXP2, 0xa8)
74 REG32(AHBNSPPPCEXP3, 0xac)
75 REG32(APBNSPPPC0, 0xb0)
76 REG32(APBNSPPPC1, 0xb4)
77 REG32(APBNSPPPCEXP0, 0xc0)
78 REG32(APBNSPPPCEXP1, 0xc4)
79 REG32(APBNSPPPCEXP2, 0xc8)
80 REG32(APBNSPPPCEXP3, 0xcc)
81 /* PID and CID registers are also present in the NS block */
82 
83 static const uint8_t iotkit_secctl_s_idregs[] = {
84     0x04, 0x00, 0x00, 0x00,
85     0x52, 0xb8, 0x0b, 0x00,
86     0x0d, 0xf0, 0x05, 0xb1,
87 };
88 
89 static const uint8_t iotkit_secctl_ns_idregs[] = {
90     0x04, 0x00, 0x00, 0x00,
91     0x53, 0xb8, 0x0b, 0x00,
92     0x0d, 0xf0, 0x05, 0xb1,
93 };
94 
95 /* The register sets for the various PPCs (AHB internal, APB internal,
96  * AHB expansion, APB expansion) are all set up so that they are
97  * in 16-aligned blocks so offsets 0xN0, 0xN4, 0xN8, 0xNC are PPCs
98  * 0, 1, 2, 3 of that type, so we can convert a register address offset
99  * into an an index into a PPC array easily.
100  */
101 static inline int offset_to_ppc_idx(uint32_t offset)
102 {
103     return extract32(offset, 2, 2);
104 }
105 
106 typedef void PerPPCFunction(IoTKitSecCtlPPC *ppc);
107 
108 static void foreach_ppc(IoTKitSecCtl *s, PerPPCFunction *fn)
109 {
110     int i;
111 
112     for (i = 0; i < IOTS_NUM_APB_PPC; i++) {
113         fn(&s->apb[i]);
114     }
115     for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) {
116         fn(&s->apbexp[i]);
117     }
118     for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) {
119         fn(&s->ahbexp[i]);
120     }
121 }
122 
123 static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr,
124                                         uint64_t *pdata,
125                                         unsigned size, MemTxAttrs attrs)
126 {
127     uint64_t r;
128     uint32_t offset = addr & ~0x3;
129     IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
130 
131     switch (offset) {
132     case A_AHBNSPPC0:
133     case A_AHBSPPPC0:
134         r = 0;
135         break;
136     case A_SECRESPCFG:
137         r = s->secrespcfg;
138         break;
139     case A_NSCCFG:
140         r = s->nsccfg;
141         break;
142     case A_SECPPCINTSTAT:
143         r = s->secppcintstat;
144         break;
145     case A_SECPPCINTEN:
146         r = s->secppcinten;
147         break;
148     case A_BRGINTSTAT:
149         /* QEMU's bus fabric can never report errors as it doesn't buffer
150          * writes, so we never report bridge interrupts.
151          */
152         r = 0;
153         break;
154     case A_BRGINTEN:
155         r = s->brginten;
156         break;
157     case A_AHBNSPPCEXP0:
158     case A_AHBNSPPCEXP1:
159     case A_AHBNSPPCEXP2:
160     case A_AHBNSPPCEXP3:
161         r = s->ahbexp[offset_to_ppc_idx(offset)].ns;
162         break;
163     case A_APBNSPPC0:
164     case A_APBNSPPC1:
165         r = s->apb[offset_to_ppc_idx(offset)].ns;
166         break;
167     case A_APBNSPPCEXP0:
168     case A_APBNSPPCEXP1:
169     case A_APBNSPPCEXP2:
170     case A_APBNSPPCEXP3:
171         r = s->apbexp[offset_to_ppc_idx(offset)].ns;
172         break;
173     case A_AHBSPPPCEXP0:
174     case A_AHBSPPPCEXP1:
175     case A_AHBSPPPCEXP2:
176     case A_AHBSPPPCEXP3:
177         r = s->apbexp[offset_to_ppc_idx(offset)].sp;
178         break;
179     case A_APBSPPPC0:
180     case A_APBSPPPC1:
181         r = s->apb[offset_to_ppc_idx(offset)].sp;
182         break;
183     case A_APBSPPPCEXP0:
184     case A_APBSPPPCEXP1:
185     case A_APBSPPPCEXP2:
186     case A_APBSPPPCEXP3:
187         r = s->apbexp[offset_to_ppc_idx(offset)].sp;
188         break;
189     case A_SECMPCINTSTATUS:
190     case A_SECMSCINTSTAT:
191     case A_SECMSCINTEN:
192     case A_NSMSCEXP:
193         qemu_log_mask(LOG_UNIMP,
194                       "IoTKit SecCtl S block read: "
195                       "unimplemented offset 0x%x\n", offset);
196         r = 0;
197         break;
198     case A_PID4:
199     case A_PID5:
200     case A_PID6:
201     case A_PID7:
202     case A_PID0:
203     case A_PID1:
204     case A_PID2:
205     case A_PID3:
206     case A_CID0:
207     case A_CID1:
208     case A_CID2:
209     case A_CID3:
210         r = iotkit_secctl_s_idregs[(offset - A_PID4) / 4];
211         break;
212     case A_SECPPCINTCLR:
213     case A_SECMSCINTCLR:
214     case A_BRGINTCLR:
215         qemu_log_mask(LOG_GUEST_ERROR,
216                       "IotKit SecCtl S block read: write-only offset 0x%x\n",
217                       offset);
218         r = 0;
219         break;
220     default:
221         qemu_log_mask(LOG_GUEST_ERROR,
222                       "IotKit SecCtl S block read: bad offset 0x%x\n", offset);
223         r = 0;
224         break;
225     }
226 
227     if (size != 4) {
228         /* None of our registers are access-sensitive, so just pull the right
229          * byte out of the word read result.
230          */
231         r = extract32(r, (addr & 3) * 8, size * 8);
232     }
233 
234     trace_iotkit_secctl_s_read(offset, r, size);
235     *pdata = r;
236     return MEMTX_OK;
237 }
238 
239 static void iotkit_secctl_update_ppc_ap(IoTKitSecCtlPPC *ppc)
240 {
241     int i;
242 
243     for (i = 0; i < ppc->numports; i++) {
244         bool v;
245 
246         if (extract32(ppc->ns, i, 1)) {
247             v = extract32(ppc->nsp, i, 1);
248         } else {
249             v = extract32(ppc->sp, i, 1);
250         }
251         qemu_set_irq(ppc->ap[i], v);
252     }
253 }
254 
255 static void iotkit_secctl_ppc_ns_write(IoTKitSecCtlPPC *ppc, uint32_t value)
256 {
257     int i;
258 
259     ppc->ns = value & MAKE_64BIT_MASK(0, ppc->numports);
260     for (i = 0; i < ppc->numports; i++) {
261         qemu_set_irq(ppc->nonsec[i], extract32(ppc->ns, i, 1));
262     }
263     iotkit_secctl_update_ppc_ap(ppc);
264 }
265 
266 static void iotkit_secctl_ppc_sp_write(IoTKitSecCtlPPC *ppc, uint32_t value)
267 {
268     ppc->sp = value & MAKE_64BIT_MASK(0, ppc->numports);
269     iotkit_secctl_update_ppc_ap(ppc);
270 }
271 
272 static void iotkit_secctl_ppc_nsp_write(IoTKitSecCtlPPC *ppc, uint32_t value)
273 {
274     ppc->nsp = value & MAKE_64BIT_MASK(0, ppc->numports);
275     iotkit_secctl_update_ppc_ap(ppc);
276 }
277 
278 static void iotkit_secctl_ppc_update_irq_clear(IoTKitSecCtlPPC *ppc)
279 {
280     uint32_t value = ppc->parent->secppcintstat;
281 
282     qemu_set_irq(ppc->irq_clear, extract32(value, ppc->irq_bit_offset, 1));
283 }
284 
285 static void iotkit_secctl_ppc_update_irq_enable(IoTKitSecCtlPPC *ppc)
286 {
287     uint32_t value = ppc->parent->secppcinten;
288 
289     qemu_set_irq(ppc->irq_enable, extract32(value, ppc->irq_bit_offset, 1));
290 }
291 
292 static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
293                                          uint64_t value,
294                                          unsigned size, MemTxAttrs attrs)
295 {
296     IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
297     uint32_t offset = addr;
298     IoTKitSecCtlPPC *ppc;
299 
300     trace_iotkit_secctl_s_write(offset, value, size);
301 
302     if (size != 4) {
303         /* Byte and halfword writes are ignored */
304         qemu_log_mask(LOG_GUEST_ERROR,
305                       "IotKit SecCtl S block write: bad size, ignored\n");
306         return MEMTX_OK;
307     }
308 
309     switch (offset) {
310     case A_NSCCFG:
311         s->nsccfg = value & 3;
312         qemu_set_irq(s->nsc_cfg_irq, s->nsccfg);
313         break;
314     case A_SECRESPCFG:
315         value &= 1;
316         s->secrespcfg = value;
317         qemu_set_irq(s->sec_resp_cfg, s->secrespcfg);
318         break;
319     case A_SECPPCINTCLR:
320         value &= 0x00f000f3;
321         foreach_ppc(s, iotkit_secctl_ppc_update_irq_clear);
322         break;
323     case A_SECPPCINTEN:
324         s->secppcinten = value & 0x00f000f3;
325         foreach_ppc(s, iotkit_secctl_ppc_update_irq_enable);
326         break;
327     case A_BRGINTCLR:
328         break;
329     case A_BRGINTEN:
330         s->brginten = value & 0xffff0000;
331         break;
332     case A_AHBNSPPCEXP0:
333     case A_AHBNSPPCEXP1:
334     case A_AHBNSPPCEXP2:
335     case A_AHBNSPPCEXP3:
336         ppc = &s->ahbexp[offset_to_ppc_idx(offset)];
337         iotkit_secctl_ppc_ns_write(ppc, value);
338         break;
339     case A_APBNSPPC0:
340     case A_APBNSPPC1:
341         ppc = &s->apb[offset_to_ppc_idx(offset)];
342         iotkit_secctl_ppc_ns_write(ppc, value);
343         break;
344     case A_APBNSPPCEXP0:
345     case A_APBNSPPCEXP1:
346     case A_APBNSPPCEXP2:
347     case A_APBNSPPCEXP3:
348         ppc = &s->apbexp[offset_to_ppc_idx(offset)];
349         iotkit_secctl_ppc_ns_write(ppc, value);
350         break;
351     case A_AHBSPPPCEXP0:
352     case A_AHBSPPPCEXP1:
353     case A_AHBSPPPCEXP2:
354     case A_AHBSPPPCEXP3:
355         ppc = &s->ahbexp[offset_to_ppc_idx(offset)];
356         iotkit_secctl_ppc_sp_write(ppc, value);
357         break;
358     case A_APBSPPPC0:
359     case A_APBSPPPC1:
360         ppc = &s->apb[offset_to_ppc_idx(offset)];
361         iotkit_secctl_ppc_sp_write(ppc, value);
362         break;
363     case A_APBSPPPCEXP0:
364     case A_APBSPPPCEXP1:
365     case A_APBSPPPCEXP2:
366     case A_APBSPPPCEXP3:
367         ppc = &s->apbexp[offset_to_ppc_idx(offset)];
368         iotkit_secctl_ppc_sp_write(ppc, value);
369         break;
370     case A_SECMSCINTCLR:
371     case A_SECMSCINTEN:
372         qemu_log_mask(LOG_UNIMP,
373                       "IoTKit SecCtl S block write: "
374                       "unimplemented offset 0x%x\n", offset);
375         break;
376     case A_SECMPCINTSTATUS:
377     case A_SECPPCINTSTAT:
378     case A_SECMSCINTSTAT:
379     case A_BRGINTSTAT:
380     case A_AHBNSPPC0:
381     case A_AHBSPPPC0:
382     case A_NSMSCEXP:
383     case A_PID4:
384     case A_PID5:
385     case A_PID6:
386     case A_PID7:
387     case A_PID0:
388     case A_PID1:
389     case A_PID2:
390     case A_PID3:
391     case A_CID0:
392     case A_CID1:
393     case A_CID2:
394     case A_CID3:
395         qemu_log_mask(LOG_GUEST_ERROR,
396                       "IoTKit SecCtl S block write: "
397                       "read-only offset 0x%x\n", offset);
398         break;
399     default:
400         qemu_log_mask(LOG_GUEST_ERROR,
401                       "IotKit SecCtl S block write: bad offset 0x%x\n",
402                       offset);
403         break;
404     }
405 
406     return MEMTX_OK;
407 }
408 
409 static MemTxResult iotkit_secctl_ns_read(void *opaque, hwaddr addr,
410                                          uint64_t *pdata,
411                                          unsigned size, MemTxAttrs attrs)
412 {
413     IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
414     uint64_t r;
415     uint32_t offset = addr & ~0x3;
416 
417     switch (offset) {
418     case A_AHBNSPPPC0:
419         r = 0;
420         break;
421     case A_AHBNSPPPCEXP0:
422     case A_AHBNSPPPCEXP1:
423     case A_AHBNSPPPCEXP2:
424     case A_AHBNSPPPCEXP3:
425         r = s->ahbexp[offset_to_ppc_idx(offset)].nsp;
426         break;
427     case A_APBNSPPPC0:
428     case A_APBNSPPPC1:
429         r = s->apb[offset_to_ppc_idx(offset)].nsp;
430         break;
431     case A_APBNSPPPCEXP0:
432     case A_APBNSPPPCEXP1:
433     case A_APBNSPPPCEXP2:
434     case A_APBNSPPPCEXP3:
435         r = s->apbexp[offset_to_ppc_idx(offset)].nsp;
436         break;
437     case A_PID4:
438     case A_PID5:
439     case A_PID6:
440     case A_PID7:
441     case A_PID0:
442     case A_PID1:
443     case A_PID2:
444     case A_PID3:
445     case A_CID0:
446     case A_CID1:
447     case A_CID2:
448     case A_CID3:
449         r = iotkit_secctl_ns_idregs[(offset - A_PID4) / 4];
450         break;
451     default:
452         qemu_log_mask(LOG_GUEST_ERROR,
453                       "IotKit SecCtl NS block write: bad offset 0x%x\n",
454                       offset);
455         r = 0;
456         break;
457     }
458 
459     if (size != 4) {
460         /* None of our registers are access-sensitive, so just pull the right
461          * byte out of the word read result.
462          */
463         r = extract32(r, (addr & 3) * 8, size * 8);
464     }
465 
466     trace_iotkit_secctl_ns_read(offset, r, size);
467     *pdata = r;
468     return MEMTX_OK;
469 }
470 
471 static MemTxResult iotkit_secctl_ns_write(void *opaque, hwaddr addr,
472                                           uint64_t value,
473                                           unsigned size, MemTxAttrs attrs)
474 {
475     IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
476     uint32_t offset = addr;
477     IoTKitSecCtlPPC *ppc;
478 
479     trace_iotkit_secctl_ns_write(offset, value, size);
480 
481     if (size != 4) {
482         /* Byte and halfword writes are ignored */
483         qemu_log_mask(LOG_GUEST_ERROR,
484                       "IotKit SecCtl NS block write: bad size, ignored\n");
485         return MEMTX_OK;
486     }
487 
488     switch (offset) {
489     case A_AHBNSPPPCEXP0:
490     case A_AHBNSPPPCEXP1:
491     case A_AHBNSPPPCEXP2:
492     case A_AHBNSPPPCEXP3:
493         ppc = &s->ahbexp[offset_to_ppc_idx(offset)];
494         iotkit_secctl_ppc_nsp_write(ppc, value);
495         break;
496     case A_APBNSPPPC0:
497     case A_APBNSPPPC1:
498         ppc = &s->apb[offset_to_ppc_idx(offset)];
499         iotkit_secctl_ppc_nsp_write(ppc, value);
500         break;
501     case A_APBNSPPPCEXP0:
502     case A_APBNSPPPCEXP1:
503     case A_APBNSPPPCEXP2:
504     case A_APBNSPPPCEXP3:
505         ppc = &s->apbexp[offset_to_ppc_idx(offset)];
506         iotkit_secctl_ppc_nsp_write(ppc, value);
507         break;
508     case A_AHBNSPPPC0:
509     case A_PID4:
510     case A_PID5:
511     case A_PID6:
512     case A_PID7:
513     case A_PID0:
514     case A_PID1:
515     case A_PID2:
516     case A_PID3:
517     case A_CID0:
518     case A_CID1:
519     case A_CID2:
520     case A_CID3:
521         qemu_log_mask(LOG_GUEST_ERROR,
522                       "IoTKit SecCtl NS block write: "
523                       "read-only offset 0x%x\n", offset);
524         break;
525     default:
526         qemu_log_mask(LOG_GUEST_ERROR,
527                       "IotKit SecCtl NS block write: bad offset 0x%x\n",
528                       offset);
529         break;
530     }
531 
532     return MEMTX_OK;
533 }
534 
535 static const MemoryRegionOps iotkit_secctl_s_ops = {
536     .read_with_attrs = iotkit_secctl_s_read,
537     .write_with_attrs = iotkit_secctl_s_write,
538     .endianness = DEVICE_LITTLE_ENDIAN,
539     .valid.min_access_size = 1,
540     .valid.max_access_size = 4,
541     .impl.min_access_size = 1,
542     .impl.max_access_size = 4,
543 };
544 
545 static const MemoryRegionOps iotkit_secctl_ns_ops = {
546     .read_with_attrs = iotkit_secctl_ns_read,
547     .write_with_attrs = iotkit_secctl_ns_write,
548     .endianness = DEVICE_LITTLE_ENDIAN,
549     .valid.min_access_size = 1,
550     .valid.max_access_size = 4,
551     .impl.min_access_size = 1,
552     .impl.max_access_size = 4,
553 };
554 
555 static void iotkit_secctl_reset_ppc(IoTKitSecCtlPPC *ppc)
556 {
557     ppc->ns = 0;
558     ppc->sp = 0;
559     ppc->nsp = 0;
560 }
561 
562 static void iotkit_secctl_reset(DeviceState *dev)
563 {
564     IoTKitSecCtl *s = IOTKIT_SECCTL(dev);
565 
566     s->secppcintstat = 0;
567     s->secppcinten = 0;
568     s->secrespcfg = 0;
569     s->nsccfg = 0;
570     s->brginten = 0;
571 
572     foreach_ppc(s, iotkit_secctl_reset_ppc);
573 }
574 
575 static void iotkit_secctl_ppc_irqstatus(void *opaque, int n, int level)
576 {
577     IoTKitSecCtlPPC *ppc = opaque;
578     IoTKitSecCtl *s = IOTKIT_SECCTL(ppc->parent);
579     int irqbit = ppc->irq_bit_offset + n;
580 
581     s->secppcintstat = deposit32(s->secppcintstat, irqbit, 1, level);
582 }
583 
584 static void iotkit_secctl_init_ppc(IoTKitSecCtl *s,
585                                    IoTKitSecCtlPPC *ppc,
586                                    const char *name,
587                                    int numports,
588                                    int irq_bit_offset)
589 {
590     char *gpioname;
591     DeviceState *dev = DEVICE(s);
592 
593     ppc->numports = numports;
594     ppc->irq_bit_offset = irq_bit_offset;
595     ppc->parent = s;
596 
597     gpioname = g_strdup_printf("%s_nonsec", name);
598     qdev_init_gpio_out_named(dev, ppc->nonsec, gpioname, numports);
599     g_free(gpioname);
600     gpioname = g_strdup_printf("%s_ap", name);
601     qdev_init_gpio_out_named(dev, ppc->ap, gpioname, numports);
602     g_free(gpioname);
603     gpioname = g_strdup_printf("%s_irq_enable", name);
604     qdev_init_gpio_out_named(dev, &ppc->irq_enable, gpioname, 1);
605     g_free(gpioname);
606     gpioname = g_strdup_printf("%s_irq_clear", name);
607     qdev_init_gpio_out_named(dev, &ppc->irq_clear, gpioname, 1);
608     g_free(gpioname);
609     gpioname = g_strdup_printf("%s_irq_status", name);
610     qdev_init_gpio_in_named_with_opaque(dev, iotkit_secctl_ppc_irqstatus,
611                                         ppc, gpioname, 1);
612     g_free(gpioname);
613 }
614 
615 static void iotkit_secctl_init(Object *obj)
616 {
617     IoTKitSecCtl *s = IOTKIT_SECCTL(obj);
618     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
619     DeviceState *dev = DEVICE(obj);
620     int i;
621 
622     iotkit_secctl_init_ppc(s, &s->apb[0], "apb_ppc0",
623                            IOTS_APB_PPC0_NUM_PORTS, 0);
624     iotkit_secctl_init_ppc(s, &s->apb[1], "apb_ppc1",
625                            IOTS_APB_PPC1_NUM_PORTS, 1);
626 
627     for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) {
628         IoTKitSecCtlPPC *ppc = &s->apbexp[i];
629         char *ppcname = g_strdup_printf("apb_ppcexp%d", i);
630         iotkit_secctl_init_ppc(s, ppc, ppcname, IOTS_PPC_NUM_PORTS, 4 + i);
631         g_free(ppcname);
632     }
633     for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) {
634         IoTKitSecCtlPPC *ppc = &s->ahbexp[i];
635         char *ppcname = g_strdup_printf("ahb_ppcexp%d", i);
636         iotkit_secctl_init_ppc(s, ppc, ppcname, IOTS_PPC_NUM_PORTS, 20 + i);
637         g_free(ppcname);
638     }
639 
640     qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg", 1);
641     qdev_init_gpio_out_named(dev, &s->nsc_cfg_irq, "nsc_cfg", 1);
642 
643     memory_region_init_io(&s->s_regs, obj, &iotkit_secctl_s_ops,
644                           s, "iotkit-secctl-s-regs", 0x1000);
645     memory_region_init_io(&s->ns_regs, obj, &iotkit_secctl_ns_ops,
646                           s, "iotkit-secctl-ns-regs", 0x1000);
647     sysbus_init_mmio(sbd, &s->s_regs);
648     sysbus_init_mmio(sbd, &s->ns_regs);
649 }
650 
651 static const VMStateDescription iotkit_secctl_ppc_vmstate = {
652     .name = "iotkit-secctl-ppc",
653     .version_id = 1,
654     .minimum_version_id = 1,
655     .fields = (VMStateField[]) {
656         VMSTATE_UINT32(ns, IoTKitSecCtlPPC),
657         VMSTATE_UINT32(sp, IoTKitSecCtlPPC),
658         VMSTATE_UINT32(nsp, IoTKitSecCtlPPC),
659         VMSTATE_END_OF_LIST()
660     }
661 };
662 
663 static const VMStateDescription iotkit_secctl_vmstate = {
664     .name = "iotkit-secctl",
665     .version_id = 1,
666     .minimum_version_id = 1,
667     .fields = (VMStateField[]) {
668         VMSTATE_UINT32(secppcintstat, IoTKitSecCtl),
669         VMSTATE_UINT32(secppcinten, IoTKitSecCtl),
670         VMSTATE_UINT32(secrespcfg, IoTKitSecCtl),
671         VMSTATE_UINT32(nsccfg, IoTKitSecCtl),
672         VMSTATE_UINT32(brginten, IoTKitSecCtl),
673         VMSTATE_STRUCT_ARRAY(apb, IoTKitSecCtl, IOTS_NUM_APB_PPC, 1,
674                              iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC),
675         VMSTATE_STRUCT_ARRAY(apbexp, IoTKitSecCtl, IOTS_NUM_APB_EXP_PPC, 1,
676                              iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC),
677         VMSTATE_STRUCT_ARRAY(ahbexp, IoTKitSecCtl, IOTS_NUM_AHB_EXP_PPC, 1,
678                              iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC),
679         VMSTATE_END_OF_LIST()
680     }
681 };
682 
683 static void iotkit_secctl_class_init(ObjectClass *klass, void *data)
684 {
685     DeviceClass *dc = DEVICE_CLASS(klass);
686 
687     dc->vmsd = &iotkit_secctl_vmstate;
688     dc->reset = iotkit_secctl_reset;
689 }
690 
691 static const TypeInfo iotkit_secctl_info = {
692     .name = TYPE_IOTKIT_SECCTL,
693     .parent = TYPE_SYS_BUS_DEVICE,
694     .instance_size = sizeof(IoTKitSecCtl),
695     .instance_init = iotkit_secctl_init,
696     .class_init = iotkit_secctl_class_init,
697 };
698 
699 static void iotkit_secctl_register_types(void)
700 {
701     type_register_static(&iotkit_secctl_info);
702 }
703 
704 type_init(iotkit_secctl_register_types);
705