2 * Xilinx Versal SoC model.
4 * Copyright (c) 2018 Xilinx Inc.
5 * Written by Edgar E. Iglesias
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.
12 #include "qemu/osdep.h"
13 #include "qapi/error.h"
14 #include "qemu-common.h"
16 #include "hw/sysbus.h"
18 #include "sysemu/sysemu.h"
19 #include "sysemu/kvm.h"
20 #include "hw/arm/arm.h"
22 #include "hw/misc/unimp.h"
23 #include "hw/intc/arm_gicv3_common.h"
24 #include "hw/arm/xlnx-versal.h"
26 #define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72")
27 #define GEM_REVISION 0x40070106
29 static void versal_create_apu_cpus(Versal
*s
)
33 for (i
= 0; i
< ARRAY_SIZE(s
->fpd
.apu
.cpu
); i
++) {
37 obj
= object_new(XLNX_VERSAL_ACPU_TYPE
);
39 /* Secondary CPUs start in PSCI powered-down state */
40 error_report("Unable to create apu.cpu[%d] of type %s",
41 i
, XLNX_VERSAL_ACPU_TYPE
);
45 name
= g_strdup_printf("apu-cpu[%d]", i
);
46 object_property_add_child(OBJECT(s
), name
, obj
, &error_fatal
);
49 object_property_set_int(obj
, s
->cfg
.psci_conduit
,
50 "psci-conduit", &error_abort
);
52 object_property_set_bool(obj
, true,
53 "start-powered-off", &error_abort
);
56 object_property_set_int(obj
, ARRAY_SIZE(s
->fpd
.apu
.cpu
),
57 "core-count", &error_abort
);
58 object_property_set_link(obj
, OBJECT(&s
->fpd
.apu
.mr
), "memory",
60 object_property_set_bool(obj
, true, "realized", &error_fatal
);
61 s
->fpd
.apu
.cpu
[i
] = ARM_CPU(obj
);
65 static void versal_create_apu_gic(Versal
*s
, qemu_irq
*pic
)
67 static const uint64_t addrs
[] = {
71 SysBusDevice
*gicbusdev
;
73 int nr_apu_cpus
= ARRAY_SIZE(s
->fpd
.apu
.cpu
);
76 sysbus_init_child_obj(OBJECT(s
), "apu-gic",
77 &s
->fpd
.apu
.gic
, sizeof(s
->fpd
.apu
.gic
),
79 gicbusdev
= SYS_BUS_DEVICE(&s
->fpd
.apu
.gic
);
80 gicdev
= DEVICE(&s
->fpd
.apu
.gic
);
81 qdev_prop_set_uint32(gicdev
, "revision", 3);
82 qdev_prop_set_uint32(gicdev
, "num-cpu", 2);
83 qdev_prop_set_uint32(gicdev
, "num-irq", XLNX_VERSAL_NR_IRQS
+ 32);
84 qdev_prop_set_uint32(gicdev
, "len-redist-region-count", 1);
85 qdev_prop_set_uint32(gicdev
, "redist-region-count[0]", 2);
86 qdev_prop_set_bit(gicdev
, "has-security-extensions", true);
88 object_property_set_bool(OBJECT(&s
->fpd
.apu
.gic
), true, "realized",
91 for (i
= 0; i
< ARRAY_SIZE(addrs
); i
++) {
94 mr
= sysbus_mmio_get_region(gicbusdev
, i
);
95 memory_region_add_subregion(&s
->fpd
.apu
.mr
, addrs
[i
], mr
);
98 for (i
= 0; i
< nr_apu_cpus
; i
++) {
99 DeviceState
*cpudev
= DEVICE(s
->fpd
.apu
.cpu
[i
]);
100 int ppibase
= XLNX_VERSAL_NR_IRQS
+ i
* GIC_INTERNAL
+ GIC_NR_SGIS
;
103 /* Mapping from the output timer irq lines from the CPU to the
106 const int timer_irq
[] = {
107 [GTIMER_PHYS
] = VERSAL_TIMER_NS_EL1_IRQ
,
108 [GTIMER_VIRT
] = VERSAL_TIMER_VIRT_IRQ
,
109 [GTIMER_HYP
] = VERSAL_TIMER_NS_EL2_IRQ
,
110 [GTIMER_SEC
] = VERSAL_TIMER_S_EL1_IRQ
,
113 for (ti
= 0; ti
< ARRAY_SIZE(timer_irq
); ti
++) {
114 qdev_connect_gpio_out(cpudev
, ti
,
115 qdev_get_gpio_in(gicdev
,
116 ppibase
+ timer_irq
[ti
]));
118 maint_irq
= qdev_get_gpio_in(gicdev
,
119 ppibase
+ VERSAL_GIC_MAINT_IRQ
);
120 qdev_connect_gpio_out_named(cpudev
, "gicv3-maintenance-interrupt",
122 sysbus_connect_irq(gicbusdev
, i
, qdev_get_gpio_in(cpudev
, ARM_CPU_IRQ
));
123 sysbus_connect_irq(gicbusdev
, i
+ nr_apu_cpus
,
124 qdev_get_gpio_in(cpudev
, ARM_CPU_FIQ
));
125 sysbus_connect_irq(gicbusdev
, i
+ 2 * nr_apu_cpus
,
126 qdev_get_gpio_in(cpudev
, ARM_CPU_VIRQ
));
127 sysbus_connect_irq(gicbusdev
, i
+ 3 * nr_apu_cpus
,
128 qdev_get_gpio_in(cpudev
, ARM_CPU_VFIQ
));
131 for (i
= 0; i
< XLNX_VERSAL_NR_IRQS
; i
++) {
132 pic
[i
] = qdev_get_gpio_in(gicdev
, i
);
136 static void versal_create_uarts(Versal
*s
, qemu_irq
*pic
)
140 for (i
= 0; i
< ARRAY_SIZE(s
->lpd
.iou
.uart
); i
++) {
141 static const int irqs
[] = { VERSAL_UART0_IRQ_0
, VERSAL_UART1_IRQ_0
};
142 static const uint64_t addrs
[] = { MM_UART0
, MM_UART1
};
143 char *name
= g_strdup_printf("uart%d", i
);
147 dev
= qdev_create(NULL
, "pl011");
148 s
->lpd
.iou
.uart
[i
] = SYS_BUS_DEVICE(dev
);
149 qdev_prop_set_chr(dev
, "chardev", serial_hd(i
));
150 object_property_add_child(OBJECT(s
), name
, OBJECT(dev
), &error_fatal
);
151 qdev_init_nofail(dev
);
153 mr
= sysbus_mmio_get_region(s
->lpd
.iou
.uart
[i
], 0);
154 memory_region_add_subregion(&s
->mr_ps
, addrs
[i
], mr
);
156 sysbus_connect_irq(s
->lpd
.iou
.uart
[i
], 0, pic
[irqs
[i
]]);
161 static void versal_create_gems(Versal
*s
, qemu_irq
*pic
)
165 for (i
= 0; i
< ARRAY_SIZE(s
->lpd
.iou
.gem
); i
++) {
166 static const int irqs
[] = { VERSAL_GEM0_IRQ_0
, VERSAL_GEM1_IRQ_0
};
167 static const uint64_t addrs
[] = { MM_GEM0
, MM_GEM1
};
168 char *name
= g_strdup_printf("gem%d", i
);
169 NICInfo
*nd
= &nd_table
[i
];
173 dev
= qdev_create(NULL
, "cadence_gem");
174 s
->lpd
.iou
.gem
[i
] = SYS_BUS_DEVICE(dev
);
175 object_property_add_child(OBJECT(s
), name
, OBJECT(dev
), &error_fatal
);
177 qemu_check_nic_model(nd
, "cadence_gem");
178 qdev_set_nic_properties(dev
, nd
);
180 object_property_set_int(OBJECT(s
->lpd
.iou
.gem
[i
]),
181 2, "num-priority-queues",
183 object_property_set_link(OBJECT(s
->lpd
.iou
.gem
[i
]),
184 OBJECT(&s
->mr_ps
), "dma",
186 qdev_init_nofail(dev
);
188 mr
= sysbus_mmio_get_region(s
->lpd
.iou
.gem
[i
], 0);
189 memory_region_add_subregion(&s
->mr_ps
, addrs
[i
], mr
);
191 sysbus_connect_irq(s
->lpd
.iou
.gem
[i
], 0, pic
[irqs
[i
]]);
196 /* This takes the board allocated linear DDR memory and creates aliases
197 * for each split DDR range/aperture on the Versal address map.
199 static void versal_map_ddr(Versal
*s
)
201 uint64_t size
= memory_region_size(s
->cfg
.mr_ddr
);
202 /* Describes the various split DDR access regions. */
203 static const struct {
207 { MM_TOP_DDR
, MM_TOP_DDR_SIZE
},
208 { MM_TOP_DDR_2
, MM_TOP_DDR_2_SIZE
},
209 { MM_TOP_DDR_3
, MM_TOP_DDR_3_SIZE
},
210 { MM_TOP_DDR_4
, MM_TOP_DDR_4_SIZE
}
215 assert(ARRAY_SIZE(addr_ranges
) == ARRAY_SIZE(s
->noc
.mr_ddr_ranges
));
216 for (i
= 0; i
< ARRAY_SIZE(addr_ranges
) && size
; i
++) {
220 mapsize
= size
< addr_ranges
[i
].size
? size
: addr_ranges
[i
].size
;
221 name
= g_strdup_printf("noc-ddr-range%d", i
);
222 /* Create the MR alias. */
223 memory_region_init_alias(&s
->noc
.mr_ddr_ranges
[i
], OBJECT(s
),
227 /* Map it onto the NoC MR. */
228 memory_region_add_subregion(&s
->mr_ps
, addr_ranges
[i
].base
,
229 &s
->noc
.mr_ddr_ranges
[i
]);
236 static void versal_unimp_area(Versal
*s
, const char *name
,
238 hwaddr base
, hwaddr size
)
240 DeviceState
*dev
= qdev_create(NULL
, TYPE_UNIMPLEMENTED_DEVICE
);
241 MemoryRegion
*mr_dev
;
243 qdev_prop_set_string(dev
, "name", name
);
244 qdev_prop_set_uint64(dev
, "size", size
);
245 object_property_add_child(OBJECT(s
), name
, OBJECT(dev
), &error_fatal
);
246 qdev_init_nofail(dev
);
248 mr_dev
= sysbus_mmio_get_region(SYS_BUS_DEVICE(dev
), 0);
249 memory_region_add_subregion(mr
, base
, mr_dev
);
252 static void versal_unimp(Versal
*s
)
254 versal_unimp_area(s
, "psm", &s
->mr_ps
,
255 MM_PSM_START
, MM_PSM_END
- MM_PSM_START
);
256 versal_unimp_area(s
, "crl", &s
->mr_ps
,
257 MM_CRL
, MM_CRL_SIZE
);
258 versal_unimp_area(s
, "crf", &s
->mr_ps
,
259 MM_FPD_CRF
, MM_FPD_CRF_SIZE
);
260 versal_unimp_area(s
, "iou-scntr", &s
->mr_ps
,
261 MM_IOU_SCNTR
, MM_IOU_SCNTR_SIZE
);
262 versal_unimp_area(s
, "iou-scntr-seucre", &s
->mr_ps
,
263 MM_IOU_SCNTRS
, MM_IOU_SCNTRS_SIZE
);
266 static void versal_realize(DeviceState
*dev
, Error
**errp
)
268 Versal
*s
= XLNX_VERSAL(dev
);
269 qemu_irq pic
[XLNX_VERSAL_NR_IRQS
];
271 versal_create_apu_cpus(s
);
272 versal_create_apu_gic(s
, pic
);
273 versal_create_uarts(s
, pic
);
274 versal_create_gems(s
, pic
);
278 /* Create the On Chip Memory (OCM). */
279 memory_region_init_ram(&s
->lpd
.mr_ocm
, OBJECT(s
), "ocm",
280 MM_OCM_SIZE
, &error_fatal
);
282 memory_region_add_subregion_overlap(&s
->mr_ps
, MM_OCM
, &s
->lpd
.mr_ocm
, 0);
283 memory_region_add_subregion_overlap(&s
->fpd
.apu
.mr
, 0, &s
->mr_ps
, 0);
286 static void versal_init(Object
*obj
)
288 Versal
*s
= XLNX_VERSAL(obj
);
290 memory_region_init(&s
->fpd
.apu
.mr
, obj
, "mr-apu", UINT64_MAX
);
291 memory_region_init(&s
->mr_ps
, obj
, "mr-ps-switch", UINT64_MAX
);
294 static Property versal_properties
[] = {
295 DEFINE_PROP_LINK("ddr", Versal
, cfg
.mr_ddr
, TYPE_MEMORY_REGION
,
297 DEFINE_PROP_UINT32("psci-conduit", Versal
, cfg
.psci_conduit
, 0),
298 DEFINE_PROP_END_OF_LIST()
301 static void versal_class_init(ObjectClass
*klass
, void *data
)
303 DeviceClass
*dc
= DEVICE_CLASS(klass
);
305 dc
->realize
= versal_realize
;
306 dc
->props
= versal_properties
;
307 /* No VMSD since we haven't got any top-level SoC state to save. */
310 static const TypeInfo versal_info
= {
311 .name
= TYPE_XLNX_VERSAL
,
312 .parent
= TYPE_SYS_BUS_DEVICE
,
313 .instance_size
= sizeof(Versal
),
314 .instance_init
= versal_init
,
315 .class_init
= versal_class_init
,
318 static void versal_register_types(void)
320 type_register_static(&versal_info
);
323 type_init(versal_register_types
);