/*
- * Xilinx Versal SoC model.
+ * AMD/Xilinx Versal family SoC model.
*
* Copyright (c) 2018 Xilinx Inc.
* Copyright (c) 2025 Advanced Micro Devices, Inc.
.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_shift = ARM_AFF1_SHIFT,
+ .cluster_shift = ARM_AFF2_SHIFT,
+ },
+ .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 = {
+ .core_shift = ARM_AFF0_SHIFT,
+ .cluster_shift = ARM_AFF1_SHIFT,
+ },
+ .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)
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);
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);
+ }
}
/*
"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_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)
{
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;
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_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);
+}
+
DeviceState *versal_get_boot_cpu(Versal *s)
{
return DEVICE(versal_get_child_idx(s, "apu-cluster/apu", 0));
{
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 = {
.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);