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