On Wed, Jul 16, 2025 at 11:54:23AM +0200, Luc Michel wrote:
> Add the Versal Gen 2 (versal2) version of the Versal SoC family.
> This version embeds up to 8 Cortex-A78AE cores (split into 4 clusters)
> and 10 Cortex-R52 cores (split into 5 clusters). The similarities
> between versal and versal2 in term of architecture allow to reuse the
> VersalMap structure to almost fully describe the implemented parts of
> versal2.
>
> The versal2 eFuse device differs quite a lot from the versal one and is
> left as future work.
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
Reviewed-by: Francisco Iglesias <francisco.iglesias@amd.com>
> ---
> include/hw/arm/xlnx-versal.h | 17 ++-
> hw/arm/xlnx-versal.c | 212 ++++++++++++++++++++++++++++++++---
> 2 files changed, 214 insertions(+), 15 deletions(-)
>
> diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h
> index bdfab2a5426..1d216b5dbf1 100644
> --- a/include/hw/arm/xlnx-versal.h
> +++ b/include/hw/arm/xlnx-versal.h
> @@ -1,7 +1,7 @@
> /*
> - * Model of the Xilinx Versal
> + * AMD/Xilinx Versal family SoC model.
> *
> * Copyright (c) 2018 Xilinx Inc.
> * Copyright (c) 2025 Advanced Micro Devices, Inc.
> * Written by Edgar E. Iglesias
> *
> @@ -20,10 +20,11 @@
>
> #define TYPE_XLNX_VERSAL_BASE "xlnx-versal-base"
> OBJECT_DECLARE_TYPE(Versal, VersalClass, XLNX_VERSAL_BASE)
>
> #define TYPE_XLNX_VERSAL "xlnx-versal"
> +#define TYPE_XLNX_VERSAL2 "xlnx-versal2"
>
> struct Versal {
> /*< private >*/
> SysBusDevice parent_obj;
>
> @@ -69,6 +70,20 @@ hwaddr versal_get_reserved_mmio_addr(Versal *s);
>
> int versal_get_num_cpu(VersalVersion version);
> int versal_get_num_can(VersalVersion version);
> int versal_get_num_sdhci(VersalVersion version);
>
> +static inline const char *versal_get_class(VersalVersion version)
> +{
> + switch (version) {
> + case VERSAL_VER_VERSAL:
> + return TYPE_XLNX_VERSAL;
> +
> + case VERSAL_VER_VERSAL2:
> + return TYPE_XLNX_VERSAL2;
> +
> + default:
> + g_assert_not_reached();
> + }
> +}
> +
> #endif
> diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
> index 551671af425..52a68e356b0 100644
> --- a/hw/arm/xlnx-versal.c
> +++ b/hw/arm/xlnx-versal.c
> @@ -1,7 +1,7 @@
> /*
> - * Xilinx Versal SoC model.
> + * AMD/Xilinx Versal family SoC model.
> *
> * Copyright (c) 2018 Xilinx Inc.
> * Copyright (c) 2025 Advanced Micro Devices, Inc.
> * Written by Edgar E. Iglesias
> *
> @@ -353,12 +353,133 @@ static const VersalMap VERSAL_MAP = {
> .crl = { 0xff5e0000, 10 },
>
> .reserved = { 0xa0000000, 111, 8 },
> };
>
> +static const VersalMap VERSAL2_MAP = {
> + .ocm = {
> + .addr = 0xbbe00000,
> + .size = 2 * MiB,
> + },
> +
> + .ddr = {
> + .chan[0] = { .addr = 0x0, .size = 2046 * MiB },
> + .chan[1] = { .addr = 0x800000000ull, .size = 32 * GiB },
> + .chan[2] = { .addr = 0xc00000000ull, .size = 256 * GiB },
> + .chan[3] = { .addr = 0x10000000000ull, .size = 734 * GiB },
> + .num_chan = 4,
> + },
> +
> + .apu = {
> + .name = "apu",
> + .cpu_model = ARM_CPU_TYPE_NAME("cortex-a78ae"),
> + .num_cluster = 4,
> + .num_core = 2,
> + .qemu_cluster_id = 0,
> + .mp_affinity = {
> + .base = 0x0, /* TODO: the MT bit should be set */
> + .core_mask = 0xff,
> + .core_shift = 8,
> + .cluster_mask = 0xff,
> + .cluster_shift = 16,
> + },
> + .start_powered_off = SPO_SECONDARIES,
> + .dtb_expose = true,
> + .gic = {
> + .version = 3,
> + .dist = 0xe2000000,
> + .redist = 0xe2060000,
> + .num_irq = 544,
> + .has_its = true,
> + .its = 0xe2040000,
> + },
> + },
> +
> + .rpu = {
> + .name = "rpu",
> + .cpu_model = ARM_CPU_TYPE_NAME("cortex-r52"),
> + .num_cluster = 5,
> + .num_core = 2,
> + .qemu_cluster_id = 1,
> + .mp_affinity = {
> + .base = 0x0,
> + .core_mask = 0xff,
> + .core_shift = 0,
> + .cluster_mask = 0xff,
> + .cluster_shift = 8,
> + },
> + .start_powered_off = SPO_ALL,
> + .dtb_expose = false,
> + .per_cluster_gic = true,
> + .gic = {
> + .version = 3,
> + .dist = 0x0,
> + .redist = 0x100000,
> + .num_irq = 288,
> + },
> + },
> +
> + .uart[0] = { 0xf1920000, 25 },
> + .uart[1] = { 0xf1930000, 26 },
> + .num_uart = 2,
> +
> + .canfd[0] = { 0xf19e0000, 27 },
> + .canfd[1] = { 0xf19f0000, 28 },
> + .canfd[2] = { 0xf1a00000, 95 },
> + .canfd[3] = { 0xf1a10000, 96 },
> + .num_canfd = 4,
> +
> + .gem[0] = { { 0xf1a60000, 39 }, 2, "rgmii-id", 1000 },
> + .gem[1] = { { 0xf1a70000, 41 }, 2, "rgmii-id", 1000 },
> + .gem[2] = { { 0xed920000, 164 }, 4, "usxgmii", 10000 }, /* MMI 10Gb GEM */
> + .num_gem = 3,
> +
> + .zdma[0] = { "adma", { 0xebd00000, 72 }, 8, 0x10000, 1 },
> + .zdma[1] = { "sdma", { 0xebd80000, 112 }, 8, 0x10000, 1 },
> + .num_zdma = 2,
> +
> + .usb[0] = { .xhci = 0xf1b00000, .ctrl = 0xf1ee0000, .irq = 29 },
> + .usb[1] = { .xhci = 0xf1c00000, .ctrl = 0xf1ef0000, .irq = 34 },
> + .num_usb = 2,
> +
> + .efuse = { .ctrl = 0xf1240000, .cache = 0xf1250000, .irq = 230 },
> +
> + .ospi = {
> + .ctrl = 0xf1010000,
> + .dac = 0xc0000000, .dac_sz = 0x20000000,
> + .dma_src = 0xf1011000, .dma_dst = 0xf1011800,
> + .irq = 216,
> + },
> +
> + .sdhci[0] = { 0xf1040000, 218 },
> + .sdhci[1] = { 0xf1050000, 220 }, /* eMMC */
> + .num_sdhci = 2,
> +
> + .pmc_iou_slcr = { 0xf1060000, 222 },
> + .bbram = { 0xf11f0000, PPU1_OR_IRQ(18, 0) },
> + .crl = { 0xeb5e0000 },
> + .trng = { 0xf1230000, 233 },
> + .rtc = {
> + { 0xf12a0000, PPU1_OR_IRQ(18, 1) },
> + .alarm_irq = 200, .second_irq = 201
> + },
> +
> + .cfu = {
> + .cframe_base = 0xf12d0000, .cframe_stride = 0x1000,
> + .cframe_bcast_reg = 0xf12ee000, .cframe_bcast_fdri = 0xf12ef000,
> + .cfu_apb = 0xf12b0000, .cfu_sfr = 0xf12c1000,
> + .cfu_stream = 0xf12c0000, .cfu_stream_2 = 0xf1f80000,
> + .cfu_fdro = 0xf12c2000,
> + .cfu_apb_irq = 235, .cframe_irq = EAM_IRQ(7),
> + },
> +
> + .reserved = { 0xf5e00000, 270, 8 },
> +};
> +
> static const VersalMap *VERSION_TO_MAP[] = {
> [VERSAL_VER_VERSAL] = &VERSAL_MAP,
> + [VERSAL_VER_VERSAL2] = &VERSAL2_MAP,
> };
>
> static inline VersalVersion versal_get_version(Versal *s)
> {
> return XLNX_VERSAL_BASE_GET_CLASS(s)->version;
> @@ -1291,10 +1412,15 @@ static void versal_create_efuse(Versal *s,
> {
> DeviceState *bits;
> DeviceState *ctrl;
> DeviceState *cache;
>
> + if (versal_get_version(s) != VERSAL_VER_VERSAL) {
> + /* TODO for versal2 */
> + return;
> + }
> +
> ctrl = qdev_new(TYPE_XLNX_VERSAL_EFUSE_CTRL);
> cache = qdev_new(TYPE_XLNX_VERSAL_EFUSE_CACHE);
> bits = qdev_new(TYPE_XLNX_EFUSE);
>
> qdev_prop_set_uint32(bits, "efuse-nr", 3);
> @@ -1542,34 +1668,47 @@ static inline void crl_connect_dev_by_name(Versal *s, Object *crl,
> }
>
> static inline void versal_create_crl(Versal *s)
> {
> const VersalMap *map;
> + VersalVersion ver;
> const char *crl_class;
> DeviceState *dev;
> + size_t num_gem;
> Object *obj;
>
> map = versal_get_map(s);
> + ver = versal_get_version(s);
>
> - crl_class = TYPE_XLNX_VERSAL_CRL;
> + crl_class = xlnx_versal_crl_class_name(ver);
> dev = qdev_new(crl_class);
> obj = OBJECT(dev);
> object_property_add_child(OBJECT(s), "crl", obj);
>
> + /*
> + * The 3rd GEM controller on versal2 is in the MMI subsystem.
> + * Its reset line is not connected to the CRL. Consider only the first two
> + * ones.
> + */
> + num_gem = ver == VERSAL_VER_VERSAL2 ? 2 : map->num_gem;
> +
> crl_connect_dev_by_name(s, obj, "rpu-cluster/rpu",
> map->rpu.num_cluster * map->rpu.num_core);
> crl_connect_dev_by_name(s, obj, map->zdma[0].name, map->zdma[0].num_chan);
> crl_connect_dev_by_name(s, obj, "uart", map->num_uart);
> - crl_connect_dev_by_name(s, obj, "gem", map->num_gem);
> + crl_connect_dev_by_name(s, obj, "gem", num_gem);
> crl_connect_dev_by_name(s, obj, "usb", map->num_usb);
>
> sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_abort);
>
> memory_region_add_subregion(&s->mr_ps, map->crl.addr,
> sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
>
> - versal_sysbus_connect_irq(s, SYS_BUS_DEVICE(dev), 0, map->crl.irq);
> + if (ver == VERSAL_VER_VERSAL) {
> + /* CRL IRQ line has been removed in versal2 */
> + versal_sysbus_connect_irq(s, SYS_BUS_DEVICE(dev), 0, map->crl.irq);
> + }
> }
>
> /*
> * This takes the board allocated linear DDR memory and creates aliases
> * for each split DDR range/aperture on the Versal address map.
> @@ -1657,21 +1796,16 @@ static void versal_unimp_irq_parity_imr(void *opaque, int n, int level)
> qemu_log_mask(LOG_UNIMP,
> "PMC SLCR parity interrupt behaviour "
> "is not yet implemented\n");
> }
>
> -static void versal_unimp(Versal *s)
> +static void versal_unimp_common(Versal *s)
> {
> DeviceState *slcr;
> qemu_irq gpio_in;
>
> - versal_unimp_area(s, "psm", &s->mr_ps, 0xffc80000, 0x70000);
> - versal_unimp_area(s, "crf", &s->mr_ps, 0xfd1a0000, 0x140000);
> - versal_unimp_area(s, "apu", &s->mr_ps, 0xfd5c0000, 0x100);
> versal_unimp_area(s, "crp", &s->mr_ps, 0xf1260000, 0x10000);
> - versal_unimp_area(s, "iou-scntr", &s->mr_ps, 0xff130000, 0x10000);
> - versal_unimp_area(s, "iou-scntr-seucre", &s->mr_ps, 0xff140000, 0x10000);
>
> qdev_init_gpio_in_named(DEVICE(s), versal_unimp_sd_emmc_sel,
> "sd-emmc-sel-dummy", 2);
> qdev_init_gpio_in_named(DEVICE(s), versal_unimp_qspi_ospi_mux_sel,
> "qspi-ospi-mux-sel-dummy", 1);
> @@ -1690,10 +1824,29 @@ static void versal_unimp(Versal *s)
>
> gpio_in = qdev_get_gpio_in_named(DEVICE(s), "irq-parity-imr-dummy", 0);
> qdev_connect_gpio_out_named(slcr, SYSBUS_DEVICE_GPIO_IRQ, 0, gpio_in);
> }
>
> +static void versal_unimp(Versal *s)
> +{
> + versal_unimp_area(s, "psm", &s->mr_ps, 0xffc80000, 0x70000);
> + versal_unimp_area(s, "crf", &s->mr_ps, 0xfd1a0000, 0x140000);
> + versal_unimp_area(s, "apu", &s->mr_ps, 0xfd5c0000, 0x100);
> + versal_unimp_area(s, "iou-scntr", &s->mr_ps, 0xff130000, 0x10000);
> + versal_unimp_area(s, "iou-scntr-secure", &s->mr_ps, 0xff140000, 0x10000);
> +
> + versal_unimp_common(s);
> +}
> +
> +static void versal2_unimp(Versal *s)
> +{
> + versal_unimp_area(s, "fpd-systmr-ctrl", &s->mr_ps, 0xec920000, 0x1000);
> + versal_unimp_area(s, "crf", &s->mr_ps, 0xec200000, 0x100000);
> +
> + versal_unimp_common(s);
> +}
> +
> static uint32_t fdt_add_clk_node(Versal *s, const char *name,
> unsigned int freq_hz)
> {
> uint32_t phandle;
>
> @@ -1707,13 +1860,12 @@ static uint32_t fdt_add_clk_node(Versal *s, const char *name,
> qemu_fdt_setprop(s->cfg.fdt, name, "u-boot,dm-pre-reloc", NULL, 0);
>
> return phandle;
> }
>
> -static void versal_realize(DeviceState *dev, Error **errp)
> +static void versal_realize_common(Versal *s)
> {
> - Versal *s = XLNX_VERSAL_BASE(dev);
> DeviceState *slcr, *ospi;
> MemoryRegion *ocm;
> Object *container;
> const VersalMap *map = versal_get_map(s);
> size_t i;
> @@ -1782,18 +1934,33 @@ static void versal_realize(DeviceState *dev, Error **errp)
> versal_create_rtc(s, &map->rtc);
> versal_create_cfu(s, &map->cfu);
> versal_create_crl(s);
>
> versal_map_ddr(s, &map->ddr);
> - versal_unimp(s);
>
> /* Create the On Chip Memory (OCM). */
> ocm = g_new(MemoryRegion, 1);
> memory_region_init_ram(ocm, OBJECT(s), "ocm", map->ocm.size, &error_fatal);
> memory_region_add_subregion_overlap(&s->mr_ps, map->ocm.addr, ocm, 0);
> }
>
> +static void versal_realize(DeviceState *dev, Error **errp)
> +{
> + Versal *s = XLNX_VERSAL_BASE(dev);
> +
> + versal_realize_common(s);
> + versal_unimp(s);
> +}
> +
> +static void versal2_realize(DeviceState *dev, Error **errp)
> +{
> + Versal *s = XLNX_VERSAL_BASE(dev);
> +
> + versal_realize_common(s);
> + versal2_unimp(s);
> +}
> +
> void versal_sdhci_plug_card(Versal *s, int sd_idx, BlockBackend *blk)
> {
> DeviceState *sdhci, *card;
>
> sdhci = DEVICE(versal_get_child_idx(s, "sdhci", sd_idx));
> @@ -1925,20 +2092,30 @@ static const Property versal_properties[] = {
>
> static void versal_base_class_init(ObjectClass *klass, const void *data)
> {
> DeviceClass *dc = DEVICE_CLASS(klass);
>
> - dc->realize = versal_realize;
> device_class_set_props(dc, versal_properties);
> /* No VMSD since we haven't got any top-level SoC state to save. */
> }
>
> static void versal_class_init(ObjectClass *klass, const void *data)
> {
> VersalClass *vc = XLNX_VERSAL_BASE_CLASS(klass);
> + DeviceClass *dc = DEVICE_CLASS(klass);
>
> vc->version = VERSAL_VER_VERSAL;
> + dc->realize = versal_realize;
> +}
> +
> +static void versal2_class_init(ObjectClass *klass, const void *data)
> +{
> + VersalClass *vc = XLNX_VERSAL_BASE_CLASS(klass);
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + vc->version = VERSAL_VER_VERSAL2;
> + dc->realize = versal2_realize;
> }
>
> static const TypeInfo versal_base_info = {
> .name = TYPE_XLNX_VERSAL_BASE,
> .parent = TYPE_SYS_BUS_DEVICE,
> @@ -1953,12 +2130,19 @@ static const TypeInfo versal_info = {
> .name = TYPE_XLNX_VERSAL,
> .parent = TYPE_XLNX_VERSAL_BASE,
> .class_init = versal_class_init,
> };
>
> +static const TypeInfo versal2_info = {
> + .name = TYPE_XLNX_VERSAL2,
> + .parent = TYPE_XLNX_VERSAL_BASE,
> + .class_init = versal2_class_init,
> +};
> +
> static void versal_register_types(void)
> {
> type_register_static(&versal_base_info);
> type_register_static(&versal_info);
> + type_register_static(&versal2_info);
> }
>
> type_init(versal_register_types);
> --
> 2.50.0
>