Message ID | 20210302110955.1810487-2-edgar.iglesias@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | hw/arm: versal: Add support for the XRAMs | expand |
On Tue, Mar 2, 2021 at 6:12 AM Edgar E. Iglesias <edgar.iglesias@gmail.com> wrote: > > From: "Edgar E. Iglesias" <edgar.iglesias@xilinx.com> > > Add a model of the Xilinx Versal Accelerator RAM (XRAM). > This is mainly a stub to make firmware happy. The size of > the RAMs can be probed. The interrupt mask logic is > modelled but none of the interrups will ever be raised > unless injected. > > Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Alistair > --- > include/hw/misc/xlnx-versal-xramc.h | 102 +++++++++++ > hw/misc/xlnx-versal-xramc.c | 253 ++++++++++++++++++++++++++++ > hw/misc/meson.build | 1 + > 3 files changed, 356 insertions(+) > create mode 100644 include/hw/misc/xlnx-versal-xramc.h > create mode 100644 hw/misc/xlnx-versal-xramc.c > > diff --git a/include/hw/misc/xlnx-versal-xramc.h b/include/hw/misc/xlnx-versal-xramc.h > new file mode 100644 > index 0000000000..68163cf330 > --- /dev/null > +++ b/include/hw/misc/xlnx-versal-xramc.h > @@ -0,0 +1,102 @@ > +/* > + * QEMU model of the Xilinx XRAM Controller. > + * > + * Copyright (c) 2021 Xilinx Inc. > + * SPDX-License-Identifier: GPL-2.0-or-later > + * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> > + */ > + > +#ifndef XLNX_VERSAL_XRAMC_H > +#define XLNX_VERSAL_XRAMC_H > + > +#include "qemu/osdep.h" > +#include "hw/sysbus.h" > +#include "hw/register.h" > +#include "qemu/bitops.h" > +#include "qemu/log.h" > +#include "migration/vmstate.h" > +#include "hw/irq.h" > + > +#define TYPE_XLNX_XRAM_CTRL "xlnx.versal-xramc" > + > +#define XLNX_XRAM_CTRL(obj) \ > + OBJECT_CHECK(XlnxXramCtrl, (obj), TYPE_XLNX_XRAM_CTRL) > + > +REG32(XRAM_ERR_CTRL, 0x0) > + FIELD(XRAM_ERR_CTRL, UE_RES, 3, 1) > + FIELD(XRAM_ERR_CTRL, PWR_ERR_RES, 2, 1) > + FIELD(XRAM_ERR_CTRL, PZ_ERR_RES, 1, 1) > + FIELD(XRAM_ERR_CTRL, APB_ERR_RES, 0, 1) > +REG32(XRAM_ISR, 0x4) > + FIELD(XRAM_ISR, INV_APB, 0, 1) > +REG32(XRAM_IMR, 0x8) > + FIELD(XRAM_IMR, INV_APB, 0, 1) > +REG32(XRAM_IEN, 0xc) > + FIELD(XRAM_IEN, INV_APB, 0, 1) > +REG32(XRAM_IDS, 0x10) > + FIELD(XRAM_IDS, INV_APB, 0, 1) > +REG32(XRAM_ECC_CNTL, 0x14) > + FIELD(XRAM_ECC_CNTL, FI_MODE, 2, 1) > + FIELD(XRAM_ECC_CNTL, DET_ONLY, 1, 1) > + FIELD(XRAM_ECC_CNTL, ECC_ON_OFF, 0, 1) > +REG32(XRAM_CLR_EXE, 0x18) > + FIELD(XRAM_CLR_EXE, MON_7, 7, 1) > + FIELD(XRAM_CLR_EXE, MON_6, 6, 1) > + FIELD(XRAM_CLR_EXE, MON_5, 5, 1) > + FIELD(XRAM_CLR_EXE, MON_4, 4, 1) > + FIELD(XRAM_CLR_EXE, MON_3, 3, 1) > + FIELD(XRAM_CLR_EXE, MON_2, 2, 1) > + FIELD(XRAM_CLR_EXE, MON_1, 1, 1) > + FIELD(XRAM_CLR_EXE, MON_0, 0, 1) > +REG32(XRAM_CE_FFA, 0x1c) > + FIELD(XRAM_CE_FFA, ADDR, 0, 20) > +REG32(XRAM_CE_FFD0, 0x20) > +REG32(XRAM_CE_FFD1, 0x24) > +REG32(XRAM_CE_FFD2, 0x28) > +REG32(XRAM_CE_FFD3, 0x2c) > +REG32(XRAM_CE_FFE, 0x30) > + FIELD(XRAM_CE_FFE, SYNDROME, 0, 16) > +REG32(XRAM_UE_FFA, 0x34) > + FIELD(XRAM_UE_FFA, ADDR, 0, 20) > +REG32(XRAM_UE_FFD0, 0x38) > +REG32(XRAM_UE_FFD1, 0x3c) > +REG32(XRAM_UE_FFD2, 0x40) > +REG32(XRAM_UE_FFD3, 0x44) > +REG32(XRAM_UE_FFE, 0x48) > + FIELD(XRAM_UE_FFE, SYNDROME, 0, 16) > +REG32(XRAM_FI_D0, 0x4c) > +REG32(XRAM_FI_D1, 0x50) > +REG32(XRAM_FI_D2, 0x54) > +REG32(XRAM_FI_D3, 0x58) > +REG32(XRAM_FI_SY, 0x5c) > + FIELD(XRAM_FI_SY, DATA, 0, 16) > +REG32(XRAM_RMW_UE_FFA, 0x70) > + FIELD(XRAM_RMW_UE_FFA, ADDR, 0, 20) > +REG32(XRAM_FI_CNTR, 0x74) > + FIELD(XRAM_FI_CNTR, COUNT, 0, 24) > +REG32(XRAM_IMP, 0x80) > + FIELD(XRAM_IMP, SIZE, 0, 4) > +REG32(XRAM_PRDY_DBG, 0x84) > + FIELD(XRAM_PRDY_DBG, ISLAND3, 12, 4) > + FIELD(XRAM_PRDY_DBG, ISLAND2, 8, 4) > + FIELD(XRAM_PRDY_DBG, ISLAND1, 4, 4) > + FIELD(XRAM_PRDY_DBG, ISLAND0, 0, 4) > +REG32(XRAM_SAFETY_CHK, 0xff8) > + > +#define XRAM_CTRL_R_MAX (R_XRAM_SAFETY_CHK + 1) > + > +typedef struct XlnxXramCtrl { > + SysBusDevice parent_obj; > + MemoryRegion iomem; > + MemoryRegion ram; > + qemu_irq irq; > + > + struct { > + uint64_t size; > + unsigned int encoded_size; > + } cfg; > + > + uint32_t regs[XRAM_CTRL_R_MAX]; > + RegisterInfo regs_info[XRAM_CTRL_R_MAX]; > +} XlnxXramCtrl; > +#endif > diff --git a/hw/misc/xlnx-versal-xramc.c b/hw/misc/xlnx-versal-xramc.c > new file mode 100644 > index 0000000000..c7f449fefa > --- /dev/null > +++ b/hw/misc/xlnx-versal-xramc.c > @@ -0,0 +1,253 @@ > +/* > + * QEMU model of the Xilinx XRAM Controller. > + * > + * Copyright (c) 2021 Xilinx Inc. > + * SPDX-License-Identifier: GPL-2.0-or-later > + * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/units.h" > +#include "qemu/bitops.h" > +#include "qapi/error.h" > +#include "migration/vmstate.h" > +#include "hw/sysbus.h" > +#include "hw/register.h" > +#include "hw/qdev-properties.h" > +#include "hw/irq.h" > +#include "hw/misc/xlnx-versal-xramc.h" > + > +#ifndef XLNX_XRAM_CTRL_ERR_DEBUG > +#define XLNX_XRAM_CTRL_ERR_DEBUG 0 > +#endif > + > +static void xram_update_irq(XlnxXramCtrl *s) > +{ > + bool pending = s->regs[R_XRAM_ISR] & ~s->regs[R_XRAM_IMR]; > + qemu_set_irq(s->irq, pending); > +} > + > +static void xram_isr_postw(RegisterInfo *reg, uint64_t val64) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); > + xram_update_irq(s); > +} > + > +static uint64_t xram_ien_prew(RegisterInfo *reg, uint64_t val64) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); > + uint32_t val = val64; > + > + s->regs[R_XRAM_IMR] &= ~val; > + xram_update_irq(s); > + return 0; > +} > + > +static uint64_t xram_ids_prew(RegisterInfo *reg, uint64_t val64) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); > + uint32_t val = val64; > + > + s->regs[R_XRAM_IMR] |= val; > + xram_update_irq(s); > + return 0; > +} > + > +static const RegisterAccessInfo xram_ctrl_regs_info[] = { > + { .name = "XRAM_ERR_CTRL", .addr = A_XRAM_ERR_CTRL, > + .reset = 0xf, > + .rsvd = 0xfffffff0, > + },{ .name = "XRAM_ISR", .addr = A_XRAM_ISR, > + .rsvd = 0xfffff800, > + .w1c = 0x7ff, > + .post_write = xram_isr_postw, > + },{ .name = "XRAM_IMR", .addr = A_XRAM_IMR, > + .reset = 0x7ff, > + .rsvd = 0xfffff800, > + .ro = 0x7ff, > + },{ .name = "XRAM_IEN", .addr = A_XRAM_IEN, > + .rsvd = 0xfffff800, > + .pre_write = xram_ien_prew, > + },{ .name = "XRAM_IDS", .addr = A_XRAM_IDS, > + .rsvd = 0xfffff800, > + .pre_write = xram_ids_prew, > + },{ .name = "XRAM_ECC_CNTL", .addr = A_XRAM_ECC_CNTL, > + .rsvd = 0xfffffff8, > + },{ .name = "XRAM_CLR_EXE", .addr = A_XRAM_CLR_EXE, > + .rsvd = 0xffffff00, > + },{ .name = "XRAM_CE_FFA", .addr = A_XRAM_CE_FFA, > + .rsvd = 0xfff00000, > + .ro = 0xfffff, > + },{ .name = "XRAM_CE_FFD0", .addr = A_XRAM_CE_FFD0, > + .ro = 0xffffffff, > + },{ .name = "XRAM_CE_FFD1", .addr = A_XRAM_CE_FFD1, > + .ro = 0xffffffff, > + },{ .name = "XRAM_CE_FFD2", .addr = A_XRAM_CE_FFD2, > + .ro = 0xffffffff, > + },{ .name = "XRAM_CE_FFD3", .addr = A_XRAM_CE_FFD3, > + .ro = 0xffffffff, > + },{ .name = "XRAM_CE_FFE", .addr = A_XRAM_CE_FFE, > + .rsvd = 0xffff0000, > + .ro = 0xffff, > + },{ .name = "XRAM_UE_FFA", .addr = A_XRAM_UE_FFA, > + .rsvd = 0xfff00000, > + .ro = 0xfffff, > + },{ .name = "XRAM_UE_FFD0", .addr = A_XRAM_UE_FFD0, > + .ro = 0xffffffff, > + },{ .name = "XRAM_UE_FFD1", .addr = A_XRAM_UE_FFD1, > + .ro = 0xffffffff, > + },{ .name = "XRAM_UE_FFD2", .addr = A_XRAM_UE_FFD2, > + .ro = 0xffffffff, > + },{ .name = "XRAM_UE_FFD3", .addr = A_XRAM_UE_FFD3, > + .ro = 0xffffffff, > + },{ .name = "XRAM_UE_FFE", .addr = A_XRAM_UE_FFE, > + .rsvd = 0xffff0000, > + .ro = 0xffff, > + },{ .name = "XRAM_FI_D0", .addr = A_XRAM_FI_D0, > + },{ .name = "XRAM_FI_D1", .addr = A_XRAM_FI_D1, > + },{ .name = "XRAM_FI_D2", .addr = A_XRAM_FI_D2, > + },{ .name = "XRAM_FI_D3", .addr = A_XRAM_FI_D3, > + },{ .name = "XRAM_FI_SY", .addr = A_XRAM_FI_SY, > + .rsvd = 0xffff0000, > + },{ .name = "XRAM_RMW_UE_FFA", .addr = A_XRAM_RMW_UE_FFA, > + .rsvd = 0xfff00000, > + .ro = 0xfffff, > + },{ .name = "XRAM_FI_CNTR", .addr = A_XRAM_FI_CNTR, > + .rsvd = 0xff000000, > + },{ .name = "XRAM_IMP", .addr = A_XRAM_IMP, > + .reset = 0x4, > + .rsvd = 0xfffffff0, > + .ro = 0xf, > + },{ .name = "XRAM_PRDY_DBG", .addr = A_XRAM_PRDY_DBG, > + .reset = 0xffff, > + .rsvd = 0xffff0000, > + .ro = 0xffff, > + },{ .name = "XRAM_SAFETY_CHK", .addr = A_XRAM_SAFETY_CHK, > + } > +}; > + > +static void xram_ctrl_reset_enter(Object *obj, ResetType type) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); > + unsigned int i; > + > + for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { > + register_reset(&s->regs_info[i]); > + } > + > + ARRAY_FIELD_DP32(s->regs, XRAM_IMP, SIZE, s->cfg.encoded_size); > +} > + > +static void xram_ctrl_reset_hold(Object *obj) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); > + > + xram_update_irq(s); > +} > + > +static const MemoryRegionOps xram_ctrl_ops = { > + .read = register_read_memory, > + .write = register_write_memory, > + .endianness = DEVICE_LITTLE_ENDIAN, > + .valid = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > +}; > + > +static void xram_ctrl_realize(DeviceState *dev, Error **errp) > +{ > + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(dev); > + > + switch (s->cfg.size) { > + case 64 * KiB: > + s->cfg.encoded_size = 0; > + break; > + case 128 * KiB: > + s->cfg.encoded_size = 1; > + break; > + case 256 * KiB: > + s->cfg.encoded_size = 2; > + break; > + case 512 * KiB: > + s->cfg.encoded_size = 3; > + break; > + case 1 * MiB: > + s->cfg.encoded_size = 4; > + break; > + default: > + error_setg(errp, "Unsupported XRAM size %" PRId64, s->cfg.size); > + return; > + } > + > + memory_region_init_ram(&s->ram, OBJECT(s), > + object_get_canonical_path_component(OBJECT(s)), > + s->cfg.size, &error_fatal); > + sysbus_init_mmio(sbd, &s->ram); > +} > + > +static void xram_ctrl_init(Object *obj) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); > + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); > + RegisterInfoArray *reg_array; > + > + memory_region_init(&s->iomem, obj, TYPE_XLNX_XRAM_CTRL, > + XRAM_CTRL_R_MAX * 4); > + reg_array = > + register_init_block32(DEVICE(obj), xram_ctrl_regs_info, > + ARRAY_SIZE(xram_ctrl_regs_info), > + s->regs_info, s->regs, > + &xram_ctrl_ops, > + XLNX_XRAM_CTRL_ERR_DEBUG, > + XRAM_CTRL_R_MAX * 4); > + memory_region_add_subregion(&s->iomem, > + 0x0, > + ®_array->mem); > + sysbus_init_mmio(sbd, &s->iomem); > + sysbus_init_irq(sbd, &s->irq); > +} > + > +static const VMStateDescription vmstate_xram_ctrl = { > + .name = TYPE_XLNX_XRAM_CTRL, > + .version_id = 1, > + .minimum_version_id = 1, > + .fields = (VMStateField[]) { > + VMSTATE_UINT32_ARRAY(regs, XlnxXramCtrl, XRAM_CTRL_R_MAX), > + VMSTATE_END_OF_LIST(), > + } > +}; > + > +static Property xram_ctrl_properties[] = { > + DEFINE_PROP_UINT64("size", XlnxXramCtrl, cfg.size, 1 * MiB), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static void xram_ctrl_class_init(ObjectClass *klass, void *data) > +{ > + ResettableClass *rc = RESETTABLE_CLASS(klass); > + DeviceClass *dc = DEVICE_CLASS(klass); > + > + dc->realize = xram_ctrl_realize; > + dc->vmsd = &vmstate_xram_ctrl; > + device_class_set_props(dc, xram_ctrl_properties); > + > + rc->phases.enter = xram_ctrl_reset_enter; > + rc->phases.hold = xram_ctrl_reset_hold; > +} > + > +static const TypeInfo xram_ctrl_info = { > + .name = TYPE_XLNX_XRAM_CTRL, > + .parent = TYPE_SYS_BUS_DEVICE, > + .instance_size = sizeof(XlnxXramCtrl), > + .class_init = xram_ctrl_class_init, > + .instance_init = xram_ctrl_init, > +}; > + > +static void xram_ctrl_register_types(void) > +{ > + type_register_static(&xram_ctrl_info); > +} > + > +type_init(xram_ctrl_register_types) > diff --git a/hw/misc/meson.build b/hw/misc/meson.build > index 629283957f..fbc4789249 100644 > --- a/hw/misc/meson.build > +++ b/hw/misc/meson.build > @@ -85,6 +85,7 @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files( > )) > softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c')) > softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c', 'zynq-xadc.c')) > +softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-xramc.c')) > softmmu_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c')) > softmmu_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c')) > softmmu_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c')) > -- > 2.25.1 > >
On 3/2/21 12:09 PM, Edgar E. Iglesias wrote: > From: "Edgar E. Iglesias" <edgar.iglesias@xilinx.com> > > Add a model of the Xilinx Versal Accelerator RAM (XRAM). > This is mainly a stub to make firmware happy. The size of > the RAMs can be probed. The interrupt mask logic is > modelled but none of the interrups will ever be raised > unless injected. > > Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Reviewed-by: Luc Michel <luc@lmichel.fr> > --- > include/hw/misc/xlnx-versal-xramc.h | 102 +++++++++++ > hw/misc/xlnx-versal-xramc.c | 253 ++++++++++++++++++++++++++++ > hw/misc/meson.build | 1 + > 3 files changed, 356 insertions(+) > create mode 100644 include/hw/misc/xlnx-versal-xramc.h > create mode 100644 hw/misc/xlnx-versal-xramc.c > > diff --git a/include/hw/misc/xlnx-versal-xramc.h b/include/hw/misc/xlnx-versal-xramc.h > new file mode 100644 > index 0000000000..68163cf330 > --- /dev/null > +++ b/include/hw/misc/xlnx-versal-xramc.h > @@ -0,0 +1,102 @@ > +/* > + * QEMU model of the Xilinx XRAM Controller. > + * > + * Copyright (c) 2021 Xilinx Inc. > + * SPDX-License-Identifier: GPL-2.0-or-later > + * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> > + */ > + > +#ifndef XLNX_VERSAL_XRAMC_H > +#define XLNX_VERSAL_XRAMC_H > + > +#include "qemu/osdep.h" > +#include "hw/sysbus.h" > +#include "hw/register.h" > +#include "qemu/bitops.h" > +#include "qemu/log.h" > +#include "migration/vmstate.h" > +#include "hw/irq.h" > + > +#define TYPE_XLNX_XRAM_CTRL "xlnx.versal-xramc" > + > +#define XLNX_XRAM_CTRL(obj) \ > + OBJECT_CHECK(XlnxXramCtrl, (obj), TYPE_XLNX_XRAM_CTRL) > + > +REG32(XRAM_ERR_CTRL, 0x0) > + FIELD(XRAM_ERR_CTRL, UE_RES, 3, 1) > + FIELD(XRAM_ERR_CTRL, PWR_ERR_RES, 2, 1) > + FIELD(XRAM_ERR_CTRL, PZ_ERR_RES, 1, 1) > + FIELD(XRAM_ERR_CTRL, APB_ERR_RES, 0, 1) > +REG32(XRAM_ISR, 0x4) > + FIELD(XRAM_ISR, INV_APB, 0, 1) > +REG32(XRAM_IMR, 0x8) > + FIELD(XRAM_IMR, INV_APB, 0, 1) > +REG32(XRAM_IEN, 0xc) > + FIELD(XRAM_IEN, INV_APB, 0, 1) > +REG32(XRAM_IDS, 0x10) > + FIELD(XRAM_IDS, INV_APB, 0, 1) > +REG32(XRAM_ECC_CNTL, 0x14) > + FIELD(XRAM_ECC_CNTL, FI_MODE, 2, 1) > + FIELD(XRAM_ECC_CNTL, DET_ONLY, 1, 1) > + FIELD(XRAM_ECC_CNTL, ECC_ON_OFF, 0, 1) > +REG32(XRAM_CLR_EXE, 0x18) > + FIELD(XRAM_CLR_EXE, MON_7, 7, 1) > + FIELD(XRAM_CLR_EXE, MON_6, 6, 1) > + FIELD(XRAM_CLR_EXE, MON_5, 5, 1) > + FIELD(XRAM_CLR_EXE, MON_4, 4, 1) > + FIELD(XRAM_CLR_EXE, MON_3, 3, 1) > + FIELD(XRAM_CLR_EXE, MON_2, 2, 1) > + FIELD(XRAM_CLR_EXE, MON_1, 1, 1) > + FIELD(XRAM_CLR_EXE, MON_0, 0, 1) > +REG32(XRAM_CE_FFA, 0x1c) > + FIELD(XRAM_CE_FFA, ADDR, 0, 20) > +REG32(XRAM_CE_FFD0, 0x20) > +REG32(XRAM_CE_FFD1, 0x24) > +REG32(XRAM_CE_FFD2, 0x28) > +REG32(XRAM_CE_FFD3, 0x2c) > +REG32(XRAM_CE_FFE, 0x30) > + FIELD(XRAM_CE_FFE, SYNDROME, 0, 16) > +REG32(XRAM_UE_FFA, 0x34) > + FIELD(XRAM_UE_FFA, ADDR, 0, 20) > +REG32(XRAM_UE_FFD0, 0x38) > +REG32(XRAM_UE_FFD1, 0x3c) > +REG32(XRAM_UE_FFD2, 0x40) > +REG32(XRAM_UE_FFD3, 0x44) > +REG32(XRAM_UE_FFE, 0x48) > + FIELD(XRAM_UE_FFE, SYNDROME, 0, 16) > +REG32(XRAM_FI_D0, 0x4c) > +REG32(XRAM_FI_D1, 0x50) > +REG32(XRAM_FI_D2, 0x54) > +REG32(XRAM_FI_D3, 0x58) > +REG32(XRAM_FI_SY, 0x5c) > + FIELD(XRAM_FI_SY, DATA, 0, 16) > +REG32(XRAM_RMW_UE_FFA, 0x70) > + FIELD(XRAM_RMW_UE_FFA, ADDR, 0, 20) > +REG32(XRAM_FI_CNTR, 0x74) > + FIELD(XRAM_FI_CNTR, COUNT, 0, 24) > +REG32(XRAM_IMP, 0x80) > + FIELD(XRAM_IMP, SIZE, 0, 4) > +REG32(XRAM_PRDY_DBG, 0x84) > + FIELD(XRAM_PRDY_DBG, ISLAND3, 12, 4) > + FIELD(XRAM_PRDY_DBG, ISLAND2, 8, 4) > + FIELD(XRAM_PRDY_DBG, ISLAND1, 4, 4) > + FIELD(XRAM_PRDY_DBG, ISLAND0, 0, 4) > +REG32(XRAM_SAFETY_CHK, 0xff8) > + > +#define XRAM_CTRL_R_MAX (R_XRAM_SAFETY_CHK + 1) > + > +typedef struct XlnxXramCtrl { > + SysBusDevice parent_obj; > + MemoryRegion iomem; > + MemoryRegion ram; > + qemu_irq irq; > + > + struct { > + uint64_t size; > + unsigned int encoded_size; > + } cfg; > + > + uint32_t regs[XRAM_CTRL_R_MAX]; > + RegisterInfo regs_info[XRAM_CTRL_R_MAX]; > +} XlnxXramCtrl; > +#endif > diff --git a/hw/misc/xlnx-versal-xramc.c b/hw/misc/xlnx-versal-xramc.c > new file mode 100644 > index 0000000000..c7f449fefa > --- /dev/null > +++ b/hw/misc/xlnx-versal-xramc.c > @@ -0,0 +1,253 @@ > +/* > + * QEMU model of the Xilinx XRAM Controller. > + * > + * Copyright (c) 2021 Xilinx Inc. > + * SPDX-License-Identifier: GPL-2.0-or-later > + * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/units.h" > +#include "qemu/bitops.h" > +#include "qapi/error.h" > +#include "migration/vmstate.h" > +#include "hw/sysbus.h" > +#include "hw/register.h" > +#include "hw/qdev-properties.h" > +#include "hw/irq.h" > +#include "hw/misc/xlnx-versal-xramc.h" > + > +#ifndef XLNX_XRAM_CTRL_ERR_DEBUG > +#define XLNX_XRAM_CTRL_ERR_DEBUG 0 > +#endif > + > +static void xram_update_irq(XlnxXramCtrl *s) > +{ > + bool pending = s->regs[R_XRAM_ISR] & ~s->regs[R_XRAM_IMR]; > + qemu_set_irq(s->irq, pending); > +} > + > +static void xram_isr_postw(RegisterInfo *reg, uint64_t val64) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); > + xram_update_irq(s); > +} > + > +static uint64_t xram_ien_prew(RegisterInfo *reg, uint64_t val64) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); > + uint32_t val = val64; > + > + s->regs[R_XRAM_IMR] &= ~val; > + xram_update_irq(s); > + return 0; > +} > + > +static uint64_t xram_ids_prew(RegisterInfo *reg, uint64_t val64) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); > + uint32_t val = val64; > + > + s->regs[R_XRAM_IMR] |= val; > + xram_update_irq(s); > + return 0; > +} > + > +static const RegisterAccessInfo xram_ctrl_regs_info[] = { > + { .name = "XRAM_ERR_CTRL", .addr = A_XRAM_ERR_CTRL, > + .reset = 0xf, > + .rsvd = 0xfffffff0, > + },{ .name = "XRAM_ISR", .addr = A_XRAM_ISR, > + .rsvd = 0xfffff800, > + .w1c = 0x7ff, > + .post_write = xram_isr_postw, > + },{ .name = "XRAM_IMR", .addr = A_XRAM_IMR, > + .reset = 0x7ff, > + .rsvd = 0xfffff800, > + .ro = 0x7ff, > + },{ .name = "XRAM_IEN", .addr = A_XRAM_IEN, > + .rsvd = 0xfffff800, > + .pre_write = xram_ien_prew, > + },{ .name = "XRAM_IDS", .addr = A_XRAM_IDS, > + .rsvd = 0xfffff800, > + .pre_write = xram_ids_prew, > + },{ .name = "XRAM_ECC_CNTL", .addr = A_XRAM_ECC_CNTL, > + .rsvd = 0xfffffff8, > + },{ .name = "XRAM_CLR_EXE", .addr = A_XRAM_CLR_EXE, > + .rsvd = 0xffffff00, > + },{ .name = "XRAM_CE_FFA", .addr = A_XRAM_CE_FFA, > + .rsvd = 0xfff00000, > + .ro = 0xfffff, > + },{ .name = "XRAM_CE_FFD0", .addr = A_XRAM_CE_FFD0, > + .ro = 0xffffffff, > + },{ .name = "XRAM_CE_FFD1", .addr = A_XRAM_CE_FFD1, > + .ro = 0xffffffff, > + },{ .name = "XRAM_CE_FFD2", .addr = A_XRAM_CE_FFD2, > + .ro = 0xffffffff, > + },{ .name = "XRAM_CE_FFD3", .addr = A_XRAM_CE_FFD3, > + .ro = 0xffffffff, > + },{ .name = "XRAM_CE_FFE", .addr = A_XRAM_CE_FFE, > + .rsvd = 0xffff0000, > + .ro = 0xffff, > + },{ .name = "XRAM_UE_FFA", .addr = A_XRAM_UE_FFA, > + .rsvd = 0xfff00000, > + .ro = 0xfffff, > + },{ .name = "XRAM_UE_FFD0", .addr = A_XRAM_UE_FFD0, > + .ro = 0xffffffff, > + },{ .name = "XRAM_UE_FFD1", .addr = A_XRAM_UE_FFD1, > + .ro = 0xffffffff, > + },{ .name = "XRAM_UE_FFD2", .addr = A_XRAM_UE_FFD2, > + .ro = 0xffffffff, > + },{ .name = "XRAM_UE_FFD3", .addr = A_XRAM_UE_FFD3, > + .ro = 0xffffffff, > + },{ .name = "XRAM_UE_FFE", .addr = A_XRAM_UE_FFE, > + .rsvd = 0xffff0000, > + .ro = 0xffff, > + },{ .name = "XRAM_FI_D0", .addr = A_XRAM_FI_D0, > + },{ .name = "XRAM_FI_D1", .addr = A_XRAM_FI_D1, > + },{ .name = "XRAM_FI_D2", .addr = A_XRAM_FI_D2, > + },{ .name = "XRAM_FI_D3", .addr = A_XRAM_FI_D3, > + },{ .name = "XRAM_FI_SY", .addr = A_XRAM_FI_SY, > + .rsvd = 0xffff0000, > + },{ .name = "XRAM_RMW_UE_FFA", .addr = A_XRAM_RMW_UE_FFA, > + .rsvd = 0xfff00000, > + .ro = 0xfffff, > + },{ .name = "XRAM_FI_CNTR", .addr = A_XRAM_FI_CNTR, > + .rsvd = 0xff000000, > + },{ .name = "XRAM_IMP", .addr = A_XRAM_IMP, > + .reset = 0x4, > + .rsvd = 0xfffffff0, > + .ro = 0xf, > + },{ .name = "XRAM_PRDY_DBG", .addr = A_XRAM_PRDY_DBG, > + .reset = 0xffff, > + .rsvd = 0xffff0000, > + .ro = 0xffff, > + },{ .name = "XRAM_SAFETY_CHK", .addr = A_XRAM_SAFETY_CHK, > + } > +}; > + > +static void xram_ctrl_reset_enter(Object *obj, ResetType type) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); > + unsigned int i; > + > + for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { > + register_reset(&s->regs_info[i]); > + } > + > + ARRAY_FIELD_DP32(s->regs, XRAM_IMP, SIZE, s->cfg.encoded_size); > +} > + > +static void xram_ctrl_reset_hold(Object *obj) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); > + > + xram_update_irq(s); > +} > + > +static const MemoryRegionOps xram_ctrl_ops = { > + .read = register_read_memory, > + .write = register_write_memory, > + .endianness = DEVICE_LITTLE_ENDIAN, > + .valid = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > +}; > + > +static void xram_ctrl_realize(DeviceState *dev, Error **errp) > +{ > + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(dev); > + > + switch (s->cfg.size) { > + case 64 * KiB: > + s->cfg.encoded_size = 0; > + break; > + case 128 * KiB: > + s->cfg.encoded_size = 1; > + break; > + case 256 * KiB: > + s->cfg.encoded_size = 2; > + break; > + case 512 * KiB: > + s->cfg.encoded_size = 3; > + break; > + case 1 * MiB: > + s->cfg.encoded_size = 4; > + break; > + default: > + error_setg(errp, "Unsupported XRAM size %" PRId64, s->cfg.size); > + return; > + } > + > + memory_region_init_ram(&s->ram, OBJECT(s), > + object_get_canonical_path_component(OBJECT(s)), > + s->cfg.size, &error_fatal); > + sysbus_init_mmio(sbd, &s->ram); > +} > + > +static void xram_ctrl_init(Object *obj) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); > + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); > + RegisterInfoArray *reg_array; > + > + memory_region_init(&s->iomem, obj, TYPE_XLNX_XRAM_CTRL, > + XRAM_CTRL_R_MAX * 4); > + reg_array = > + register_init_block32(DEVICE(obj), xram_ctrl_regs_info, > + ARRAY_SIZE(xram_ctrl_regs_info), > + s->regs_info, s->regs, > + &xram_ctrl_ops, > + XLNX_XRAM_CTRL_ERR_DEBUG, > + XRAM_CTRL_R_MAX * 4); > + memory_region_add_subregion(&s->iomem, > + 0x0, > + ®_array->mem); > + sysbus_init_mmio(sbd, &s->iomem); > + sysbus_init_irq(sbd, &s->irq); > +} > + > +static const VMStateDescription vmstate_xram_ctrl = { > + .name = TYPE_XLNX_XRAM_CTRL, > + .version_id = 1, > + .minimum_version_id = 1, > + .fields = (VMStateField[]) { > + VMSTATE_UINT32_ARRAY(regs, XlnxXramCtrl, XRAM_CTRL_R_MAX), > + VMSTATE_END_OF_LIST(), > + } > +}; > + > +static Property xram_ctrl_properties[] = { > + DEFINE_PROP_UINT64("size", XlnxXramCtrl, cfg.size, 1 * MiB), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static void xram_ctrl_class_init(ObjectClass *klass, void *data) > +{ > + ResettableClass *rc = RESETTABLE_CLASS(klass); > + DeviceClass *dc = DEVICE_CLASS(klass); > + > + dc->realize = xram_ctrl_realize; > + dc->vmsd = &vmstate_xram_ctrl; > + device_class_set_props(dc, xram_ctrl_properties); > + > + rc->phases.enter = xram_ctrl_reset_enter; > + rc->phases.hold = xram_ctrl_reset_hold; > +} > + > +static const TypeInfo xram_ctrl_info = { > + .name = TYPE_XLNX_XRAM_CTRL, > + .parent = TYPE_SYS_BUS_DEVICE, > + .instance_size = sizeof(XlnxXramCtrl), > + .class_init = xram_ctrl_class_init, > + .instance_init = xram_ctrl_init, > +}; > + > +static void xram_ctrl_register_types(void) > +{ > + type_register_static(&xram_ctrl_info); > +} > + > +type_init(xram_ctrl_register_types) > diff --git a/hw/misc/meson.build b/hw/misc/meson.build > index 629283957f..fbc4789249 100644 > --- a/hw/misc/meson.build > +++ b/hw/misc/meson.build > @@ -85,6 +85,7 @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files( > )) > softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c')) > softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c', 'zynq-xadc.c')) > +softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-xramc.c')) > softmmu_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c')) > softmmu_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c')) > softmmu_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c')) >
On Tue, 2 Mar 2021 at 11:09, Edgar E. Iglesias <edgar.iglesias@gmail.com> wrote: > > From: "Edgar E. Iglesias" <edgar.iglesias@xilinx.com> > > Add a model of the Xilinx Versal Accelerator RAM (XRAM). > This is mainly a stub to make firmware happy. The size of > the RAMs can be probed. The interrupt mask logic is > modelled but none of the interrups will ever be raised > unless injected. > > Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> > --- > include/hw/misc/xlnx-versal-xramc.h | 102 +++++++++++ > hw/misc/xlnx-versal-xramc.c | 253 ++++++++++++++++++++++++++++ > hw/misc/meson.build | 1 + > 3 files changed, 356 insertions(+) > create mode 100644 include/hw/misc/xlnx-versal-xramc.h > create mode 100644 hw/misc/xlnx-versal-xramc.c > > diff --git a/include/hw/misc/xlnx-versal-xramc.h b/include/hw/misc/xlnx-versal-xramc.h > new file mode 100644 > index 0000000000..68163cf330 > --- /dev/null > +++ b/include/hw/misc/xlnx-versal-xramc.h > @@ -0,0 +1,102 @@ > +/* > + * QEMU model of the Xilinx XRAM Controller. > + * > + * Copyright (c) 2021 Xilinx Inc. > + * SPDX-License-Identifier: GPL-2.0-or-later > + * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> > + */ > + > +#ifndef XLNX_VERSAL_XRAMC_H > +#define XLNX_VERSAL_XRAMC_H > + > +#include "qemu/osdep.h" Headers must never include osdep.h. > +#include "hw/sysbus.h" > +#include "hw/register.h" > +#include "qemu/bitops.h" > +#include "qemu/log.h" > +#include "migration/vmstate.h" > +#include "hw/irq.h" I bet you don't really need all of these includes in the header file; some of them belong in the .c file. > +static void xram_ctrl_init(Object *obj) > +{ > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); > + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); > + RegisterInfoArray *reg_array; > + > + memory_region_init(&s->iomem, obj, TYPE_XLNX_XRAM_CTRL, > + XRAM_CTRL_R_MAX * 4); > + reg_array = > + register_init_block32(DEVICE(obj), xram_ctrl_regs_info, > + ARRAY_SIZE(xram_ctrl_regs_info), > + s->regs_info, s->regs, > + &xram_ctrl_ops, > + XLNX_XRAM_CTRL_ERR_DEBUG, > + XRAM_CTRL_R_MAX * 4); > + memory_region_add_subregion(&s->iomem, > + 0x0, > + ®_array->mem); Isn't this just creating a container region that contains exactly one subregion that is the same size as it? Do we need to do this so that the reg_array is disposed of via refcounting or something ? > + sysbus_init_mmio(sbd, &s->iomem); > + sysbus_init_irq(sbd, &s->irq); > +} thanks -- PMM
On Mon, Mar 08, 2021 at 04:54:26PM +0000, Peter Maydell wrote: > On Tue, 2 Mar 2021 at 11:09, Edgar E. Iglesias <edgar.iglesias@gmail.com> wrote: > > > > From: "Edgar E. Iglesias" <edgar.iglesias@xilinx.com> > > > > Add a model of the Xilinx Versal Accelerator RAM (XRAM). > > This is mainly a stub to make firmware happy. The size of > > the RAMs can be probed. The interrupt mask logic is > > modelled but none of the interrups will ever be raised > > unless injected. > > > > Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> > > --- > > include/hw/misc/xlnx-versal-xramc.h | 102 +++++++++++ > > hw/misc/xlnx-versal-xramc.c | 253 ++++++++++++++++++++++++++++ > > hw/misc/meson.build | 1 + > > 3 files changed, 356 insertions(+) > > create mode 100644 include/hw/misc/xlnx-versal-xramc.h > > create mode 100644 hw/misc/xlnx-versal-xramc.c > > > > diff --git a/include/hw/misc/xlnx-versal-xramc.h b/include/hw/misc/xlnx-versal-xramc.h > > new file mode 100644 > > index 0000000000..68163cf330 > > --- /dev/null > > +++ b/include/hw/misc/xlnx-versal-xramc.h > > @@ -0,0 +1,102 @@ > > +/* > > + * QEMU model of the Xilinx XRAM Controller. > > + * > > + * Copyright (c) 2021 Xilinx Inc. > > + * SPDX-License-Identifier: GPL-2.0-or-later > > + * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> > > + */ > > + > > +#ifndef XLNX_VERSAL_XRAMC_H > > +#define XLNX_VERSAL_XRAMC_H > > + > > +#include "qemu/osdep.h" > > Headers must never include osdep.h. > > > +#include "hw/sysbus.h" > > +#include "hw/register.h" > > +#include "qemu/bitops.h" > > +#include "qemu/log.h" > > +#include "migration/vmstate.h" > > +#include "hw/irq.h" > > I bet you don't really need all of these includes in the header file; > some of them belong in the .c file. Yep, I'll cleanup the header files in v2. > > > +static void xram_ctrl_init(Object *obj) > > +{ > > + XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); > > + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); > > + RegisterInfoArray *reg_array; > > + > > + memory_region_init(&s->iomem, obj, TYPE_XLNX_XRAM_CTRL, > > + XRAM_CTRL_R_MAX * 4); > > + reg_array = > > + register_init_block32(DEVICE(obj), xram_ctrl_regs_info, > > + ARRAY_SIZE(xram_ctrl_regs_info), > > + s->regs_info, s->regs, > > + &xram_ctrl_ops, > > + XLNX_XRAM_CTRL_ERR_DEBUG, > > + XRAM_CTRL_R_MAX * 4); > > + memory_region_add_subregion(&s->iomem, > > + 0x0, > > + ®_array->mem); > > Isn't this just creating a container region that contains > exactly one subregion that is the same size as it? Do we > need to do this so that the reg_array is disposed of via > refcounting or something ? TBH I was just copying a pattern here. It looks to me like if reg_array gets leaked and we're using an unnecesarry container MR. I'll fix this in v2 (if I understood the life-cycle of these regs correctly). Cheers, Edgar
diff --git a/include/hw/misc/xlnx-versal-xramc.h b/include/hw/misc/xlnx-versal-xramc.h new file mode 100644 index 0000000000..68163cf330 --- /dev/null +++ b/include/hw/misc/xlnx-versal-xramc.h @@ -0,0 +1,102 @@ +/* + * QEMU model of the Xilinx XRAM Controller. + * + * Copyright (c) 2021 Xilinx Inc. + * SPDX-License-Identifier: GPL-2.0-or-later + * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> + */ + +#ifndef XLNX_VERSAL_XRAMC_H +#define XLNX_VERSAL_XRAMC_H + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/register.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "migration/vmstate.h" +#include "hw/irq.h" + +#define TYPE_XLNX_XRAM_CTRL "xlnx.versal-xramc" + +#define XLNX_XRAM_CTRL(obj) \ + OBJECT_CHECK(XlnxXramCtrl, (obj), TYPE_XLNX_XRAM_CTRL) + +REG32(XRAM_ERR_CTRL, 0x0) + FIELD(XRAM_ERR_CTRL, UE_RES, 3, 1) + FIELD(XRAM_ERR_CTRL, PWR_ERR_RES, 2, 1) + FIELD(XRAM_ERR_CTRL, PZ_ERR_RES, 1, 1) + FIELD(XRAM_ERR_CTRL, APB_ERR_RES, 0, 1) +REG32(XRAM_ISR, 0x4) + FIELD(XRAM_ISR, INV_APB, 0, 1) +REG32(XRAM_IMR, 0x8) + FIELD(XRAM_IMR, INV_APB, 0, 1) +REG32(XRAM_IEN, 0xc) + FIELD(XRAM_IEN, INV_APB, 0, 1) +REG32(XRAM_IDS, 0x10) + FIELD(XRAM_IDS, INV_APB, 0, 1) +REG32(XRAM_ECC_CNTL, 0x14) + FIELD(XRAM_ECC_CNTL, FI_MODE, 2, 1) + FIELD(XRAM_ECC_CNTL, DET_ONLY, 1, 1) + FIELD(XRAM_ECC_CNTL, ECC_ON_OFF, 0, 1) +REG32(XRAM_CLR_EXE, 0x18) + FIELD(XRAM_CLR_EXE, MON_7, 7, 1) + FIELD(XRAM_CLR_EXE, MON_6, 6, 1) + FIELD(XRAM_CLR_EXE, MON_5, 5, 1) + FIELD(XRAM_CLR_EXE, MON_4, 4, 1) + FIELD(XRAM_CLR_EXE, MON_3, 3, 1) + FIELD(XRAM_CLR_EXE, MON_2, 2, 1) + FIELD(XRAM_CLR_EXE, MON_1, 1, 1) + FIELD(XRAM_CLR_EXE, MON_0, 0, 1) +REG32(XRAM_CE_FFA, 0x1c) + FIELD(XRAM_CE_FFA, ADDR, 0, 20) +REG32(XRAM_CE_FFD0, 0x20) +REG32(XRAM_CE_FFD1, 0x24) +REG32(XRAM_CE_FFD2, 0x28) +REG32(XRAM_CE_FFD3, 0x2c) +REG32(XRAM_CE_FFE, 0x30) + FIELD(XRAM_CE_FFE, SYNDROME, 0, 16) +REG32(XRAM_UE_FFA, 0x34) + FIELD(XRAM_UE_FFA, ADDR, 0, 20) +REG32(XRAM_UE_FFD0, 0x38) +REG32(XRAM_UE_FFD1, 0x3c) +REG32(XRAM_UE_FFD2, 0x40) +REG32(XRAM_UE_FFD3, 0x44) +REG32(XRAM_UE_FFE, 0x48) + FIELD(XRAM_UE_FFE, SYNDROME, 0, 16) +REG32(XRAM_FI_D0, 0x4c) +REG32(XRAM_FI_D1, 0x50) +REG32(XRAM_FI_D2, 0x54) +REG32(XRAM_FI_D3, 0x58) +REG32(XRAM_FI_SY, 0x5c) + FIELD(XRAM_FI_SY, DATA, 0, 16) +REG32(XRAM_RMW_UE_FFA, 0x70) + FIELD(XRAM_RMW_UE_FFA, ADDR, 0, 20) +REG32(XRAM_FI_CNTR, 0x74) + FIELD(XRAM_FI_CNTR, COUNT, 0, 24) +REG32(XRAM_IMP, 0x80) + FIELD(XRAM_IMP, SIZE, 0, 4) +REG32(XRAM_PRDY_DBG, 0x84) + FIELD(XRAM_PRDY_DBG, ISLAND3, 12, 4) + FIELD(XRAM_PRDY_DBG, ISLAND2, 8, 4) + FIELD(XRAM_PRDY_DBG, ISLAND1, 4, 4) + FIELD(XRAM_PRDY_DBG, ISLAND0, 0, 4) +REG32(XRAM_SAFETY_CHK, 0xff8) + +#define XRAM_CTRL_R_MAX (R_XRAM_SAFETY_CHK + 1) + +typedef struct XlnxXramCtrl { + SysBusDevice parent_obj; + MemoryRegion iomem; + MemoryRegion ram; + qemu_irq irq; + + struct { + uint64_t size; + unsigned int encoded_size; + } cfg; + + uint32_t regs[XRAM_CTRL_R_MAX]; + RegisterInfo regs_info[XRAM_CTRL_R_MAX]; +} XlnxXramCtrl; +#endif diff --git a/hw/misc/xlnx-versal-xramc.c b/hw/misc/xlnx-versal-xramc.c new file mode 100644 index 0000000000..c7f449fefa --- /dev/null +++ b/hw/misc/xlnx-versal-xramc.c @@ -0,0 +1,253 @@ +/* + * QEMU model of the Xilinx XRAM Controller. + * + * Copyright (c) 2021 Xilinx Inc. + * SPDX-License-Identifier: GPL-2.0-or-later + * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/bitops.h" +#include "qapi/error.h" +#include "migration/vmstate.h" +#include "hw/sysbus.h" +#include "hw/register.h" +#include "hw/qdev-properties.h" +#include "hw/irq.h" +#include "hw/misc/xlnx-versal-xramc.h" + +#ifndef XLNX_XRAM_CTRL_ERR_DEBUG +#define XLNX_XRAM_CTRL_ERR_DEBUG 0 +#endif + +static void xram_update_irq(XlnxXramCtrl *s) +{ + bool pending = s->regs[R_XRAM_ISR] & ~s->regs[R_XRAM_IMR]; + qemu_set_irq(s->irq, pending); +} + +static void xram_isr_postw(RegisterInfo *reg, uint64_t val64) +{ + XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); + xram_update_irq(s); +} + +static uint64_t xram_ien_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); + uint32_t val = val64; + + s->regs[R_XRAM_IMR] &= ~val; + xram_update_irq(s); + return 0; +} + +static uint64_t xram_ids_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque); + uint32_t val = val64; + + s->regs[R_XRAM_IMR] |= val; + xram_update_irq(s); + return 0; +} + +static const RegisterAccessInfo xram_ctrl_regs_info[] = { + { .name = "XRAM_ERR_CTRL", .addr = A_XRAM_ERR_CTRL, + .reset = 0xf, + .rsvd = 0xfffffff0, + },{ .name = "XRAM_ISR", .addr = A_XRAM_ISR, + .rsvd = 0xfffff800, + .w1c = 0x7ff, + .post_write = xram_isr_postw, + },{ .name = "XRAM_IMR", .addr = A_XRAM_IMR, + .reset = 0x7ff, + .rsvd = 0xfffff800, + .ro = 0x7ff, + },{ .name = "XRAM_IEN", .addr = A_XRAM_IEN, + .rsvd = 0xfffff800, + .pre_write = xram_ien_prew, + },{ .name = "XRAM_IDS", .addr = A_XRAM_IDS, + .rsvd = 0xfffff800, + .pre_write = xram_ids_prew, + },{ .name = "XRAM_ECC_CNTL", .addr = A_XRAM_ECC_CNTL, + .rsvd = 0xfffffff8, + },{ .name = "XRAM_CLR_EXE", .addr = A_XRAM_CLR_EXE, + .rsvd = 0xffffff00, + },{ .name = "XRAM_CE_FFA", .addr = A_XRAM_CE_FFA, + .rsvd = 0xfff00000, + .ro = 0xfffff, + },{ .name = "XRAM_CE_FFD0", .addr = A_XRAM_CE_FFD0, + .ro = 0xffffffff, + },{ .name = "XRAM_CE_FFD1", .addr = A_XRAM_CE_FFD1, + .ro = 0xffffffff, + },{ .name = "XRAM_CE_FFD2", .addr = A_XRAM_CE_FFD2, + .ro = 0xffffffff, + },{ .name = "XRAM_CE_FFD3", .addr = A_XRAM_CE_FFD3, + .ro = 0xffffffff, + },{ .name = "XRAM_CE_FFE", .addr = A_XRAM_CE_FFE, + .rsvd = 0xffff0000, + .ro = 0xffff, + },{ .name = "XRAM_UE_FFA", .addr = A_XRAM_UE_FFA, + .rsvd = 0xfff00000, + .ro = 0xfffff, + },{ .name = "XRAM_UE_FFD0", .addr = A_XRAM_UE_FFD0, + .ro = 0xffffffff, + },{ .name = "XRAM_UE_FFD1", .addr = A_XRAM_UE_FFD1, + .ro = 0xffffffff, + },{ .name = "XRAM_UE_FFD2", .addr = A_XRAM_UE_FFD2, + .ro = 0xffffffff, + },{ .name = "XRAM_UE_FFD3", .addr = A_XRAM_UE_FFD3, + .ro = 0xffffffff, + },{ .name = "XRAM_UE_FFE", .addr = A_XRAM_UE_FFE, + .rsvd = 0xffff0000, + .ro = 0xffff, + },{ .name = "XRAM_FI_D0", .addr = A_XRAM_FI_D0, + },{ .name = "XRAM_FI_D1", .addr = A_XRAM_FI_D1, + },{ .name = "XRAM_FI_D2", .addr = A_XRAM_FI_D2, + },{ .name = "XRAM_FI_D3", .addr = A_XRAM_FI_D3, + },{ .name = "XRAM_FI_SY", .addr = A_XRAM_FI_SY, + .rsvd = 0xffff0000, + },{ .name = "XRAM_RMW_UE_FFA", .addr = A_XRAM_RMW_UE_FFA, + .rsvd = 0xfff00000, + .ro = 0xfffff, + },{ .name = "XRAM_FI_CNTR", .addr = A_XRAM_FI_CNTR, + .rsvd = 0xff000000, + },{ .name = "XRAM_IMP", .addr = A_XRAM_IMP, + .reset = 0x4, + .rsvd = 0xfffffff0, + .ro = 0xf, + },{ .name = "XRAM_PRDY_DBG", .addr = A_XRAM_PRDY_DBG, + .reset = 0xffff, + .rsvd = 0xffff0000, + .ro = 0xffff, + },{ .name = "XRAM_SAFETY_CHK", .addr = A_XRAM_SAFETY_CHK, + } +}; + +static void xram_ctrl_reset_enter(Object *obj, ResetType type) +{ + XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { + register_reset(&s->regs_info[i]); + } + + ARRAY_FIELD_DP32(s->regs, XRAM_IMP, SIZE, s->cfg.encoded_size); +} + +static void xram_ctrl_reset_hold(Object *obj) +{ + XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); + + xram_update_irq(s); +} + +static const MemoryRegionOps xram_ctrl_ops = { + .read = register_read_memory, + .write = register_write_memory, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void xram_ctrl_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + XlnxXramCtrl *s = XLNX_XRAM_CTRL(dev); + + switch (s->cfg.size) { + case 64 * KiB: + s->cfg.encoded_size = 0; + break; + case 128 * KiB: + s->cfg.encoded_size = 1; + break; + case 256 * KiB: + s->cfg.encoded_size = 2; + break; + case 512 * KiB: + s->cfg.encoded_size = 3; + break; + case 1 * MiB: + s->cfg.encoded_size = 4; + break; + default: + error_setg(errp, "Unsupported XRAM size %" PRId64, s->cfg.size); + return; + } + + memory_region_init_ram(&s->ram, OBJECT(s), + object_get_canonical_path_component(OBJECT(s)), + s->cfg.size, &error_fatal); + sysbus_init_mmio(sbd, &s->ram); +} + +static void xram_ctrl_init(Object *obj) +{ + XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + RegisterInfoArray *reg_array; + + memory_region_init(&s->iomem, obj, TYPE_XLNX_XRAM_CTRL, + XRAM_CTRL_R_MAX * 4); + reg_array = + register_init_block32(DEVICE(obj), xram_ctrl_regs_info, + ARRAY_SIZE(xram_ctrl_regs_info), + s->regs_info, s->regs, + &xram_ctrl_ops, + XLNX_XRAM_CTRL_ERR_DEBUG, + XRAM_CTRL_R_MAX * 4); + memory_region_add_subregion(&s->iomem, + 0x0, + ®_array->mem); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); +} + +static const VMStateDescription vmstate_xram_ctrl = { + .name = TYPE_XLNX_XRAM_CTRL, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, XlnxXramCtrl, XRAM_CTRL_R_MAX), + VMSTATE_END_OF_LIST(), + } +}; + +static Property xram_ctrl_properties[] = { + DEFINE_PROP_UINT64("size", XlnxXramCtrl, cfg.size, 1 * MiB), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xram_ctrl_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = xram_ctrl_realize; + dc->vmsd = &vmstate_xram_ctrl; + device_class_set_props(dc, xram_ctrl_properties); + + rc->phases.enter = xram_ctrl_reset_enter; + rc->phases.hold = xram_ctrl_reset_hold; +} + +static const TypeInfo xram_ctrl_info = { + .name = TYPE_XLNX_XRAM_CTRL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XlnxXramCtrl), + .class_init = xram_ctrl_class_init, + .instance_init = xram_ctrl_init, +}; + +static void xram_ctrl_register_types(void) +{ + type_register_static(&xram_ctrl_info); +} + +type_init(xram_ctrl_register_types) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 629283957f..fbc4789249 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -85,6 +85,7 @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files( )) softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c')) softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c', 'zynq-xadc.c')) +softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-xramc.c')) softmmu_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c')) softmmu_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c')) softmmu_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c'))