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> --- 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