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.mic...@amd.com>
Reviewed-by: Francisco Iglesias <francisco.igles...@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 >