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
> 

Reply via email to