On Wed, Jul 16, 2025 at 11:54:11AM +0200, Luc Michel wrote:
> Refactor the DDR aperture regions creation using the VersalMap
> structure. Device creation and FDT node creation are split into two
> functions because the later must happen during ARM virtual bootloader
> modify_dtb callback.
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
Reviewed-by: Francisco Iglesias <francisco.iglesias@amd.com>
> ---
> include/hw/arm/xlnx-versal.h | 7 +---
> hw/arm/xlnx-versal-virt.c | 79 +-----------------------------------
> hw/arm/xlnx-versal.c | 73 ++++++++++++++++++++++-----------
> 3 files changed, 53 insertions(+), 106 deletions(-)
>
> diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h
> index 7be5a6ccf4d..a3bc967c352 100644
> --- a/include/hw/arm/xlnx-versal.h
> +++ b/include/hw/arm/xlnx-versal.h
> @@ -41,15 +41,10 @@ struct Versal {
>
> /*< public >*/
> GArray *intc;
> MemoryRegion mr_ps;
>
> - struct {
> - /* 4 ranges to access DDR. */
> - MemoryRegion mr_ddr_ranges[4];
> - } noc;
> -
> struct {
> uint32_t clk_25mhz;
> uint32_t clk_125mhz;
> uint32_t gic;
> } phandle;
> @@ -71,10 +66,12 @@ static inline void versal_set_fdt(Versal *s, void *fdt)
> {
> g_assert(!qdev_is_realized(DEVICE(s)));
> s->cfg.fdt = fdt;
> }
>
> +void versal_fdt_add_memory_nodes(Versal *s, uint64_t ram_size);
> +
> void versal_sdhci_plug_card(Versal *s, int sd_idx, BlockBackend *blk);
> void versal_efuse_attach_drive(Versal *s, BlockBackend *blk);
> void versal_bbram_attach_drive(Versal *s, BlockBackend *blk);
> void versal_ospi_create_flash(Versal *s, int flash_idx, const char *flash_mdl,
> BlockBackend *blk);
> diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
> index cad345b98e0..7f40c197072 100644
> --- a/hw/arm/xlnx-versal-virt.c
> +++ b/hw/arm/xlnx-versal-virt.c
> @@ -104,92 +104,17 @@ static void fdt_nop_memory_nodes(void *fdt, Error **errp)
> n++;
> }
> g_strfreev(node_path);
> }
>
> -static void fdt_add_memory_nodes(VersalVirt *s, void *fdt, uint64_t ram_size)
> -{
> - /* Describes the various split DDR access regions. */
> - static const struct {
> - uint64_t base;
> - uint64_t size;
> - } addr_ranges[] = {
> - { MM_TOP_DDR, MM_TOP_DDR_SIZE },
> - { MM_TOP_DDR_2, MM_TOP_DDR_2_SIZE },
> - { MM_TOP_DDR_3, MM_TOP_DDR_3_SIZE },
> - { MM_TOP_DDR_4, MM_TOP_DDR_4_SIZE }
> - };
> - uint64_t mem_reg_prop[8] = {0};
> - uint64_t size = ram_size;
> - Error *err = NULL;
> - char *name;
> - int i;
> -
> - fdt_nop_memory_nodes(fdt, &err);
> - if (err) {
> - error_report_err(err);
> - return;
> - }
> -
> - name = g_strdup_printf("/memory@%x", MM_TOP_DDR);
> - for (i = 0; i < ARRAY_SIZE(addr_ranges) && size; i++) {
> - uint64_t mapsize;
> -
> - mapsize = size < addr_ranges[i].size ? size : addr_ranges[i].size;
> -
> - mem_reg_prop[i * 2] = addr_ranges[i].base;
> - mem_reg_prop[i * 2 + 1] = mapsize;
> - size -= mapsize;
> - }
> - qemu_fdt_add_subnode(fdt, name);
> - qemu_fdt_setprop_string(fdt, name, "device_type", "memory");
> -
> - switch (i) {
> - case 1:
> - qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> - 2, mem_reg_prop[0],
> - 2, mem_reg_prop[1]);
> - break;
> - case 2:
> - qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> - 2, mem_reg_prop[0],
> - 2, mem_reg_prop[1],
> - 2, mem_reg_prop[2],
> - 2, mem_reg_prop[3]);
> - break;
> - case 3:
> - qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> - 2, mem_reg_prop[0],
> - 2, mem_reg_prop[1],
> - 2, mem_reg_prop[2],
> - 2, mem_reg_prop[3],
> - 2, mem_reg_prop[4],
> - 2, mem_reg_prop[5]);
> - break;
> - case 4:
> - qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> - 2, mem_reg_prop[0],
> - 2, mem_reg_prop[1],
> - 2, mem_reg_prop[2],
> - 2, mem_reg_prop[3],
> - 2, mem_reg_prop[4],
> - 2, mem_reg_prop[5],
> - 2, mem_reg_prop[6],
> - 2, mem_reg_prop[7]);
> - break;
> - default:
> - g_assert_not_reached();
> - }
> - g_free(name);
> -}
> -
> static void versal_virt_modify_dtb(const struct arm_boot_info *binfo,
> void *fdt)
> {
> VersalVirt *s = container_of(binfo, VersalVirt, binfo);
>
> - fdt_add_memory_nodes(s, fdt, binfo->ram_size);
> + fdt_nop_memory_nodes(s->fdt, &error_abort);
> + versal_fdt_add_memory_nodes(&s->soc, binfo->ram_size);
> }
>
> static void *versal_virt_get_dtb(const struct arm_boot_info *binfo,
> int *fdt_size)
> {
> diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
> index f46c73ac8e7..bf680077e48 100644
> --- a/hw/arm/xlnx-versal.c
> +++ b/hw/arm/xlnx-versal.c
> @@ -115,10 +115,15 @@ typedef struct VersalCpuClusterMap {
> } VersalCpuClusterMap;
>
> typedef struct VersalMap {
> VersalMemMap ocm;
>
> + struct VersalDDRMap {
> + VersalMemMap chan[4];
> + size_t num_chan;
> + } ddr;
> +
> VersalCpuClusterMap apu;
> VersalCpuClusterMap rpu;
>
> VersalSimplePeriphMap uart[2];
> size_t num_uart;
> @@ -219,10 +224,18 @@ static const VersalMap VERSAL_MAP = {
> .ocm = {
> .addr = 0xfffc0000,
> .size = 0x40000,
> },
>
> + .ddr = {
> + .chan[0] = { .addr = 0x0, .size = 2 * GiB },
> + .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-a72"),
> .num_cluster = 1,
> .num_core = 2,
> @@ -1480,50 +1493,62 @@ static inline void versal_create_crl(Versal *s)
> sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
>
> versal_sysbus_connect_irq(s, SYS_BUS_DEVICE(dev), 0, map->crl.irq);
> }
>
> -/* This takes the board allocated linear DDR memory and creates aliases
> +/*
> + * This takes the board allocated linear DDR memory and creates aliases
> * for each split DDR range/aperture on the Versal address map.
> */
> -static void versal_map_ddr(Versal *s)
> +static void versal_map_ddr(Versal *s, const struct VersalDDRMap *map)
> {
> uint64_t size = memory_region_size(s->cfg.mr_ddr);
> - /* Describes the various split DDR access regions. */
> - static const struct {
> - uint64_t base;
> - uint64_t size;
> - } addr_ranges[] = {
> - { MM_TOP_DDR, MM_TOP_DDR_SIZE },
> - { MM_TOP_DDR_2, MM_TOP_DDR_2_SIZE },
> - { MM_TOP_DDR_3, MM_TOP_DDR_3_SIZE },
> - { MM_TOP_DDR_4, MM_TOP_DDR_4_SIZE }
> - };
> uint64_t offset = 0;
> int i;
>
> - assert(ARRAY_SIZE(addr_ranges) == ARRAY_SIZE(s->noc.mr_ddr_ranges));
> - for (i = 0; i < ARRAY_SIZE(addr_ranges) && size; i++) {
> - char *name;
> + for (i = 0; i < map->num_chan && size; i++) {
> uint64_t mapsize;
> + MemoryRegion *alias;
> +
> + mapsize = MIN(size, map->chan[i].size);
>
> - mapsize = size < addr_ranges[i].size ? size : addr_ranges[i].size;
> - name = g_strdup_printf("noc-ddr-range%d", i);
> /* Create the MR alias. */
> - memory_region_init_alias(&s->noc.mr_ddr_ranges[i], OBJECT(s),
> - name, s->cfg.mr_ddr,
> - offset, mapsize);
> + alias = g_new(MemoryRegion, 1);
> + memory_region_init_alias(alias, OBJECT(s), "noc-ddr-range",
> + s->cfg.mr_ddr, offset, mapsize);
>
> /* Map it onto the NoC MR. */
> - memory_region_add_subregion(&s->mr_ps, addr_ranges[i].base,
> - &s->noc.mr_ddr_ranges[i]);
> + memory_region_add_subregion(&s->mr_ps, map->chan[i].addr, alias);
> offset += mapsize;
> size -= mapsize;
> - g_free(name);
> }
> }
>
> +void versal_fdt_add_memory_nodes(Versal *s, uint64_t size)
> +{
> + const struct VersalDDRMap *map = &versal_get_map(s)->ddr;
> + g_autofree char *node;
> + g_autofree uint64_t *reg;
> + int i;
> +
> + reg = g_new(uint64_t, map->num_chan * 2);
> +
> + for (i = 0; i < map->num_chan && size; i++) {
> + uint64_t mapsize;
> +
> + mapsize = MIN(size, map->chan[i].size);
> +
> + reg[i * 2] = cpu_to_be64(map->chan[i].addr);
> + reg[i * 2 + 1] = cpu_to_be64(mapsize);
> +
> + size -= mapsize;
> + }
> +
> + node = versal_fdt_add_subnode(s, "/memory", 0, "memory", sizeof("memory"));
> + qemu_fdt_setprop(s->cfg.fdt, node, "reg", reg, sizeof(uint64_t) * i * 2);
> +}
> +
> static void versal_unimp_area(Versal *s, const char *name,
> MemoryRegion *mr,
> hwaddr base, hwaddr size)
> {
> DeviceState *dev = qdev_new(TYPE_UNIMPLEMENTED_DEVICE);
> @@ -1687,11 +1712,11 @@ static void versal_realize(DeviceState *dev, Error **errp)
> versal_create_trng(s, &map->trng);
> versal_create_rtc(s, &map->rtc);
> versal_create_cfu(s, &map->cfu);
> versal_create_crl(s);
>
> - versal_map_ddr(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);
> --
> 2.50.0
>