1
2
3
4
5
6
7
8
9
10
11
12#include "qemu/osdep.h"
13#include "qemu/log.h"
14#include "qemu/module.h"
15#include "qemu/bitops.h"
16#include "qapi/error.h"
17#include "trace.h"
18#include "hw/sysbus.h"
19#include "hw/registerfields.h"
20#include "hw/arm/armsse.h"
21#include "hw/arm/boot.h"
22
23
24typedef enum SysConfigFormat {
25 IoTKitFormat,
26 SSE200Format,
27} SysConfigFormat;
28
29struct ARMSSEInfo {
30 const char *name;
31 int sram_banks;
32 int num_cpus;
33 uint32_t sys_version;
34 uint32_t cpuwait_rst;
35 SysConfigFormat sys_config_format;
36 bool has_mhus;
37 bool has_ppus;
38 bool has_cachectrl;
39 bool has_cpusecctrl;
40 bool has_cpuid;
41 Property *props;
42};
43
44static Property iotkit_properties[] = {
45 DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION,
46 MemoryRegion *),
47 DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
48 DEFINE_PROP_UINT32("MAINCLK", ARMSSE, mainclk_frq, 0),
49 DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15),
50 DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000),
51 DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], true),
52 DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], true),
53 DEFINE_PROP_END_OF_LIST()
54};
55
56static Property armsse_properties[] = {
57 DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION,
58 MemoryRegion *),
59 DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
60 DEFINE_PROP_UINT32("MAINCLK", ARMSSE, mainclk_frq, 0),
61 DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15),
62 DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000),
63 DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], false),
64 DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], false),
65 DEFINE_PROP_BOOL("CPU1_FPU", ARMSSE, cpu_fpu[1], true),
66 DEFINE_PROP_BOOL("CPU1_DSP", ARMSSE, cpu_dsp[1], true),
67 DEFINE_PROP_END_OF_LIST()
68};
69
70static const ARMSSEInfo armsse_variants[] = {
71 {
72 .name = TYPE_IOTKIT,
73 .sram_banks = 1,
74 .num_cpus = 1,
75 .sys_version = 0x41743,
76 .cpuwait_rst = 0,
77 .sys_config_format = IoTKitFormat,
78 .has_mhus = false,
79 .has_ppus = false,
80 .has_cachectrl = false,
81 .has_cpusecctrl = false,
82 .has_cpuid = false,
83 .props = iotkit_properties,
84 },
85 {
86 .name = TYPE_SSE200,
87 .sram_banks = 4,
88 .num_cpus = 2,
89 .sys_version = 0x22041743,
90 .cpuwait_rst = 2,
91 .sys_config_format = SSE200Format,
92 .has_mhus = true,
93 .has_ppus = true,
94 .has_cachectrl = true,
95 .has_cpusecctrl = true,
96 .has_cpuid = true,
97 .props = armsse_properties,
98 },
99};
100
101static uint32_t armsse_sys_config_value(ARMSSE *s, const ARMSSEInfo *info)
102{
103
104 uint32_t sys_config;
105
106 switch (info->sys_config_format) {
107 case IoTKitFormat:
108 sys_config = 0;
109 sys_config = deposit32(sys_config, 0, 4, info->sram_banks);
110 sys_config = deposit32(sys_config, 4, 4, s->sram_addr_width - 12);
111 break;
112 case SSE200Format:
113 sys_config = 0;
114 sys_config = deposit32(sys_config, 0, 4, info->sram_banks);
115 sys_config = deposit32(sys_config, 4, 5, s->sram_addr_width);
116 sys_config = deposit32(sys_config, 24, 4, 2);
117 if (info->num_cpus > 1) {
118 sys_config = deposit32(sys_config, 10, 1, 1);
119 sys_config = deposit32(sys_config, 20, 4, info->sram_banks - 1);
120 sys_config = deposit32(sys_config, 28, 4, 2);
121 }
122 break;
123 default:
124 g_assert_not_reached();
125 }
126 return sys_config;
127}
128
129
130#define S32KCLK (32 * 1000)
131
132
133static bool irq_is_common[32] = {
134 [0 ... 5] = true,
135
136 [8 ... 12] = true,
137
138
139 [15 ... 20] = true,
140
141 [22 ... 26] = true,
142
143
144
145};
146
147
148
149
150
151static void make_alias(ARMSSE *s, MemoryRegion *mr, MemoryRegion *container,
152 const char *name, hwaddr base, hwaddr size, hwaddr orig)
153{
154 memory_region_init_alias(mr, NULL, name, container, orig, size);
155
156 memory_region_add_subregion_overlap(container, base, mr, -1500);
157}
158
159static void irq_status_forwarder(void *opaque, int n, int level)
160{
161 qemu_irq destirq = opaque;
162
163 qemu_set_irq(destirq, level);
164}
165
166static void nsccfg_handler(void *opaque, int n, int level)
167{
168 ARMSSE *s = ARMSSE(opaque);
169
170 s->nsccfg = level;
171}
172
173static void armsse_forward_ppc(ARMSSE *s, const char *ppcname, int ppcnum)
174{
175
176
177
178
179
180
181 SplitIRQ *splitter = &s->ppc_irq_splitter[ppcnum];
182 DeviceState *armssedev = DEVICE(s);
183 DeviceState *dev_secctl = DEVICE(&s->secctl);
184 DeviceState *dev_splitter = DEVICE(splitter);
185 char *name;
186
187 name = g_strdup_printf("%s_nonsec", ppcname);
188 qdev_pass_gpios(dev_secctl, armssedev, name);
189 g_free(name);
190 name = g_strdup_printf("%s_ap", ppcname);
191 qdev_pass_gpios(dev_secctl, armssedev, name);
192 g_free(name);
193 name = g_strdup_printf("%s_irq_enable", ppcname);
194 qdev_pass_gpios(dev_secctl, armssedev, name);
195 g_free(name);
196 name = g_strdup_printf("%s_irq_clear", ppcname);
197 qdev_pass_gpios(dev_secctl, armssedev, name);
198 g_free(name);
199
200
201
202
203
204
205
206 name = g_strdup_printf("%s_irq_status", ppcname);
207 qdev_connect_gpio_out(dev_splitter, 0,
208 qdev_get_gpio_in_named(dev_secctl,
209 name, 0));
210 qdev_connect_gpio_out(dev_splitter, 1,
211 qdev_get_gpio_in(DEVICE(&s->ppc_irq_orgate), ppcnum));
212 s->irq_status_in[ppcnum] = qdev_get_gpio_in(dev_splitter, 0);
213 qdev_init_gpio_in_named_with_opaque(armssedev, irq_status_forwarder,
214 s->irq_status_in[ppcnum], name, 1);
215 g_free(name);
216}
217
218static void armsse_forward_sec_resp_cfg(ARMSSE *s)
219{
220
221
222
223 DeviceState *dev = DEVICE(s);
224 DeviceState *dev_splitter = DEVICE(&s->sec_resp_splitter);
225
226 qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg", 1);
227 s->sec_resp_cfg_in = qemu_allocate_irq(irq_status_forwarder,
228 s->sec_resp_cfg, 1);
229 qdev_connect_gpio_out(dev_splitter, 2, s->sec_resp_cfg_in);
230}
231
232static void armsse_init(Object *obj)
233{
234 ARMSSE *s = ARMSSE(obj);
235 ARMSSEClass *asc = ARMSSE_GET_CLASS(obj);
236 const ARMSSEInfo *info = asc->info;
237 int i;
238
239 assert(info->sram_banks <= MAX_SRAM_BANKS);
240 assert(info->num_cpus <= SSE_MAX_CPUS);
241
242 memory_region_init(&s->container, obj, "armsse-container", UINT64_MAX);
243
244 for (i = 0; i < info->num_cpus; i++) {
245
246
247
248
249 char *name;
250
251 name = g_strdup_printf("cluster%d", i);
252 object_initialize_child(obj, name, &s->cluster[i],
253 sizeof(s->cluster[i]), TYPE_CPU_CLUSTER,
254 &error_abort, NULL);
255 qdev_prop_set_uint32(DEVICE(&s->cluster[i]), "cluster-id", i);
256 g_free(name);
257
258 name = g_strdup_printf("armv7m%d", i);
259 sysbus_init_child_obj(OBJECT(&s->cluster[i]), name,
260 &s->armv7m[i], sizeof(s->armv7m), TYPE_ARMV7M);
261 qdev_prop_set_string(DEVICE(&s->armv7m[i]), "cpu-type",
262 ARM_CPU_TYPE_NAME("cortex-m33"));
263 g_free(name);
264 name = g_strdup_printf("arm-sse-cpu-container%d", i);
265 memory_region_init(&s->cpu_container[i], obj, name, UINT64_MAX);
266 g_free(name);
267 if (i > 0) {
268 name = g_strdup_printf("arm-sse-container-alias%d", i);
269 memory_region_init_alias(&s->container_alias[i - 1], obj,
270 name, &s->container, 0, UINT64_MAX);
271 g_free(name);
272 }
273 }
274
275 sysbus_init_child_obj(obj, "secctl", &s->secctl, sizeof(s->secctl),
276 TYPE_IOTKIT_SECCTL);
277 sysbus_init_child_obj(obj, "apb-ppc0", &s->apb_ppc0, sizeof(s->apb_ppc0),
278 TYPE_TZ_PPC);
279 sysbus_init_child_obj(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1),
280 TYPE_TZ_PPC);
281 for (i = 0; i < info->sram_banks; i++) {
282 char *name = g_strdup_printf("mpc%d", i);
283 sysbus_init_child_obj(obj, name, &s->mpc[i],
284 sizeof(s->mpc[i]), TYPE_TZ_MPC);
285 g_free(name);
286 }
287 object_initialize_child(obj, "mpc-irq-orgate", &s->mpc_irq_orgate,
288 sizeof(s->mpc_irq_orgate), TYPE_OR_IRQ,
289 &error_abort, NULL);
290
291 for (i = 0; i < IOTS_NUM_EXP_MPC + info->sram_banks; i++) {
292 char *name = g_strdup_printf("mpc-irq-splitter-%d", i);
293 SplitIRQ *splitter = &s->mpc_irq_splitter[i];
294
295 object_initialize_child(obj, name, splitter, sizeof(*splitter),
296 TYPE_SPLIT_IRQ, &error_abort, NULL);
297 g_free(name);
298 }
299 sysbus_init_child_obj(obj, "timer0", &s->timer0, sizeof(s->timer0),
300 TYPE_CMSDK_APB_TIMER);
301 sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1),
302 TYPE_CMSDK_APB_TIMER);
303 sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
304 TYPE_CMSDK_APB_TIMER);
305 sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
306 TYPE_CMSDK_APB_DUALTIMER);
307 sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog,
308 sizeof(s->s32kwatchdog), TYPE_CMSDK_APB_WATCHDOG);
309 sysbus_init_child_obj(obj, "nswatchdog", &s->nswatchdog,
310 sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG);
311 sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog,
312 sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG);
313 sysbus_init_child_obj(obj, "armsse-sysctl", &s->sysctl,
314 sizeof(s->sysctl), TYPE_IOTKIT_SYSCTL);
315 sysbus_init_child_obj(obj, "armsse-sysinfo", &s->sysinfo,
316 sizeof(s->sysinfo), TYPE_IOTKIT_SYSINFO);
317 if (info->has_mhus) {
318 sysbus_init_child_obj(obj, "mhu0", &s->mhu[0], sizeof(s->mhu[0]),
319 TYPE_ARMSSE_MHU);
320 sysbus_init_child_obj(obj, "mhu1", &s->mhu[1], sizeof(s->mhu[1]),
321 TYPE_ARMSSE_MHU);
322 }
323 if (info->has_ppus) {
324 for (i = 0; i < info->num_cpus; i++) {
325 char *name = g_strdup_printf("CPU%dCORE_PPU", i);
326 int ppuidx = CPU0CORE_PPU + i;
327
328 sysbus_init_child_obj(obj, name, &s->ppu[ppuidx],
329 sizeof(s->ppu[ppuidx]),
330 TYPE_UNIMPLEMENTED_DEVICE);
331 g_free(name);
332 }
333 sysbus_init_child_obj(obj, "DBG_PPU", &s->ppu[DBG_PPU],
334 sizeof(s->ppu[DBG_PPU]),
335 TYPE_UNIMPLEMENTED_DEVICE);
336 for (i = 0; i < info->sram_banks; i++) {
337 char *name = g_strdup_printf("RAM%d_PPU", i);
338 int ppuidx = RAM0_PPU + i;
339
340 sysbus_init_child_obj(obj, name, &s->ppu[ppuidx],
341 sizeof(s->ppu[ppuidx]),
342 TYPE_UNIMPLEMENTED_DEVICE);
343 g_free(name);
344 }
345 }
346 if (info->has_cachectrl) {
347 for (i = 0; i < info->num_cpus; i++) {
348 char *name = g_strdup_printf("cachectrl%d", i);
349
350 sysbus_init_child_obj(obj, name, &s->cachectrl[i],
351 sizeof(s->cachectrl[i]),
352 TYPE_UNIMPLEMENTED_DEVICE);
353 g_free(name);
354 }
355 }
356 if (info->has_cpusecctrl) {
357 for (i = 0; i < info->num_cpus; i++) {
358 char *name = g_strdup_printf("cpusecctrl%d", i);
359
360 sysbus_init_child_obj(obj, name, &s->cpusecctrl[i],
361 sizeof(s->cpusecctrl[i]),
362 TYPE_UNIMPLEMENTED_DEVICE);
363 g_free(name);
364 }
365 }
366 if (info->has_cpuid) {
367 for (i = 0; i < info->num_cpus; i++) {
368 char *name = g_strdup_printf("cpuid%d", i);
369
370 sysbus_init_child_obj(obj, name, &s->cpuid[i],
371 sizeof(s->cpuid[i]),
372 TYPE_ARMSSE_CPUID);
373 g_free(name);
374 }
375 }
376 object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate,
377 sizeof(s->nmi_orgate), TYPE_OR_IRQ,
378 &error_abort, NULL);
379 object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate,
380 sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ,
381 &error_abort, NULL);
382 object_initialize_child(obj, "sec-resp-splitter", &s->sec_resp_splitter,
383 sizeof(s->sec_resp_splitter), TYPE_SPLIT_IRQ,
384 &error_abort, NULL);
385 for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
386 char *name = g_strdup_printf("ppc-irq-splitter-%d", i);
387 SplitIRQ *splitter = &s->ppc_irq_splitter[i];
388
389 object_initialize_child(obj, name, splitter, sizeof(*splitter),
390 TYPE_SPLIT_IRQ, &error_abort, NULL);
391 g_free(name);
392 }
393 if (info->num_cpus > 1) {
394 for (i = 0; i < ARRAY_SIZE(s->cpu_irq_splitter); i++) {
395 if (irq_is_common[i]) {
396 char *name = g_strdup_printf("cpu-irq-splitter%d", i);
397 SplitIRQ *splitter = &s->cpu_irq_splitter[i];
398
399 object_initialize_child(obj, name, splitter, sizeof(*splitter),
400 TYPE_SPLIT_IRQ, &error_abort, NULL);
401 g_free(name);
402 }
403 }
404 }
405}
406
407static void armsse_exp_irq(void *opaque, int n, int level)
408{
409 qemu_irq *irqarray = opaque;
410
411 qemu_set_irq(irqarray[n], level);
412}
413
414static void armsse_mpcexp_status(void *opaque, int n, int level)
415{
416 ARMSSE *s = ARMSSE(opaque);
417 qemu_set_irq(s->mpcexp_status_in[n], level);
418}
419
420static qemu_irq armsse_get_common_irq_in(ARMSSE *s, int irqno)
421{
422
423
424
425
426 ARMSSEClass *asc = ARMSSE_GET_CLASS(s);
427 const ARMSSEInfo *info = asc->info;
428
429 assert(irq_is_common[irqno]);
430
431 if (info->num_cpus == 1) {
432
433 return qdev_get_gpio_in(DEVICE(&s->armv7m[0]), irqno);
434 } else {
435
436 return qdev_get_gpio_in(DEVICE(&s->cpu_irq_splitter[irqno]), 0);
437 }
438}
439
440static void map_ppu(ARMSSE *s, int ppuidx, const char *name, hwaddr addr)
441{
442
443 DeviceState *dev = DEVICE(&s->ppu[ppuidx]);
444
445 qdev_prop_set_string(dev, "name", name);
446 qdev_prop_set_uint64(dev, "size", 0x1000);
447 qdev_init_nofail(dev);
448 sysbus_mmio_map(SYS_BUS_DEVICE(&s->ppu[ppuidx]), 0, addr);
449}
450
451static void armsse_realize(DeviceState *dev, Error **errp)
452{
453 ARMSSE *s = ARMSSE(dev);
454 ARMSSEClass *asc = ARMSSE_GET_CLASS(dev);
455 const ARMSSEInfo *info = asc->info;
456 int i;
457 MemoryRegion *mr;
458 Error *err = NULL;
459 SysBusDevice *sbd_apb_ppc0;
460 SysBusDevice *sbd_secctl;
461 DeviceState *dev_apb_ppc0;
462 DeviceState *dev_apb_ppc1;
463 DeviceState *dev_secctl;
464 DeviceState *dev_splitter;
465 uint32_t addr_width_max;
466
467 if (!s->board_memory) {
468 error_setg(errp, "memory property was not set");
469 return;
470 }
471
472 if (!s->mainclk_frq) {
473 error_setg(errp, "MAINCLK property was not set");
474 return;
475 }
476
477
478 assert(is_power_of_2(info->sram_banks));
479 addr_width_max = 24 - ctz32(info->sram_banks);
480 if (s->sram_addr_width < 1 || s->sram_addr_width > addr_width_max) {
481 error_setg(errp, "SRAM_ADDR_WIDTH must be between 1 and %d",
482 addr_width_max);
483 return;
484 }
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522 memory_region_add_subregion_overlap(&s->container, 0, s->board_memory, -2);
523
524 for (i = 0; i < info->num_cpus; i++) {
525 DeviceState *cpudev = DEVICE(&s->armv7m[i]);
526 Object *cpuobj = OBJECT(&s->armv7m[i]);
527 int j;
528 char *gpioname;
529
530 qdev_prop_set_uint32(cpudev, "num-irq", s->exp_numirq + 32);
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548 qdev_prop_set_uint32(cpudev, "init-svtor", s->init_svtor);
549
550
551
552
553
554
555
556
557
558 if (extract32(info->cpuwait_rst, i, 1)) {
559 object_property_set_bool(cpuobj, true, "start-powered-off", &err);
560 if (err) {
561 error_propagate(errp, err);
562 return;
563 }
564 }
565 if (!s->cpu_fpu[i]) {
566 object_property_set_bool(cpuobj, false, "vfp", &err);
567 if (err) {
568 error_propagate(errp, err);
569 return;
570 }
571 }
572 if (!s->cpu_dsp[i]) {
573 object_property_set_bool(cpuobj, false, "dsp", &err);
574 if (err) {
575 error_propagate(errp, err);
576 return;
577 }
578 }
579
580 if (i > 0) {
581 memory_region_add_subregion_overlap(&s->cpu_container[i], 0,
582 &s->container_alias[i - 1], -1);
583 } else {
584 memory_region_add_subregion_overlap(&s->cpu_container[i], 0,
585 &s->container, -1);
586 }
587 object_property_set_link(cpuobj, OBJECT(&s->cpu_container[i]),
588 "memory", &err);
589 if (err) {
590 error_propagate(errp, err);
591 return;
592 }
593 object_property_set_link(cpuobj, OBJECT(s), "idau", &err);
594 if (err) {
595 error_propagate(errp, err);
596 return;
597 }
598 object_property_set_bool(cpuobj, true, "realized", &err);
599 if (err) {
600 error_propagate(errp, err);
601 return;
602 }
603
604
605
606
607
608
609 object_property_set_bool(OBJECT(&s->cluster[i]),
610 true, "realized", &err);
611 if (err) {
612 error_propagate(errp, err);
613 return;
614 }
615
616
617 s->exp_irqs[i] = g_new(qemu_irq, s->exp_numirq);
618 for (j = 0; j < s->exp_numirq; j++) {
619 s->exp_irqs[i][j] = qdev_get_gpio_in(cpudev, j + 32);
620 }
621 if (i == 0) {
622 gpioname = g_strdup("EXP_IRQ");
623 } else {
624 gpioname = g_strdup_printf("EXP_CPU%d_IRQ", i);
625 }
626 qdev_init_gpio_in_named_with_opaque(dev, armsse_exp_irq,
627 s->exp_irqs[i],
628 gpioname, s->exp_numirq);
629 g_free(gpioname);
630 }
631
632
633 if (info->num_cpus > 1) {
634 for (i = 0; i < ARRAY_SIZE(s->cpu_irq_splitter); i++) {
635 if (irq_is_common[i]) {
636 Object *splitter = OBJECT(&s->cpu_irq_splitter[i]);
637 DeviceState *devs = DEVICE(splitter);
638 int cpunum;
639
640 object_property_set_int(splitter, info->num_cpus,
641 "num-lines", &err);
642 if (err) {
643 error_propagate(errp, err);
644 return;
645 }
646 object_property_set_bool(splitter, true, "realized", &err);
647 if (err) {
648 error_propagate(errp, err);
649 return;
650 }
651 for (cpunum = 0; cpunum < info->num_cpus; cpunum++) {
652 DeviceState *cpudev = DEVICE(&s->armv7m[cpunum]);
653
654 qdev_connect_gpio_out(devs, cpunum,
655 qdev_get_gpio_in(cpudev, i));
656 }
657 }
658 }
659 }
660
661
662 make_alias(s, &s->alias1, &s->container, "alias 1",
663 0x10000000, 0x10000000, 0x00000000);
664 make_alias(s, &s->alias2, &s->container,
665 "alias 2", 0x30000000, 0x10000000, 0x20000000);
666
667
668
669
670
671
672
673 for (i = 0; i < info->num_cpus; i++) {
674 make_alias(s, &s->alias3[i], &s->cpu_container[i],
675 "alias 3", 0x50000000, 0x10000000, 0x40000000);
676 }
677
678
679 object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err);
680 if (err) {
681 error_propagate(errp, err);
682 return;
683 }
684 sbd_secctl = SYS_BUS_DEVICE(&s->secctl);
685 dev_secctl = DEVICE(&s->secctl);
686 sysbus_mmio_map(sbd_secctl, 0, 0x50080000);
687 sysbus_mmio_map(sbd_secctl, 1, 0x40080000);
688
689 s->nsc_cfg_in = qemu_allocate_irq(nsccfg_handler, s, 1);
690 qdev_connect_gpio_out_named(dev_secctl, "nsc_cfg", 0, s->nsc_cfg_in);
691
692
693
694
695
696 object_property_set_int(OBJECT(&s->sec_resp_splitter), 3,
697 "num-lines", &err);
698 if (err) {
699 error_propagate(errp, err);
700 return;
701 }
702 object_property_set_bool(OBJECT(&s->sec_resp_splitter), true,
703 "realized", &err);
704 if (err) {
705 error_propagate(errp, err);
706 return;
707 }
708 dev_splitter = DEVICE(&s->sec_resp_splitter);
709 qdev_connect_gpio_out_named(dev_secctl, "sec_resp_cfg", 0,
710 qdev_get_gpio_in(dev_splitter, 0));
711
712
713 for (i = 0; i < info->sram_banks; i++) {
714 char *ramname = g_strdup_printf("armsse.sram%d", i);
715 SysBusDevice *sbd_mpc;
716 uint32_t sram_bank_size = 1 << s->sram_addr_width;
717
718 memory_region_init_ram(&s->sram[i], NULL, ramname,
719 sram_bank_size, &err);
720 g_free(ramname);
721 if (err) {
722 error_propagate(errp, err);
723 return;
724 }
725 object_property_set_link(OBJECT(&s->mpc[i]), OBJECT(&s->sram[i]),
726 "downstream", &err);
727 if (err) {
728 error_propagate(errp, err);
729 return;
730 }
731 object_property_set_bool(OBJECT(&s->mpc[i]), true, "realized", &err);
732 if (err) {
733 error_propagate(errp, err);
734 return;
735 }
736
737 sbd_mpc = SYS_BUS_DEVICE(&s->mpc[i]);
738 memory_region_add_subregion(&s->container,
739 0x20000000 + i * sram_bank_size,
740 sysbus_mmio_get_region(sbd_mpc, 1));
741
742 memory_region_add_subregion(&s->container, 0x50083000 + i * 0x1000,
743 sysbus_mmio_get_region(sbd_mpc, 0));
744 }
745
746
747 object_property_set_int(OBJECT(&s->mpc_irq_orgate),
748 IOTS_NUM_EXP_MPC + info->sram_banks,
749 "num-lines", &err);
750 if (err) {
751 error_propagate(errp, err);
752 return;
753 }
754 object_property_set_bool(OBJECT(&s->mpc_irq_orgate), true,
755 "realized", &err);
756 if (err) {
757 error_propagate(errp, err);
758 return;
759 }
760 qdev_connect_gpio_out(DEVICE(&s->mpc_irq_orgate), 0,
761 armsse_get_common_irq_in(s, 9));
762
763
764
765
766
767
768
769
770
771
772
773 qdev_prop_set_uint32(DEVICE(&s->timer0), "pclk-frq", s->mainclk_frq);
774 object_property_set_bool(OBJECT(&s->timer0), true, "realized", &err);
775 if (err) {
776 error_propagate(errp, err);
777 return;
778 }
779 sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer0), 0,
780 armsse_get_common_irq_in(s, 3));
781 mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer0), 0);
782 object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[0]", &err);
783 if (err) {
784 error_propagate(errp, err);
785 return;
786 }
787
788 qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq);
789 object_property_set_bool(OBJECT(&s->timer1), true, "realized", &err);
790 if (err) {
791 error_propagate(errp, err);
792 return;
793 }
794 sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer1), 0,
795 armsse_get_common_irq_in(s, 4));
796 mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer1), 0);
797 object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[1]", &err);
798 if (err) {
799 error_propagate(errp, err);
800 return;
801 }
802
803
804 qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq);
805 object_property_set_bool(OBJECT(&s->dualtimer), true, "realized", &err);
806 if (err) {
807 error_propagate(errp, err);
808 return;
809 }
810 sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0,
811 armsse_get_common_irq_in(s, 5));
812 mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0);
813 object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", &err);
814 if (err) {
815 error_propagate(errp, err);
816 return;
817 }
818
819 if (info->has_mhus) {
820
821
822
823
824
825
826
827 assert(info->num_cpus == ARRAY_SIZE(s->mhu));
828
829 for (i = 0; i < ARRAY_SIZE(s->mhu); i++) {
830 char *port;
831 int cpunum;
832 SysBusDevice *mhu_sbd = SYS_BUS_DEVICE(&s->mhu[i]);
833
834 object_property_set_bool(OBJECT(&s->mhu[i]), true,
835 "realized", &err);
836 if (err) {
837 error_propagate(errp, err);
838 return;
839 }
840 port = g_strdup_printf("port[%d]", i + 3);
841 mr = sysbus_mmio_get_region(mhu_sbd, 0);
842 object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr),
843 port, &err);
844 g_free(port);
845 if (err) {
846 error_propagate(errp, err);
847 return;
848 }
849
850
851
852
853
854
855
856
857 for (cpunum = 0; cpunum < info->num_cpus; cpunum++) {
858 DeviceState *cpudev = DEVICE(&s->armv7m[cpunum]);
859
860 sysbus_connect_irq(mhu_sbd, cpunum,
861 qdev_get_gpio_in(cpudev, 6 + i));
862 }
863 }
864 }
865
866 object_property_set_bool(OBJECT(&s->apb_ppc0), true, "realized", &err);
867 if (err) {
868 error_propagate(errp, err);
869 return;
870 }
871
872 sbd_apb_ppc0 = SYS_BUS_DEVICE(&s->apb_ppc0);
873 dev_apb_ppc0 = DEVICE(&s->apb_ppc0);
874
875 mr = sysbus_mmio_get_region(sbd_apb_ppc0, 0);
876 memory_region_add_subregion(&s->container, 0x40000000, mr);
877 mr = sysbus_mmio_get_region(sbd_apb_ppc0, 1);
878 memory_region_add_subregion(&s->container, 0x40001000, mr);
879 mr = sysbus_mmio_get_region(sbd_apb_ppc0, 2);
880 memory_region_add_subregion(&s->container, 0x40002000, mr);
881 if (info->has_mhus) {
882 mr = sysbus_mmio_get_region(sbd_apb_ppc0, 3);
883 memory_region_add_subregion(&s->container, 0x40003000, mr);
884 mr = sysbus_mmio_get_region(sbd_apb_ppc0, 4);
885 memory_region_add_subregion(&s->container, 0x40004000, mr);
886 }
887 for (i = 0; i < IOTS_APB_PPC0_NUM_PORTS; i++) {
888 qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_nonsec", i,
889 qdev_get_gpio_in_named(dev_apb_ppc0,
890 "cfg_nonsec", i));
891 qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_ap", i,
892 qdev_get_gpio_in_named(dev_apb_ppc0,
893 "cfg_ap", i));
894 }
895 qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_irq_enable", 0,
896 qdev_get_gpio_in_named(dev_apb_ppc0,
897 "irq_enable", 0));
898 qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_irq_clear", 0,
899 qdev_get_gpio_in_named(dev_apb_ppc0,
900 "irq_clear", 0));
901 qdev_connect_gpio_out(dev_splitter, 0,
902 qdev_get_gpio_in_named(dev_apb_ppc0,
903 "cfg_sec_resp", 0));
904
905
906
907
908
909 object_property_set_int(OBJECT(&s->ppc_irq_orgate),
910 NUM_PPCS, "num-lines", &err);
911 if (err) {
912 error_propagate(errp, err);
913 return;
914 }
915 object_property_set_bool(OBJECT(&s->ppc_irq_orgate), true,
916 "realized", &err);
917 if (err) {
918 error_propagate(errp, err);
919 return;
920 }
921 qdev_connect_gpio_out(DEVICE(&s->ppc_irq_orgate), 0,
922 armsse_get_common_irq_in(s, 10));
923
924
925
926
927
928
929
930
931 if (info->has_cachectrl) {
932 for (i = 0; i < info->num_cpus; i++) {
933 char *name = g_strdup_printf("cachectrl%d", i);
934 MemoryRegion *mr;
935
936 qdev_prop_set_string(DEVICE(&s->cachectrl[i]), "name", name);
937 g_free(name);
938 qdev_prop_set_uint64(DEVICE(&s->cachectrl[i]), "size", 0x1000);
939 object_property_set_bool(OBJECT(&s->cachectrl[i]), true,
940 "realized", &err);
941 if (err) {
942 error_propagate(errp, err);
943 return;
944 }
945
946 mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cachectrl[i]), 0);
947 memory_region_add_subregion(&s->cpu_container[i], 0x50010000, mr);
948 }
949 }
950 if (info->has_cpusecctrl) {
951 for (i = 0; i < info->num_cpus; i++) {
952 char *name = g_strdup_printf("CPUSECCTRL%d", i);
953 MemoryRegion *mr;
954
955 qdev_prop_set_string(DEVICE(&s->cpusecctrl[i]), "name", name);
956 g_free(name);
957 qdev_prop_set_uint64(DEVICE(&s->cpusecctrl[i]), "size", 0x1000);
958 object_property_set_bool(OBJECT(&s->cpusecctrl[i]), true,
959 "realized", &err);
960 if (err) {
961 error_propagate(errp, err);
962 return;
963 }
964
965 mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpusecctrl[i]), 0);
966 memory_region_add_subregion(&s->cpu_container[i], 0x50011000, mr);
967 }
968 }
969 if (info->has_cpuid) {
970 for (i = 0; i < info->num_cpus; i++) {
971 MemoryRegion *mr;
972
973 qdev_prop_set_uint32(DEVICE(&s->cpuid[i]), "CPUID", i);
974 object_property_set_bool(OBJECT(&s->cpuid[i]), true,
975 "realized", &err);
976 if (err) {
977 error_propagate(errp, err);
978 return;
979 }
980
981 mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpuid[i]), 0);
982 memory_region_add_subregion(&s->cpu_container[i], 0x4001F000, mr);
983 }
984 }
985
986
987
988
989
990 qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK);
991 object_property_set_bool(OBJECT(&s->s32ktimer), true, "realized", &err);
992 if (err) {
993 error_propagate(errp, err);
994 return;
995 }
996 sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0,
997 armsse_get_common_irq_in(s, 2));
998 mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0);
999 object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err);
1000 if (err) {
1001 error_propagate(errp, err);
1002 return;
1003 }
1004
1005 object_property_set_bool(OBJECT(&s->apb_ppc1), true, "realized", &err);
1006 if (err) {
1007 error_propagate(errp, err);
1008 return;
1009 }
1010 mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->apb_ppc1), 0);
1011 memory_region_add_subregion(&s->container, 0x4002f000, mr);
1012
1013 dev_apb_ppc1 = DEVICE(&s->apb_ppc1);
1014 qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_nonsec", 0,
1015 qdev_get_gpio_in_named(dev_apb_ppc1,
1016 "cfg_nonsec", 0));
1017 qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_ap", 0,
1018 qdev_get_gpio_in_named(dev_apb_ppc1,
1019 "cfg_ap", 0));
1020 qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_irq_enable", 0,
1021 qdev_get_gpio_in_named(dev_apb_ppc1,
1022 "irq_enable", 0));
1023 qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_irq_clear", 0,
1024 qdev_get_gpio_in_named(dev_apb_ppc1,
1025 "irq_clear", 0));
1026 qdev_connect_gpio_out(dev_splitter, 1,
1027 qdev_get_gpio_in_named(dev_apb_ppc1,
1028 "cfg_sec_resp", 0));
1029
1030 object_property_set_int(OBJECT(&s->sysinfo), info->sys_version,
1031 "SYS_VERSION", &err);
1032 if (err) {
1033 error_propagate(errp, err);
1034 return;
1035 }
1036 object_property_set_int(OBJECT(&s->sysinfo),
1037 armsse_sys_config_value(s, info),
1038 "SYS_CONFIG", &err);
1039 if (err) {
1040 error_propagate(errp, err);
1041 return;
1042 }
1043 object_property_set_bool(OBJECT(&s->sysinfo), true, "realized", &err);
1044 if (err) {
1045 error_propagate(errp, err);
1046 return;
1047 }
1048
1049 sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000);
1050
1051 object_property_set_int(OBJECT(&s->sysctl), info->sys_version,
1052 "SYS_VERSION", &err);
1053 object_property_set_int(OBJECT(&s->sysctl), info->cpuwait_rst,
1054 "CPUWAIT_RST", &err);
1055 object_property_set_int(OBJECT(&s->sysctl), s->init_svtor,
1056 "INITSVTOR0_RST", &err);
1057 object_property_set_int(OBJECT(&s->sysctl), s->init_svtor,
1058 "INITSVTOR1_RST", &err);
1059 object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err);
1060 if (err) {
1061 error_propagate(errp, err);
1062 return;
1063 }
1064 sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x50021000);
1065
1066 if (info->has_ppus) {
1067
1068 for (i = 0; i < info->num_cpus; i++) {
1069 char *name = g_strdup_printf("CPU%dCORE_PPU", i);
1070
1071 map_ppu(s, CPU0CORE_PPU + i, name, 0x50023000 + i * 0x2000);
1072
1073
1074
1075
1076 g_free(name);
1077 }
1078 map_ppu(s, DBG_PPU, "DBG_PPU", 0x50029000);
1079
1080 for (i = 0; i < info->sram_banks; i++) {
1081 char *name = g_strdup_printf("RAM%d_PPU", i);
1082
1083 map_ppu(s, RAM0_PPU + i, name, 0x5002a000 + i * 0x1000);
1084 g_free(name);
1085 }
1086 }
1087
1088
1089 object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err);
1090 if (err) {
1091 error_propagate(errp, err);
1092 return;
1093 }
1094 object_property_set_bool(OBJECT(&s->nmi_orgate), true, "realized", &err);
1095 if (err) {
1096 error_propagate(errp, err);
1097 return;
1098 }
1099 qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0,
1100 qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0));
1101
1102 qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK);
1103 object_property_set_bool(OBJECT(&s->s32kwatchdog), true, "realized", &err);
1104 if (err) {
1105 error_propagate(errp, err);
1106 return;
1107 }
1108 sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32kwatchdog), 0,
1109 qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 0));
1110 sysbus_mmio_map(SYS_BUS_DEVICE(&s->s32kwatchdog), 0, 0x5002e000);
1111
1112
1113
1114 qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq);
1115 object_property_set_bool(OBJECT(&s->nswatchdog), true, "realized", &err);
1116 if (err) {
1117 error_propagate(errp, err);
1118 return;
1119 }
1120 sysbus_connect_irq(SYS_BUS_DEVICE(&s->nswatchdog), 0,
1121 armsse_get_common_irq_in(s, 1));
1122 sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000);
1123
1124 qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq);
1125 object_property_set_bool(OBJECT(&s->swatchdog), true, "realized", &err);
1126 if (err) {
1127 error_propagate(errp, err);
1128 return;
1129 }
1130 sysbus_connect_irq(SYS_BUS_DEVICE(&s->swatchdog), 0,
1131 qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 1));
1132 sysbus_mmio_map(SYS_BUS_DEVICE(&s->swatchdog), 0, 0x50081000);
1133
1134 for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
1135 Object *splitter = OBJECT(&s->ppc_irq_splitter[i]);
1136
1137 object_property_set_int(splitter, 2, "num-lines", &err);
1138 if (err) {
1139 error_propagate(errp, err);
1140 return;
1141 }
1142 object_property_set_bool(splitter, true, "realized", &err);
1143 if (err) {
1144 error_propagate(errp, err);
1145 return;
1146 }
1147 }
1148
1149 for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) {
1150 char *ppcname = g_strdup_printf("ahb_ppcexp%d", i);
1151
1152 armsse_forward_ppc(s, ppcname, i);
1153 g_free(ppcname);
1154 }
1155
1156 for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) {
1157 char *ppcname = g_strdup_printf("apb_ppcexp%d", i);
1158
1159 armsse_forward_ppc(s, ppcname, i + IOTS_NUM_AHB_EXP_PPC);
1160 g_free(ppcname);
1161 }
1162
1163 for (i = NUM_EXTERNAL_PPCS; i < NUM_PPCS; i++) {
1164
1165 DeviceState *devs = DEVICE(&s->ppc_irq_splitter[i]);
1166 char *gpioname = g_strdup_printf("apb_ppc%d_irq_status",
1167 i - NUM_EXTERNAL_PPCS);
1168 TZPPC *ppc = (i == NUM_EXTERNAL_PPCS) ? &s->apb_ppc0 : &s->apb_ppc1;
1169
1170 qdev_connect_gpio_out(devs, 0,
1171 qdev_get_gpio_in_named(dev_secctl, gpioname, 0));
1172 qdev_connect_gpio_out(devs, 1,
1173 qdev_get_gpio_in(DEVICE(&s->ppc_irq_orgate), i));
1174 qdev_connect_gpio_out_named(DEVICE(ppc), "irq", 0,
1175 qdev_get_gpio_in(devs, 0));
1176 g_free(gpioname);
1177 }
1178
1179
1180 for (i = 0; i < IOTS_NUM_EXP_MPC + info->sram_banks; i++) {
1181 SplitIRQ *splitter = &s->mpc_irq_splitter[i];
1182 DeviceState *dev_splitter = DEVICE(splitter);
1183
1184 object_property_set_int(OBJECT(splitter), 2, "num-lines", &err);
1185 if (err) {
1186 error_propagate(errp, err);
1187 return;
1188 }
1189 object_property_set_bool(OBJECT(splitter), true, "realized", &err);
1190 if (err) {
1191 error_propagate(errp, err);
1192 return;
1193 }
1194
1195 if (i < IOTS_NUM_EXP_MPC) {
1196
1197 s->mpcexp_status_in[i] = qdev_get_gpio_in(dev_splitter, 0);
1198 qdev_connect_gpio_out(dev_splitter, 0,
1199 qdev_get_gpio_in_named(dev_secctl,
1200 "mpcexp_status", i));
1201 } else {
1202
1203 qdev_connect_gpio_out_named(DEVICE(&s->mpc[i - IOTS_NUM_EXP_MPC]),
1204 "irq", 0,
1205 qdev_get_gpio_in(dev_splitter, 0));
1206 qdev_connect_gpio_out(dev_splitter, 0,
1207 qdev_get_gpio_in_named(dev_secctl,
1208 "mpc_status", 0));
1209 }
1210
1211 qdev_connect_gpio_out(dev_splitter, 1,
1212 qdev_get_gpio_in(DEVICE(&s->mpc_irq_orgate), i));
1213 }
1214
1215
1216
1217 qdev_init_gpio_in_named(dev, armsse_mpcexp_status, "mpcexp_status",
1218 IOTS_NUM_EXP_MPC);
1219
1220 armsse_forward_sec_resp_cfg(s);
1221
1222
1223 qdev_pass_gpios(dev_secctl, dev, "mscexp_status");
1224 qdev_pass_gpios(dev_secctl, dev, "mscexp_clear");
1225 qdev_pass_gpios(dev_secctl, dev, "mscexp_ns");
1226 qdev_connect_gpio_out_named(dev_secctl, "msc_irq", 0,
1227 armsse_get_common_irq_in(s, 11));
1228
1229
1230
1231
1232
1233
1234
1235 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
1236
1237 system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq;
1238}
1239
1240static void armsse_idau_check(IDAUInterface *ii, uint32_t address,
1241 int *iregion, bool *exempt, bool *ns, bool *nsc)
1242{
1243
1244
1245
1246
1247
1248 ARMSSE *s = ARMSSE(ii);
1249 int region = extract32(address, 28, 4);
1250
1251 *ns = !(region & 1);
1252 *nsc = (region == 1 && (s->nsccfg & 1)) || (region == 3 && (s->nsccfg & 2));
1253
1254 *exempt = (address & 0xeff00000) == 0xe0000000;
1255 *iregion = region;
1256}
1257
1258static const VMStateDescription armsse_vmstate = {
1259 .name = "iotkit",
1260 .version_id = 1,
1261 .minimum_version_id = 1,
1262 .fields = (VMStateField[]) {
1263 VMSTATE_UINT32(nsccfg, ARMSSE),
1264 VMSTATE_END_OF_LIST()
1265 }
1266};
1267
1268static void armsse_reset(DeviceState *dev)
1269{
1270 ARMSSE *s = ARMSSE(dev);
1271
1272 s->nsccfg = 0;
1273}
1274
1275static void armsse_class_init(ObjectClass *klass, void *data)
1276{
1277 DeviceClass *dc = DEVICE_CLASS(klass);
1278 IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(klass);
1279 ARMSSEClass *asc = ARMSSE_CLASS(klass);
1280 const ARMSSEInfo *info = data;
1281
1282 dc->realize = armsse_realize;
1283 dc->vmsd = &armsse_vmstate;
1284 dc->props = info->props;
1285 dc->reset = armsse_reset;
1286 iic->check = armsse_idau_check;
1287 asc->info = info;
1288}
1289
1290static const TypeInfo armsse_info = {
1291 .name = TYPE_ARMSSE,
1292 .parent = TYPE_SYS_BUS_DEVICE,
1293 .instance_size = sizeof(ARMSSE),
1294 .instance_init = armsse_init,
1295 .abstract = true,
1296 .interfaces = (InterfaceInfo[]) {
1297 { TYPE_IDAU_INTERFACE },
1298 { }
1299 }
1300};
1301
1302static void armsse_register_types(void)
1303{
1304 int i;
1305
1306 type_register_static(&armsse_info);
1307
1308 for (i = 0; i < ARRAY_SIZE(armsse_variants); i++) {
1309 TypeInfo ti = {
1310 .name = armsse_variants[i].name,
1311 .parent = TYPE_ARMSSE,
1312 .class_init = armsse_class_init,
1313 .class_data = (void *)&armsse_variants[i],
1314 };
1315 type_register(&ti);
1316 }
1317}
1318
1319type_init(armsse_register_types);
1320