:p
atchew
Login
Hi; here's an arm pullreq. This is mostly bug fixes; the new features are emulation of a couple of small Arm CPU features. thanks -- PMM The following changes since commit 2db91528542672cf0db78b3f2cc0e22b36302b38: Merge tag 'pull-vfio-20260527' of https://github.com/legoater/qemu into staging (2026-05-27 14:45:58 -0400) are available in the Git repository at: https://gitlab.com/pm215/qemu.git tags/pull-target-arm-20260529 for you to fetch changes up to 44f2c7f3df0028de7991385f568add12e24aca47: hw/dma/omap_dma: Fix indentation after ifdef removal (2026-05-29 10:18:11 +0100) ---------------------------------------------------------------- target-arm queue: * target/arm: Implement FEAT_CMPBR emulation * target/arm: Implement FEAT_RNG_TRAP emulation * target/arm: Don't assert if 64-bit EL2 AT insn sees a Domain fault * target/arm: SME BFCVT, BFCVTN have "Alternate BFloat16 behaviors" * target/arm: Enable REVD for SVE2.1 * zynq: Various minor bug fixes * hw/misc: Add dummy ZYNQ DDR controller * hw/block/m25p80: Add HAS_SR_TB flag for is25lp016d * hw/dma/omap_dma: Remove unused ifdeffed out code ---------------------------------------------------------------- Jason Wright (2): target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS target/arm: advertise FEAT_RNG_TRAP on cortex-max Peter Maydell (5): target/arm: Don't assert if 64-bit EL2 AT insn sees a Domain fault target/arm: SME BFCVT, BFCVTN have "Alternate BFloat16 behaviors" hw/dma/omap_dma: Remove unused ifdeffed out code hw/dma/omap_dma: Fix coding style in omap_dma_transfer_setup() hw/dma/omap_dma: Fix indentation after ifdef removal Richard Henderson (5): target/arm: Enable REVD for SVE2.1 target/arm: Add feature predicate for FEAT_CMPBR target/arm: Implement CB, CBB, CBH target/arm: Implement CB (immediate) target/arm: Enable FEAT_CMPBR for -cpu max YannickV (9): hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff hw/arm/zynq-devcfg: Prevent unintended unlock during initialization hw/dma/zynq: Ensure PCFG_DONE bit remains set to indicate PL is in user mode hw/dma/zynq-devcfg: Simulate dummy PL reset hw/dma/zynq-devcfg: Indicate power-up status of PL hw/misc: Add dummy ZYNQ DDR controller hw/misc/zynq_slcr: Add logic for DCI configuration hw/block/m25p80: Add HAS_SR_TB flag for is25lp016d hw/arm/xilinx_zynq: Split xilinx_zynq into header and implementation files MAINTAINERS | 2 + docs/system/arm/emulation.rst | 2 + hw/arm/Kconfig | 1 + hw/arm/xilinx_zynq.c | 29 ++- hw/block/m25p80.c | 3 +- hw/dma/omap_dma.c | 247 ++++++++--------------- hw/dma/xlnx-zynq-devcfg.c | 27 ++- hw/misc/Kconfig | 3 + hw/misc/meson.build | 1 + hw/misc/xlnx-zynq-ddrc.c | 421 +++++++++++++++++++++++++++++++++++++++ hw/misc/zynq_slcr.c | 31 +++ include/hw/arm/xilinx_zynq.h | 30 +++ include/hw/misc/xlnx-zynq-ddrc.h | 147 ++++++++++++++ linux-user/aarch64/elfload.c | 1 + target/arm/cpu-features.h | 10 + target/arm/helper.c | 58 +++++- target/arm/internals.h | 10 + target/arm/tcg/a64.decode | 11 + target/arm/tcg/cpu64.c | 3 +- target/arm/tcg/translate-a64.c | 86 ++++++++ target/arm/tcg/translate-sme.c | 4 +- target/arm/tcg/translate-sve.c | 3 +- 22 files changed, 939 insertions(+), 191 deletions(-) create mode 100644 hw/misc/xlnx-zynq-ddrc.c create mode 100644 include/hw/arm/xilinx_zynq.h create mode 100644 include/hw/misc/xlnx-zynq-ddrc.h
From: Richard Henderson <richard.henderson@linaro.org> Cc: qemu-stable@nongnu.org Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260522220408.235438-1-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/translate-sve.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(REVH, aa64_sme_or_sve, gen_gvec_ool_arg_zpz, revh_fns[a->esz], a, 0) TRANS_FEAT(REVW, aa64_sme_or_sve, gen_gvec_ool_arg_zpz, a->esz == 3 ? gen_helper_sve_revw_d : NULL, a, 0) -TRANS_FEAT(REVD, aa64_sme, gen_gvec_ool_arg_zpz, gen_helper_sme_revd_q, a, 0) +TRANS_FEAT(REVD, aa64_sme_or_sve2p1, gen_gvec_ool_arg_zpz, + gen_helper_sme_revd_q, a, 0) TRANS_FEAT(SPLICE, aa64_sme_or_sve, gen_gvec_ool_arg_zpzz, gen_helper_sve_splice, a, a->esz) -- 2.43.0
From: YannickV <Y.Vossen@beckhoff.com> A DMA transfer to destination address `0xffffffff` should trigger a bitstream load via the PCAP interface. Currently, this case is not intercepted, causing loaders to enter an infinite loop when polling the status register. This commit adds a check for `0xffffffff` as the destination address. If detected, the relevant status register bits (`DMA_DONE`, `DMA_P_DONE`, and `PCFG_DONE`) are set to indicate a successful bitstream load. If the address is different, the DMA transfer proceeds as usual. A successful load is indicated but nothing is actually done. Guests relying on FPGA functions are still known to fail. This feature is required for the integration of the Beckhoff CX7200 model. Signed-off-by: YannickV <Y.Vossen@beckhoff.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com> Message-id: 20260518073401.11279-2-corvin.koehne@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/dma/xlnx-zynq-devcfg.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/dma/xlnx-zynq-devcfg.c +++ b/hw/dma/xlnx-zynq-devcfg.c @@ -XXX,XX +XXX,XX @@ static uint64_t r_lock_pre_write(RegisterInfo *reg, uint64_t val) static void r_dma_dst_len_post_write(RegisterInfo *reg, uint64_t val) { XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); - + if ((s->regs[R_DMA_DST_ADDR]) == 0xffffffff) { + DB_PRINT("bitstream loading detected\n"); + s->regs[R_INT_STS] |= R_INT_STS_DMA_DONE_MASK | + R_INT_STS_DMA_P_DONE_MASK | + R_INT_STS_PCFG_DONE_MASK; + xlnx_zynq_devcfg_update_ixr(s); + return; + } s->dma_cmd_fifo[s->dma_cmd_fifo_num] = (XlnxZynqDevcfgDMACmd) { .src_addr = s->regs[R_DMA_SRC_ADDR] & ~0x3UL, .dest_addr = s->regs[R_DMA_DST_ADDR] & ~0x3UL, -- 2.43.0
From: YannickV <Y.Vossen@beckhoff.com> During the emulation startup, all registers are reset, which triggers the `r_unlock_post_write` function with a value of 0. This led to an unintended memory access disable, making the devcfg unusable. During startup, the memory space no longer gets locked. Signed-off-by: YannickV <Y.Vossen@beckhoff.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com> Message-id: 20260518073401.11279-3-corvin.koehne@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/dma/xlnx-zynq-devcfg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/dma/xlnx-zynq-devcfg.c +++ b/hw/dma/xlnx-zynq-devcfg.c @@ -XXX,XX +XXX,XX @@ static void r_unlock_post_write(RegisterInfo *reg, uint64_t val) { XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); const char *device_prefix = object_get_typename(OBJECT(s)); - + if (device_is_in_reset(DEVICE(s))) { + return; + } if (val == R_UNLOCK_MAGIC) { DB_PRINT("successful unlock\n"); s->regs[R_CTRL] |= R_CTRL_PCAP_PR_MASK; -- 2.43.0
From: YannickV <Y.Vossen@beckhoff.com> All register bits are clear on write by writing 1s to those bits, however the register bits will only be cleared if the condition that sets the interrupt flag is no longer true. Since we can assume that programming is always done, the `PCFG_DONE` flag is always set to 1, so it will not never be cleared. Signed-off-by: YannickV <Y.Vossen@beckhoff.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com> Message-id: 20260518073401.11279-4-corvin.koehne@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/dma/xlnx-zynq-devcfg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/dma/xlnx-zynq-devcfg.c +++ b/hw/dma/xlnx-zynq-devcfg.c @@ -XXX,XX +XXX,XX @@ static void r_ixr_post_write(RegisterInfo *reg, uint64_t val) { XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); + s->regs[R_INT_STS] |= R_INT_STS_PCFG_DONE_MASK; + xlnx_zynq_devcfg_update_ixr(s); } -- 2.43.0
From: YannickV <Y.Vossen@beckhoff.com> Setting PCFG_PROG_B should reset the PL. After a reset PCFG_INIT should indicate that the reset is finished successfully. In order to add a MMIO-Device as part of the PL in the Zynq, the reset logic must succeed. The PCFG_INIT flag is now set when the PL reset is triggered by PCFG_PROG_B. Indicating the reset was successful. Signed-off-by: YannickV <Y.Vossen@beckhoff.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com> Message-id: 20260518073401.11279-5-corvin.koehne@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/dma/xlnx-zynq-devcfg.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/dma/xlnx-zynq-devcfg.c +++ b/hw/dma/xlnx-zynq-devcfg.c @@ -XXX,XX +XXX,XX @@ REG32(CTRL, 0x00) FIELD(CTRL, FORCE_RST, 31, 1) /* Not supported, wr ignored */ + FIELD(CTRL, PCFG_PROG_B, 30, 1) FIELD(CTRL, PCAP_PR, 27, 1) /* Forced to 0 on bad unlock */ FIELD(CTRL, PCAP_MODE, 26, 1) FIELD(CTRL, MULTIBOOT_EN, 24, 1) @@ -XXX,XX +XXX,XX @@ REG32(STATUS, 0x14) FIELD(STATUS, PSS_GTS_USR_B, 11, 1) FIELD(STATUS, PSS_FST_CFG_B, 10, 1) FIELD(STATUS, PSS_CFG_RESET_B, 5, 1) + FIELD(STATUS, PCFG_INIT, 4, 1) REG32(DMA_SRC_ADDR, 0x18) REG32(DMA_DST_ADDR, 0x1C) @@ -XXX,XX +XXX,XX @@ static uint64_t r_ctrl_pre_write(RegisterInfo *reg, uint64_t val) val |= lock_ctrl_map[i] & s->regs[R_CTRL]; } } + + if (FIELD_EX32(val, CTRL, PCFG_PROG_B)) { + s->regs[R_STATUS] |= R_STATUS_PCFG_INIT_MASK; + } else { + s->regs[R_STATUS] &= ~R_STATUS_PCFG_INIT_MASK; + } + return val; } -- 2.43.0
From: YannickV <Y.Vossen@beckhoff.com> It is assumed, that the programmable logic (PL) is always powered during emulation. Therefor the PCFG_POR_B bit in the MCTRL register is set. Signed-off-by: YannickV <Y.Vossen@beckhoff.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com> Message-id: 20260518073401.11279-6-corvin.koehne@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/dma/xlnx-zynq-devcfg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/dma/xlnx-zynq-devcfg.c +++ b/hw/dma/xlnx-zynq-devcfg.c @@ -XXX,XX +XXX,XX @@ static const RegisterAccessInfo xlnx_zynq_devcfg_regs_info[] = { /* Silicon 3.0 for version field, the mysterious reserved bit 23 * and QEMU platform identifier. */ - .reset = 0x2 << R_MCTRL_PS_VERSION_SHIFT | 1 << 23 | R_MCTRL_QEMU_MASK, + .reset = 0x2 << R_MCTRL_PS_VERSION_SHIFT | 1 << 23 | + R_MCTRL_PCFG_POR_B_MASK | R_MCTRL_QEMU_MASK, .ro = ~R_MCTRL_INT_PCAP_LPBK_MASK, .rsvd = 0x00f00303, }, -- 2.43.0
From: YannickV <Y.Vossen@beckhoff.com> A dummy DDR controller for ZYNQ has been added. While all registers are present, not all are functional. Read and write access is validated, and the user mode can be set. This provides a basic DDR controller initialization, preventing system hangs due to endless polling or similar issues. Signed-off-by: YannickV <Y.Vossen@beckhoff.com> Message-id: 20260518073401.11279-7-corvin.koehne@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- MAINTAINERS | 2 + hw/arm/Kconfig | 1 + hw/arm/xilinx_zynq.c | 16 +- hw/misc/Kconfig | 3 + hw/misc/meson.build | 1 + hw/misc/xlnx-zynq-ddrc.c | 421 +++++++++++++++++++++++++++++++ include/hw/misc/xlnx-zynq-ddrc.h | 147 +++++++++++ 7 files changed, 588 insertions(+), 3 deletions(-) create mode 100644 hw/misc/xlnx-zynq-ddrc.c create mode 100644 include/hw/misc/xlnx-zynq-ddrc.h diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org S: Maintained F: hw/*/xilinx_* F: hw/*/cadence_* +F: hw/misc/xlnx-zynq-ddrc.c F: hw/misc/zynq_slcr.c F: hw/adc/zynq-xadc.c +F: include/hw/misc/xlnx-zynq-ddrc.h F: include/hw/misc/zynq_slcr.h F: include/hw/adc/zynq-xadc.h X: hw/ssi/xilinx_* diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config ZYNQ select XILINX_AXI select XILINX_SPI select XILINX_SPIPS + select XLNX_ZYNQ_DDRC select ZYNQ_DEVCFG config ARM_V7M diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -XXX,XX +XXX,XX @@ static void zynq_set_boot_mode(Object *obj, const char *str, m->boot_mode = mode; } +static void ddr_ctrl_init(uint32_t base) +{ + DeviceState *dev; + SysBusDevice *busdev; + + dev = qdev_new("zynq.ddr-ctlr"); + busdev = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(busdev, &error_fatal); + sysbus_mmio_map(busdev, 0, base); +} + static void zynq_init(MachineState *machine) { ZynqMachineState *zynq_machine = ZYNQ_MACHINE(machine); @@ -XXX,XX +XXX,XX @@ static void zynq_init(MachineState *machine) sysbus_create_varargs("cadence_ttc", 0xF8002000, pic[69-GIC_INTERNAL], pic[70-GIC_INTERNAL], pic[71-GIC_INTERNAL], NULL); + ddr_ctrl_init(0xF8006000); + gem_init(0xE000B000, pic[54 - GIC_INTERNAL]); gem_init(0xE000C000, pic[77 - GIC_INTERNAL]); @@ -XXX,XX +XXX,XX @@ static void zynq_init(MachineState *machine) /* System Watchdog Timer Registers */ create_unimplemented_device("zynq.swdt", 0xF8005000, 4 * KiB); - /* DDR memory controller */ - create_unimplemented_device("zynq.ddrc", 0xF8006000, 4 * KiB); - /* AXI_HP Interface (AFI) */ create_unimplemented_device("zynq.axi_hp0", 0xF8008000, 0x28); create_unimplemented_device("zynq.axi_hp1", 0xF8009000, 0x28); diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -XXX,XX +XXX,XX @@ config IOSB config XLNX_VERSAL_TRNG bool +config XLNX_ZYNQ_DDRC + bool + source macio/Kconfig diff --git a/hw/misc/meson.build b/hw/misc/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_RASPI', if_true: files( )) system_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c')) system_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c')) +system_ss.add(when: 'CONFIG_XLNX_ZYNQ_DDRC', if_true: files('xlnx-zynq-ddrc.c')) system_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-crf.c')) system_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-apu-ctrl.c')) system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files( diff --git a/hw/misc/xlnx-zynq-ddrc.c b/hw/misc/xlnx-zynq-ddrc.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/misc/xlnx-zynq-ddrc.c @@ -XXX,XX +XXX,XX @@ +/* + * QEMU model of the Xilinx Zynq Double Data Rate Controller + * + * Copyright (c) Beckhoff Automation GmbH. & Co. KG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/core/sysbus.h" +#include "hw/core/register.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "hw/core/registerfields.h" +#include "system/block-backend.h" +#include "system/address-spaces.h" +#include "system/memory.h" +#include "system/dma.h" +#include "hw/misc/xlnx-zynq-ddrc.h" +#include "migration/vmstate.h" + +#ifndef DDRCTRL_ERR_DEBUG +#define DDRCTRL_ERR_DEBUG 0 +#endif + +static void zynq_ddrctrl_post_write(RegisterInfo *reg, uint64_t val) +{ + DDRCTRLState *s = DDRCTRL(reg->opaque); + if (reg->access->addr == A_DDRC_CTRL) { + if (val & 0x1) { + s->reg[R_MODE_STS_REG] |= + (R_MODE_STS_REG_DDR_REG_OPERATING_MODE_MASK & 0x1); + } else { + s->reg[R_MODE_STS_REG] &= + ~R_MODE_STS_REG_DDR_REG_OPERATING_MODE_MASK; + } + } +} + +static const RegisterAccessInfo xlnx_zynq_ddrc_regs_info[] = { + /* 0x00 - 0x3C: Basic DDRC control and config */ + { .name = "DDRC_CTRL", + .addr = A_DDRC_CTRL, + .reset = 0x00000200, + .post_write = zynq_ddrctrl_post_write }, + { .name = "TWO_RANK_CFG", + .addr = A_TWO_RANK_CFG, + .reset = 0x000C1076 }, + { .name = "HPR_REG", + .addr = A_HPR_REG, + .reset = 0x03C0780F }, + { .name = "LPR_REG", + .addr = A_LPR_REG, + .reset = 0x03C0780F }, + { .name = "WR_REG", + .addr = A_WR_REG, + .reset = 0x0007F80F }, + { .name = "DRAM_PARAM_REG0", + .addr = A_DRAM_PARAM_REG0, + .reset = 0x00041016 }, + { .name = "DRAM_PARAM_REG1", + .addr = A_DRAM_PARAM_REG1, + .reset = 0x351B48D9 }, + { .name = "DRAM_PARAM_REG2", + .addr = A_DRAM_PARAM_REG2, + .reset = 0x83015904 }, + { .name = "DRAM_PARAM_REG3", + .addr = A_DRAM_PARAM_REG3, + .reset = 0x250882D0 }, + { .name = "DRAM_PARAM_REG4", + .addr = A_DRAM_PARAM_REG4, + .reset = 0x0000003C }, + { .name = "DRAM_INIT_PARAM", + .addr = A_DRAM_INIT_PARAM, + .reset = 0x00002007 }, + { .name = "DRAM_EMR_REG", + .addr = A_DRAM_EMR_REG, + .reset = 0x00000008 }, + { .name = "DRAM_EMR_MR_REG", + .addr = A_DRAM_EMR_MR_REG, + .reset = 0x00000940 }, + { .name = "DRAM_BURST8_RDWR", + .addr = A_DRAM_BURST8_RDWR, + .reset = 0x00020034 }, + { .name = "DRAM_DISABLE_DQ", + .addr = A_DRAM_DISABLE_DQ }, + { .name = "DRAM_ADDR_MAP_BANK", + .addr = A_DRAM_ADDR_MAP_BANK, + .reset = 0x00000F77 }, + { .name = "DRAM_ADDR_MAP_COL", + .addr = A_DRAM_ADDR_MAP_COL, + .reset = 0xFFF00000 }, + { .name = "DRAM_ADDR_MAP_ROW", + .addr = A_DRAM_ADDR_MAP_ROW, + .reset = 0x0FF55555 }, + { .name = "DRAM_ODT_REG", + .addr = A_DRAM_ODT_REG, + .reset = 0x00000249 }, + + /* 0x4C - 0x5C: PHY and DLL */ + { .name = "PHY_DBG_REG", + .addr = A_PHY_DBG_REG }, + { .name = "PHY_CMD_TIMEOUT_RDDATA_CPT", + .addr = A_PHY_CMD_TIMEOUT_RDDATA_CPT, + .reset = 0x00010200 }, + { .name = "MODE_STS_REG", + .addr = A_MODE_STS_REG }, + { .name = "DLL_CALIB", + .addr = A_DLL_CALIB, + .reset = 0x00000101 }, + { .name = "ODT_DELAY_HOLD", + .addr = A_ODT_DELAY_HOLD, + .reset = 0x00000023 }, + + /* 0x60 - 0x7C: Control registers */ + { .name = "CTRL_REG1", + .addr = A_CTRL_REG1, + .reset = 0x0000003E }, + { .name = "CTRL_REG2", + .addr = A_CTRL_REG2, + .reset = 0x00020000 }, + { .name = "CTRL_REG3", + .addr = A_CTRL_REG3, + .reset = 0x00284027 }, + { .name = "CTRL_REG4", + .addr = A_CTRL_REG4, + .reset = 0x00001610 }, + { .name = "CTRL_REG5", + .addr = A_CTRL_REG5, + .reset = 0x00455111 }, + { .name = "CTRL_REG6", + .addr = A_CTRL_REG6, + .reset = 0x00032222 }, + + /* 0xA0 - 0xB4: Refresh, ZQ, powerdown, misc */ + { .name = "CHE_REFRESH_TIMER0", + .addr = A_CHE_REFRESH_TIMER0, + .reset = 0x00008000 }, + { .name = "CHE_T_ZQ", + .addr = A_CHE_T_ZQ, + .reset = 0x10300802 }, + { .name = "CHE_T_ZQ_SHORT_INTERVAL_REG", + .addr = A_CHE_T_ZQ_SHORT_INTERVAL_REG, + .reset = 0x0020003A }, + { .name = "DEEP_PWRDWN_REG", + .addr = A_DEEP_PWRDWN_REG }, + { .name = "REG_2C", + .addr = A_REG_2C }, + { .name = "REG_2D", + .addr = A_REG_2D, + .reset = 0x00000200 }, + + /* 0xB8 - 0xF8: ECC, DFI, etc. */ + { .name = "DFI_TIMING", + .addr = A_DFI_TIMING, + .reset = 0x00200067 }, + { .name = "CHE_ECC_CONTROL_REG_OFFSET", + .addr = A_CHE_ECC_CONTROL_REG_OFFSET }, + { .name = "CHE_CORR_ECC_LOG_REG_OFFSET", + .addr = A_CHE_CORR_ECC_LOG_REG_OFFSET }, + { .name = "CHE_CORR_ECC_ADDR_REG_OFFSET", + .addr = A_CHE_CORR_ECC_ADDR_REG_OFFSET }, + { .name = "CHE_CORR_ECC_DATA_31_0_REG_OFFSET", + .addr = A_CHE_CORR_ECC_DATA_31_0_REG_OFFSET }, + { .name = "CHE_CORR_ECC_DATA_63_32_REG_OFFSET", + .addr = A_CHE_CORR_ECC_DATA_63_32_REG_OFFSET }, + { .name = "CHE_CORR_ECC_DATA_71_64_REG_OFFSET", + .addr = A_CHE_CORR_ECC_DATA_71_64_REG_OFFSET }, + { .name = "CHE_UNCORR_ECC_LOG_REG_OFFSET", + .addr = A_CHE_UNCORR_ECC_LOG_REG_OFFSET }, + { .name = "CHE_UNCORR_ECC_ADDR_REG_OFFSET", + .addr = A_CHE_UNCORR_ECC_ADDR_REG_OFFSET }, + { .name = "CHE_UNCORR_ECC_DATA_31_0_REG_OFFSET", + .addr = A_CHE_UNCORR_ECC_DATA_31_0_REG_OFFSET }, + { .name = "CHE_UNCORR_ECC_DATA_63_32_REG_OFFSET", + .addr = A_CHE_UNCORR_ECC_DATA_63_32_REG_OFFSET }, + { .name = "CHE_UNCORR_ECC_DATA_71_64_REG_OFFSET", + .addr = A_CHE_UNCORR_ECC_DATA_71_64_REG_OFFSET }, + { .name = "CHE_ECC_STATS_REG_OFFSET", + .addr = A_CHE_ECC_STATS_REG_OFFSET }, + { .name = "ECC_SCRUB", + .addr = A_ECC_SCRUB, + .reset = 0x00000008 }, + { .name = "CHE_ECC_CORR_BIT_MASK_31_0_REG_OFFSET", + .addr = A_CHE_ECC_CORR_BIT_MASK_31_0_REG_OFFSET }, + { .name = "CHE_ECC_CORR_BIT_MASK_63_32_REG_OFFSET", + .addr = A_CHE_ECC_CORR_BIT_MASK_63_32_REG_OFFSET }, + + /* 0x114 - 0x174: PHY config, ratios, DQS, WE */ + { .name = "PHY_RCVER_ENABLE", + .addr = A_PHY_RCVER_ENABLE }, + { .name = "PHY_CONFIG0", + .addr = A_PHY_CONFIG0, + .reset = 0x40000001 }, + { .name = "PHY_CONFIG1", + .addr = A_PHY_CONFIG1, + .reset = 0x40000001 }, + { .name = "PHY_CONFIG2", + .addr = A_PHY_CONFIG2, + .reset = 0x40000001 }, + { .name = "PHY_CONFIG3", + .addr = A_PHY_CONFIG3, + .reset = 0x40000001 }, + { .name = "PHY_INIT_RATIO0", + .addr = A_PHY_INIT_RATIO0 }, + { .name = "PHY_INIT_RATIO1", + .addr = A_PHY_INIT_RATIO1 }, + { .name = "PHY_INIT_RATIO2", + .addr = A_PHY_INIT_RATIO2 }, + { .name = "PHY_INIT_RATIO3", + .addr = A_PHY_INIT_RATIO3 }, + { .name = "PHY_RD_DQS_CFG0", + .addr = A_PHY_RD_DQS_CFG0, + .reset = 0x00000040 }, + { .name = "PHY_RD_DQS_CFG1", + .addr = A_PHY_RD_DQS_CFG1, + .reset = 0x00000040 }, + { .name = "PHY_RD_DQS_CFG2", + .addr = A_PHY_RD_DQS_CFG2, + .reset = 0x00000040 }, + { .name = "PHY_RD_DQS_CFG3", + .addr = A_PHY_RD_DQS_CFG3, + .reset = 0x00000040 }, + { .name = "PHY_WR_DQS_CFG0", + .addr = A_PHY_WR_DQS_CFG0 }, + { .name = "PHY_WR_DQS_CFG1", + .addr = A_PHY_WR_DQS_CFG1 }, + { .name = "PHY_WR_DQS_CFG2", + .addr = A_PHY_WR_DQS_CFG2 }, + { .name = "PHY_WR_DQS_CFG3", + .addr = A_PHY_WR_DQS_CFG3 }, + { .name = "PHY_WE_CFG0", + .addr = A_PHY_WE_CFG0, + .reset = 0x00000040 }, + { .name = "PHY_WE_CFG1", + .addr = A_PHY_WE_CFG1, + .reset = 0x00000040 }, + { .name = "PHY_WE_CFG2", + .addr = A_PHY_WE_CFG2, + .reset = 0x00000040 }, + { .name = "PHY_WE_CFG3", + .addr = A_PHY_WE_CFG3, + .reset = 0x00000040 }, + + /* 0x17C - 0x194: Write data slaves, misc */ + { .name = "WR_DATA_SLV0", + .addr = A_WR_DATA_SLV0, + .reset = 0x00000080 }, + { .name = "WR_DATA_SLV1", + .addr = A_WR_DATA_SLV1, + .reset = 0x00000080 }, + { .name = "WR_DATA_SLV2", + .addr = A_WR_DATA_SLV2, + .reset = 0x00000080 }, + { .name = "WR_DATA_SLV3", + .addr = A_WR_DATA_SLV3, + .reset = 0x00000080 }, + { .name = "REG_64", + .addr = A_REG_64, + .reset = 0x10020000 }, + { .name = "REG_65", + .addr = A_REG_65 }, + + /* 0x1A4 - 0x1C4: Misc registers */ + { .name = "REG69_6A0", + .addr = A_REG69_6A0 }, + { .name = "REG69_6A1", + .addr = A_REG69_6A1 }, + { .name = "REG6C_6D2", + .addr = A_REG6C_6D2 }, + { .name = "REG6C_6D3", + .addr = A_REG6C_6D3 }, + { .name = "REG6E_710", + .addr = A_REG6E_710 }, + { .name = "REG6E_711", + .addr = A_REG6E_711 }, + { .name = "REG6E_712", + .addr = A_REG6E_712 }, + { .name = "REG6E_713", + .addr = A_REG6E_713 }, + + /* 0x1CC - 0x1E8: DLL, PHY status */ + { .name = "PHY_DLL_STS0", + .addr = A_PHY_DLL_STS0 }, + { .name = "PHY_DLL_STS1", + .addr = A_PHY_DLL_STS1 }, + { .name = "PHY_DLL_STS2", + .addr = A_PHY_DLL_STS2 }, + { .name = "PHY_DLL_STS3", + .addr = A_PHY_DLL_STS3 }, + { .name = "DLL_LOCK_STS", + .addr = A_DLL_LOCK_STS }, + { .name = "PHY_CTRL_STS", + .addr = A_PHY_CTRL_STS }, + { .name = "PHY_CTRL_STS_REG2", + .addr = A_PHY_CTRL_STS_REG2 }, + + /* 0x200 - 0x2B4: AXI, LPDDR, misc */ + { .name = "AXI_ID", + .addr = A_AXI_ID }, + { .name = "PAGE_MASK", + .addr = A_PAGE_MASK }, + { .name = "AXI_PRIORITY_WR_PORT0", + .addr = A_AXI_PRIORITY_WR_PORT0, + .reset = 0x000803FF }, + { .name = "AXI_PRIORITY_WR_PORT1", + .addr = A_AXI_PRIORITY_WR_PORT1, + .reset = 0x000803FF }, + { .name = "AXI_PRIORITY_WR_PORT2", + .addr = A_AXI_PRIORITY_WR_PORT2, + .reset = 0x000803FF }, + { .name = "AXI_PRIORITY_WR_PORT3", + .addr = A_AXI_PRIORITY_WR_PORT3, + .reset = 0x000803FF }, + { .name = "AXI_PRIORITY_RD_PORT0", + .addr = A_AXI_PRIORITY_RD_PORT0, + .reset = 0x000003FF }, + { .name = "AXI_PRIORITY_RD_PORT1", + .addr = A_AXI_PRIORITY_RD_PORT1, + .reset = 0x000003FF }, + { .name = "AXI_PRIORITY_RD_PORT2", + .addr = A_AXI_PRIORITY_RD_PORT2, + .reset = 0x000003FF }, + { .name = "AXI_PRIORITY_RD_PORT3", + .addr = A_AXI_PRIORITY_RD_PORT3, + .reset = 0x000003FF }, + { .name = "EXCL_ACCESS_CFG0", + .addr = A_EXCL_ACCESS_CFG0 }, + { .name = "EXCL_ACCESS_CFG1", + .addr = A_EXCL_ACCESS_CFG1 }, + { .name = "EXCL_ACCESS_CFG2", + .addr = A_EXCL_ACCESS_CFG2 }, + { .name = "EXCL_ACCESS_CFG3", + .addr = A_EXCL_ACCESS_CFG3 }, + { .name = "MODE_REG_READ", + .addr = A_MODE_REG_READ }, + { .name = "LPDDR_CTRL0", + .addr = A_LPDDR_CTRL0 }, + { .name = "LPDDR_CTRL1", + .addr = A_LPDDR_CTRL1 }, + { .name = "LPDDR_CTRL2", + .addr = A_LPDDR_CTRL2, + .reset = 0x003C0015 }, + { .name = "LPDDR_CTRL3", + .addr = A_LPDDR_CTRL3, + .reset = 0x00000601 }, +}; + +static void zynq_ddrctrl_reset(DeviceState *dev) +{ + DDRCTRLState *s = DDRCTRL(dev); + int i; + + for (i = 0; i < ZYNQ_DDRCTRL_NUM_REG; ++i) { + register_reset(&s->regs_info[i]); + } +} + +static const MemoryRegionOps ddrctrl_ops = { + .read = register_read_memory, + .write = register_write_memory, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static const VMStateDescription vmstate_zynq_ddrctrl = { + .name = "zynq_ddrc", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(reg, DDRCTRLState, ZYNQ_DDRCTRL_NUM_REG), + VMSTATE_END_OF_LIST() + } +}; + +static void zynq_ddrctrl_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DDRCTRLState *s = DDRCTRL(obj); + + s->reg_array = + register_init_block32(DEVICE(obj), xlnx_zynq_ddrc_regs_info, + ARRAY_SIZE(xlnx_zynq_ddrc_regs_info), + s->regs_info, s->reg, + &ddrctrl_ops, + DDRCTRL_ERR_DEBUG, + ZYNQ_DDRCTRL_MMIO_SIZE); + + sysbus_init_mmio(sbd, &s->reg_array->mem); +} + +static void zynq_ddrctrl_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_legacy_reset(dc, zynq_ddrctrl_reset); + dc->vmsd = &vmstate_zynq_ddrctrl; +} + +static const TypeInfo ddrctrl_info = { + .name = TYPE_DDRCTRL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(DDRCTRLState), + .instance_init = zynq_ddrctrl_init, + .class_init = zynq_ddrctrl_class_init, +}; + +static void ddrctrl_register_types(void) +{ + type_register_static(&ddrctrl_info); +} + +type_init(ddrctrl_register_types) diff --git a/include/hw/misc/xlnx-zynq-ddrc.h b/include/hw/misc/xlnx-zynq-ddrc.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/misc/xlnx-zynq-ddrc.h @@ -XXX,XX +XXX,XX @@ +/* + * QEMU model of the Xilinx Zynq Double Data Rate Controller + * + * Copyright (c) Beckhoff Automation GmbH. & Co. KG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef XLNX_ZYNQ_DDRC_H +#define XLNX_ZYNQ_DDRC_H + +#include "hw/core/sysbus.h" +#include "hw/core/register.h" + +#define TYPE_DDRCTRL "zynq.ddr-ctlr" +OBJECT_DECLARE_SIMPLE_TYPE(DDRCTRLState, DDRCTRL) + +REG32(DDRC_CTRL, 0x00) +REG32(TWO_RANK_CFG, 0x04) +REG32(HPR_REG, 0x08) +REG32(LPR_REG, 0x0C) +REG32(WR_REG, 0x10) +REG32(DRAM_PARAM_REG0, 0x14) +REG32(DRAM_PARAM_REG1, 0x18) +REG32(DRAM_PARAM_REG2, 0x1C) +REG32(DRAM_PARAM_REG3, 0x20) +REG32(DRAM_PARAM_REG4, 0x24) +REG32(DRAM_INIT_PARAM, 0x28) +REG32(DRAM_EMR_REG, 0x2C) +REG32(DRAM_EMR_MR_REG, 0x30) +REG32(DRAM_BURST8_RDWR, 0x34) +REG32(DRAM_DISABLE_DQ, 0x38) +REG32(DRAM_ADDR_MAP_BANK, 0x3C) +REG32(DRAM_ADDR_MAP_COL, 0x40) +REG32(DRAM_ADDR_MAP_ROW, 0x44) +REG32(DRAM_ODT_REG, 0x48) +REG32(PHY_DBG_REG, 0x4C) +REG32(PHY_CMD_TIMEOUT_RDDATA_CPT, 0x50) +REG32(MODE_STS_REG, 0x54) + FIELD(MODE_STS_REG, DDR_REG_DBG_STALL, 3, 3) + FIELD(MODE_STS_REG, DDR_REG_OPERATING_MODE, 0, 2) +REG32(DLL_CALIB, 0x58) +REG32(ODT_DELAY_HOLD, 0x5C) +REG32(CTRL_REG1, 0x60) +REG32(CTRL_REG2, 0x64) +REG32(CTRL_REG3, 0x68) +REG32(CTRL_REG4, 0x6C) +REG32(CTRL_REG5, 0x78) +REG32(CTRL_REG6, 0x7C) +REG32(CHE_REFRESH_TIMER0, 0xA0) +REG32(CHE_T_ZQ, 0xA4) +REG32(CHE_T_ZQ_SHORT_INTERVAL_REG, 0xA8) +REG32(DEEP_PWRDWN_REG, 0xAC) +REG32(REG_2C, 0xB0) +REG32(REG_2D, 0xB4) +REG32(DFI_TIMING, 0xB8) +REG32(CHE_ECC_CONTROL_REG_OFFSET, 0xC4) +REG32(CHE_CORR_ECC_LOG_REG_OFFSET, 0xC8) +REG32(CHE_CORR_ECC_ADDR_REG_OFFSET, 0xCC) +REG32(CHE_CORR_ECC_DATA_31_0_REG_OFFSET, 0xD0) +REG32(CHE_CORR_ECC_DATA_63_32_REG_OFFSET, 0xD4) +REG32(CHE_CORR_ECC_DATA_71_64_REG_OFFSET, 0xD8) +REG32(CHE_UNCORR_ECC_LOG_REG_OFFSET, 0xDC) +REG32(CHE_UNCORR_ECC_ADDR_REG_OFFSET, 0xE0) +REG32(CHE_UNCORR_ECC_DATA_31_0_REG_OFFSET, 0xE4) +REG32(CHE_UNCORR_ECC_DATA_63_32_REG_OFFSET, 0xE8) +REG32(CHE_UNCORR_ECC_DATA_71_64_REG_OFFSET, 0xEC) +REG32(CHE_ECC_STATS_REG_OFFSET, 0xF0) +REG32(ECC_SCRUB, 0xF4) +REG32(CHE_ECC_CORR_BIT_MASK_31_0_REG_OFFSET, 0xF8) +REG32(CHE_ECC_CORR_BIT_MASK_63_32_REG_OFFSET, 0xFC) +REG32(PHY_RCVER_ENABLE, 0x114) +REG32(PHY_CONFIG0, 0x118) +REG32(PHY_CONFIG1, 0x11C) +REG32(PHY_CONFIG2, 0x120) +REG32(PHY_CONFIG3, 0x124) +REG32(PHY_INIT_RATIO0, 0x12C) +REG32(PHY_INIT_RATIO1, 0x130) +REG32(PHY_INIT_RATIO2, 0x134) +REG32(PHY_INIT_RATIO3, 0x138) +REG32(PHY_RD_DQS_CFG0, 0x140) +REG32(PHY_RD_DQS_CFG1, 0x144) +REG32(PHY_RD_DQS_CFG2, 0x148) +REG32(PHY_RD_DQS_CFG3, 0x14C) +REG32(PHY_WR_DQS_CFG0, 0x154) +REG32(PHY_WR_DQS_CFG1, 0x158) +REG32(PHY_WR_DQS_CFG2, 0x15C) +REG32(PHY_WR_DQS_CFG3, 0x160) +REG32(PHY_WE_CFG0, 0x168) +REG32(PHY_WE_CFG1, 0x16C) +REG32(PHY_WE_CFG2, 0x170) +REG32(PHY_WE_CFG3, 0x174) +REG32(WR_DATA_SLV0, 0x17C) +REG32(WR_DATA_SLV1, 0x180) +REG32(WR_DATA_SLV2, 0x184) +REG32(WR_DATA_SLV3, 0x188) +REG32(REG_64, 0x190) +REG32(REG_65, 0x194) +REG32(REG69_6A0, 0x1A4) +REG32(REG69_6A1, 0x1A8) +REG32(REG6C_6D2, 0x1B0) +REG32(REG6C_6D3, 0x1B4) +REG32(REG6E_710, 0x1B8) +REG32(REG6E_711, 0x1BC) +REG32(REG6E_712, 0x1C0) +REG32(REG6E_713, 0x1C4) +REG32(PHY_DLL_STS0, 0x1CC) +REG32(PHY_DLL_STS1, 0x1D0) +REG32(PHY_DLL_STS2, 0x1D4) +REG32(PHY_DLL_STS3, 0x1D8) +REG32(DLL_LOCK_STS, 0x1E0) +REG32(PHY_CTRL_STS, 0x1E4) +REG32(PHY_CTRL_STS_REG2, 0x1E8) +REG32(AXI_ID, 0x200) +REG32(PAGE_MASK, 0x204) +REG32(AXI_PRIORITY_WR_PORT0, 0x208) +REG32(AXI_PRIORITY_WR_PORT1, 0x20C) +REG32(AXI_PRIORITY_WR_PORT2, 0x210) +REG32(AXI_PRIORITY_WR_PORT3, 0x214) +REG32(AXI_PRIORITY_RD_PORT0, 0x218) +REG32(AXI_PRIORITY_RD_PORT1, 0x21C) +REG32(AXI_PRIORITY_RD_PORT2, 0x220) +REG32(AXI_PRIORITY_RD_PORT3, 0x224) +REG32(EXCL_ACCESS_CFG0, 0x294) +REG32(EXCL_ACCESS_CFG1, 0x298) +REG32(EXCL_ACCESS_CFG2, 0x29C) +REG32(EXCL_ACCESS_CFG3, 0x2A0) +REG32(MODE_REG_READ, 0x2A4) +REG32(LPDDR_CTRL0, 0x2A8) +REG32(LPDDR_CTRL1, 0x2AC) +REG32(LPDDR_CTRL2, 0x2B0) +REG32(LPDDR_CTRL3, 0x2B4) + + +#define ZYNQ_DDRCTRL_MMIO_SIZE 0x400 +#define ZYNQ_DDRCTRL_NUM_REG (ZYNQ_DDRCTRL_MMIO_SIZE / 4) + +typedef struct DDRCTRLState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + + RegisterInfoArray *reg_array; + uint32_t reg[ZYNQ_DDRCTRL_NUM_REG]; + RegisterInfo regs_info[ZYNQ_DDRCTRL_NUM_REG]; +} DDRCTRLState; +#endif -- 2.43.0
From: YannickV <Y.Vossen@beckhoff.com> The registers for the digitally controlled impedance (DCI) clock are part of the system level control registers (SLCR). The DONE bit in the status register indicates a successfull DCI calibration. An description of the calibration process can be found here: https://docs.amd.com/r/en-US/ug585-zynq-7000-SoC-TRM/DDR-IOB-Impedance-Calibration The DCI control register and status register have been added. As soon as the ENABLE and RESET bit are set, the RESET bit has also been toggled to 0 before and the UPDATE_CONTROL is not set, the DONE bit in the status register is set. If these bits change the DONE bit is reset. Note that the option bits are not taken into consideration. Signed-off-by: YannickV <Y.Vossen@beckhoff.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com> Message-id: 20260518073401.11279-8-corvin.koehne@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/misc/zynq_slcr.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -XXX,XX +XXX,XX @@ REG32(GPIOB_CFG_HSTL, 0xb14) REG32(GPIOB_DRVR_BIAS_CTRL, 0xb18) REG32(DDRIOB, 0xb40) +REG32(DDRIOB_DCI_CTRL, 0xb70) + FIELD(DDRIOB_DCI_CTRL, RESET, 0, 1) + FIELD(DDRIOB_DCI_CTRL, ENABLE, 1, 1) + FIELD(DDRIOB_DCI_CTRL, UPDATE_CONTROL, 20, 1) +REG32(DDRIOB_DCI_STATUS, 0xb74) + FIELD(DDRIOB_DCI_STATUS, DONE, 13, 1) #define DDRIOB_LENGTH 14 #define ZYNQ_SLCR_MMIO_SIZE 0x1000 @@ -XXX,XX +XXX,XX @@ struct ZynqSLCRState { MemoryRegion iomem; + bool ddriob_dci_ctrl_reset_toggled; + uint32_t regs[ZYNQ_SLCR_NUM_REGS]; Clock *ps_clk; @@ -XXX,XX +XXX,XX @@ static void zynq_slcr_reset_init(Object *obj, ResetType type) DB_PRINT("RESET\n"); + s->ddriob_dci_ctrl_reset_toggled = false; + s->regs[R_LOCKSTA] = 1; /* 0x100 - 0x11C */ s->regs[R_ARM_PLL_CTRL] = 0x0001A008; @@ -XXX,XX +XXX,XX @@ static void zynq_slcr_reset_init(Object *obj, ResetType type) s->regs[R_DDRIOB + 4] = s->regs[R_DDRIOB + 5] = s->regs[R_DDRIOB + 6] = 0x00000e00; s->regs[R_DDRIOB + 12] = 0x00000021; + + s->regs[R_DDRIOB_DCI_CTRL] = 0x00000020; } static void zynq_slcr_reset_hold(Object *obj, ResetType type) @@ -XXX,XX +XXX,XX @@ static void zynq_slcr_write(void *opaque, hwaddr offset, (int)offset, (unsigned)val & 0xFFFF); } return; + + case R_DDRIOB_DCI_CTRL: + if (!FIELD_EX32(val, DDRIOB_DCI_CTRL, RESET) && + FIELD_EX32(s->regs[R_DDRIOB_DCI_CTRL], DDRIOB_DCI_CTRL, RESET)) { + + s->ddriob_dci_ctrl_reset_toggled = true; + DB_PRINT("DDRIOB DCI CTRL RESET was toggled\n"); + } + + if (FIELD_EX32(val, DDRIOB_DCI_CTRL, ENABLE) && + FIELD_EX32(val, DDRIOB_DCI_CTRL, RESET) && + !FIELD_EX32(val, DDRIOB_DCI_CTRL, UPDATE_CONTROL) && + s->ddriob_dci_ctrl_reset_toggled) { + + s->regs[R_DDRIOB_DCI_STATUS] |= R_DDRIOB_DCI_STATUS_DONE_MASK; + } else { + s->regs[R_DDRIOB_DCI_STATUS] &= ~R_DDRIOB_DCI_STATUS_DONE_MASK; + } + break; } if (s->regs[R_LOCKSTA]) { -- 2.43.0
From: YannickV <Y.Vossen@beckhoff.com> The is25lp016d has 4 Block Write Protect Bits. BP3 specifies whether the upper or lower range should be protected. Therefore, we add the HAS_SR_TB flag to the is25lp016d flags. Signed-off-by: YannickV <Y.Vossen@beckhoff.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260518073401.11279-10-corvin.koehne@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/block/m25p80.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index XXXXXXX..XXXXXXX 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -XXX,XX +XXX,XX @@ static const FlashPartInfo known_devices[] = { /* ISSI */ { INFO("is25lq040b", 0x9d4013, 0, 64 << 10, 8, ER_4K) }, { INFO("is25lp080d", 0x9d6014, 0, 64 << 10, 16, ER_4K) }, - { INFO("is25lp016d", 0x9d6015, 0, 64 << 10, 32, ER_4K) }, + { INFO("is25lp016d", 0x9d6015, 0, 64 << 10, 32, + ER_4K | HAS_SR_TB) }, { INFO("is25lp032", 0x9d6016, 0, 64 << 10, 64, ER_4K) }, { INFO("is25lp064", 0x9d6017, 0, 64 << 10, 128, ER_4K) }, { INFO("is25lp128", 0x9d6018, 0, 64 << 10, 256, ER_4K) }, -- 2.43.0
From: YannickV <Y.Vossen@beckhoff.com> Create xilinx_zynq.h header file to expose ZynqMachineState and related definitions for machine inheritance. This enables creation of derived machines based on the Zynq platform. Signed-off-by: YannickV <Y.Vossen@beckhoff.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260518073401.11279-11-corvin.koehne@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/xilinx_zynq.c | 13 +------------ include/hw/arm/xilinx_zynq.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 include/hw/arm/xilinx_zynq.h diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -XXX,XX +XXX,XX @@ #include "exec/tswap.h" #include "target/arm/cpu-qom.h" #include "qapi/visitor.h" - -#define TYPE_ZYNQ_MACHINE MACHINE_TYPE_NAME("xilinx-zynq-a9") -OBJECT_DECLARE_SIMPLE_TYPE(ZynqMachineState, ZYNQ_MACHINE) +#include "hw/arm/xilinx_zynq.h" /* board base frequency: 33.333333 MHz */ #define PS_CLK_FREQUENCY (100 * 1000 * 1000 / 3) @@ -XXX,XX +XXX,XX @@ static const int dma_irqs[8] = { 0xe3401000 + ARMV7_IMM16(extract32((val), 16, 16)), /* movt r1 ... */ \ 0xe5801000 + (addr) -#define ZYNQ_MAX_CPUS 2 - -struct ZynqMachineState { - MachineState parent; - Clock *ps_clk; - ARMCPU *cpu[ZYNQ_MAX_CPUS]; - uint8_t boot_mode; -}; - static void zynq_write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info) { diff --git a/include/hw/arm/xilinx_zynq.h b/include/hw/arm/xilinx_zynq.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/arm/xilinx_zynq.h @@ -XXX,XX +XXX,XX @@ +/* + * Xilinx Zynq Baseboard System emulation. + * + * Copyright (c) 2010 Xilinx. + * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.croshtwaite@petalogix.com) + * Copyright (c) 2012 Petalogix Pty Ltd. + * Written by Haibing Ma + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef QEMU_ARM_ZYNQ_H +#define QEMU_ARM_ZYNQ_H + +#include "target/arm/cpu-qom.h" +#include "hw/core/qdev-clock.h" + +#define TYPE_ZYNQ_MACHINE MACHINE_TYPE_NAME("xilinx-zynq-a9") +OBJECT_DECLARE_SIMPLE_TYPE(ZynqMachineState, ZYNQ_MACHINE) + +#define ZYNQ_MAX_CPUS 2 + +struct ZynqMachineState { + MachineState parent; + Clock *ps_clk; + ARMCPU *cpu[ZYNQ_MAX_CPUS]; + uint8_t boot_mode; +}; + +#endif /* QEMU_ARM_ZYNQ_H */ -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260518174750.660258-2-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_cssc(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64ISAR2, CSSC) != 0; } +static inline bool isar_feature_aa64_cmpbr(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64ISAR2, CSSC) >= 2; +} + static inline bool isar_feature_aa64_lut(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64ISAR2, LUT); -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Compare and branch instructions, with various operand widths. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260518174750.660258-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> [PMM: move var decl to top of function] Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 9 +++++++ target/arm/tcg/translate-a64.c | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ TBZ . 011011 nz:1 ..... .............. rt:5 &tbz imm=%imm14 bitpos= # B.cond and BC.cond B_cond 0101010 0 ................... c:1 cond:4 imm=%imm19 +# CB, CBB, CBH +%imm9 5:s9 !function=times_4 +&cb cc rt rm imm esz +@cb . ....... cc:3 rm:5 .. ......... rt:5 &cb imm=%imm9 +CB_cond 0 1110100 ... ..... 00 ......... ..... @cb esz=2 +CB_cond 1 1110100 ... ..... 00 ......... ..... @cb esz=3 +CB_cond 0 1110100 ... ..... 10 ......... ..... @cb esz=0 # CBB +CB_cond 0 1110100 ... ..... 11 ......... ..... @cb esz=1 # CBH + BR 1101011 0000 11111 000000 rn:5 00000 &r BLR 1101011 0001 11111 000000 rn:5 00000 &r RET 1101011 0010 11111 000000 rn:5 00000 &r diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_B_cond(DisasContext *s, arg_B_cond *a) return true; } +static bool trans_CB_cond(DisasContext *s, arg_CB_cond *a) +{ + static const TCGCond cb_cond[8] = { + [0] = TCG_COND_GT, + [1] = TCG_COND_GE, + [2] = TCG_COND_GTU, + [3] = TCG_COND_GEU, + [4] = TCG_COND_NEVER, /* reserved */ + [5] = TCG_COND_NEVER, /* reserved */ + [6] = TCG_COND_EQ, + [7] = TCG_COND_NE, + }; + TCGCond cond = cb_cond[a->cc]; + TCGv_i64 t, m; + DisasLabel match; + + if (!dc_isar_feature(aa64_cmpbr, s) || cond == TCG_COND_NEVER) { + return false; + } + + t = cpu_reg(s, a->rt); + m = cpu_reg(s, a->rm); + if (a->esz != MO_64) { + MemOp mop = a->esz | (is_signed_cond(cond) ? MO_SIGN : 0); + TCGv_i64 tt = tcg_temp_new_i64(); + TCGv_i64 tm = tcg_temp_new_i64(); + + tcg_gen_ext_i64(tt, t, mop); + tcg_gen_ext_i64(tm, m, mop); + t = tt; + m = tm; + } + + reset_btype(s); + match = gen_disas_label(s); + + tcg_gen_brcond_i64(cond, t, m, match.label); + gen_goto_tb(s, 0, 4); + set_disas_label(s, match); + gen_goto_tb(s, 1, a->imm); + return true; +} + static void set_btype_for_br(DisasContext *s, int rn) { if (dc_isar_feature(aa64_bti, s)) { -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260518174750.660258-4-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> [PMM: var decl at top of function; add comment] Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 2 ++ target/arm/tcg/translate-a64.c | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ CB_cond 1 1110100 ... ..... 00 ......... ..... @cb esz=3 CB_cond 0 1110100 ... ..... 10 ......... ..... @cb esz=0 # CBB CB_cond 0 1110100 ... ..... 11 ......... ..... @cb esz=1 # CBH +CB_cond_imm sf:1 1110101 cc:3 imm6:6 0 ......... rt:5 %imm9 + BR 1101011 0000 11111 000000 rn:5 00000 &r BLR 1101011 0001 11111 000000 rn:5 00000 &r RET 1101011 0010 11111 000000 rn:5 00000 &r diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_CB_cond(DisasContext *s, arg_CB_cond *a) return true; } +static bool trans_CB_cond_imm(DisasContext *s, arg_CB_cond_imm *a) +{ + /* Note that CB imm and CB encode the condition differently */ + static const TCGCond cb_cond[8] = { + [0] = TCG_COND_GT, + [1] = TCG_COND_LT, + [2] = TCG_COND_GTU, + [3] = TCG_COND_LTU, + [4] = TCG_COND_NEVER, /* reserved */ + [5] = TCG_COND_NEVER, /* reserved */ + [6] = TCG_COND_EQ, + [7] = TCG_COND_NE, + }; + TCGCond cond = cb_cond[a->cc]; + TCGv_i64 t; + DisasLabel match; + + if (!dc_isar_feature(aa64_cmpbr, s) || cond == TCG_COND_NEVER) { + return false; + } + + t = cpu_reg(s, a->rt); + if (!a->sf) { + TCGv_i64 tt = tcg_temp_new_i64(); + + if (is_signed_cond(cond)) { + tcg_gen_ext32s_i64(tt, t); + } else { + tcg_gen_ext32u_i64(tt, t); + } + t = tt; + } + + reset_btype(s); + match = gen_disas_label(s); + + tcg_gen_brcondi_i64(cond, t, a->imm6, match.label); + gen_goto_tb(s, 0, 4); + set_disas_label(s, match); + gen_goto_tb(s, 1, a->imm9); + return true; +} + static void set_btype_for_br(DisasContext *s, int rn) { if (dc_isar_feature(aa64_bti, s)) { -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260518174750.660258-5-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 1 + linux-user/aarch64/elfload.c | 1 + target/arm/tcg/cpu64.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_CCIDX (Extended cache index) - FEAT_CHK (Check Feature Status) - FEAT_CMOW (Control for cache maintenance permission) +- FEAT_CMPBR (Compare and Branch instructions) - FEAT_CRC32 (CRC32 instructions) - FEAT_Crypto (Cryptographic Extension) - FEAT_CSSC (Common Short Sequence Compression instructions) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap(CPUState *cs) GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC); GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC); GET_FEATURE_ID(aa64_gcs, ARM_HWCAP_A64_GCS); + GET_FEATURE_ID(aa64_cmpbr, ARM_HWCAP_A64_CMPBR); return hwcaps; } diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64ISAR2, MOPS, 1); /* FEAT_MOPS */ t = FIELD_DP64(t, ID_AA64ISAR2, BC, 1); /* FEAT_HBC */ t = FIELD_DP64(t, ID_AA64ISAR2, WFXT, 2); /* FEAT_WFxT */ - t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 1); /* FEAT_CSSC */ + t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 2); /* FEAT_CSSC, FEAT_CMPBR */ t = FIELD_DP64(t, ID_AA64ISAR2, ATS1A, 1); /* FEAT_ATS1A */ SET_IDREG(isar, ID_AA64ISAR2, t); -- 2.43.0
The Domain fault type can only happen for 32-bit short-format descriptors. This means that it almost never needs to be encoded in a long-format fault status code. However, there is one corner case where we do need to report it as a long-format FSC: if a 64-bit EL2 does an AT insn on an AArch32 EL1&0 translation regime that is using short-descriptors and that translation operation hits a Domain fault, then this is reported in the PAR_EL1 in long-format. The PAR_EL1 register description defines that this should be reported as 0b111101 for a level 1 Domain fault or 0b111110 for a level 2 Domain fault. The Arm ARM pseudocode special cases this in the function AArch64_PARFaultStatus() (because no other "fault to LFSC" code path can be a Domain fault). For QEMU, implement it in arm_fi_to_lfsc(). Cc: qemu-stable@nongnu.org Fixes: 1fa498fe0de97 ("target/arm: Provide fault type enum and FSR conversion functions") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3512 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260526174155.2491217-1-peter.maydell@linaro.org --- target/arm/internals.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t arm_fi_to_lfsc(ARMMMUFaultInfo *fi) assert(fi->level >= 0 && fi->level <= 3); fsc = 0b001100 | fi->level; break; + case ARMFault_Domain: + /* + * This can only happen when doing an AT insn at EL2 for an AArch32 + * stage 1 EL1&0 translation regime using short-descriptors, and + * the translation hits a Domain fault. This needs to be reported in + * the long-format PAR. Compare pseudocode AArch64_PARFaultStatus(). + */ + assert(fi->level == 1 || fi->level == 2); + fsc = 0b111100 | fi->level; + break; case ARMFault_Translation: assert(fi->level >= -1 && fi->level <= 3); if (fi->level < 0) { -- 2.43.0
The Arm ARM A1.5.10 notes that some instructions have "Alternate Bfloat16 behaviors" when FPCR.AH == 1. We implement these using the FPST_AH and FPST_AH_F16 fp_status words. The list includes the SME BFVCT (single-precision to BFloat16) and BFCVTN, but we forgot to make those use FPST_AH_F16 when we implemented them. (We get the ASIMD and SVE insns on the list right.) Add the missing logic to select the right FPST. Cc: qemu-stable@nongnu.org Fixes: 465d36db0e1 ("target/arm: Implement SME2 BFCVT, BFCVTN, FCVT, FCVTN") Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260521180854.1744788-1-peter.maydell@linaro.org --- target/arm/tcg/translate-sme.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static bool do_zz_fpst(DisasContext *s, arg_zz_n *a, int data, } TRANS_FEAT(BFCVT, aa64_sme2, do_zz_fpst, a, 0, - FPST_A64, gen_helper_sme2_bfcvt) + s->fpcr_ah ? FPST_AH : FPST_A64, gen_helper_sme2_bfcvt) TRANS_FEAT(BFCVTN, aa64_sme2, do_zz_fpst, a, 0, - FPST_A64, gen_helper_sme2_bfcvtn) + s->fpcr_ah ? FPST_AH : FPST_A64, gen_helper_sme2_bfcvtn) TRANS_FEAT(FCVT_n, aa64_sme2, do_zz_fpst, a, 0, FPST_A64, gen_helper_sme2_fcvt_n) TRANS_FEAT(FCVTN, aa64_sme2, do_zz_fpst, a, 0, -- 2.43.0
From: Jason Wright <wrigjl@proton.me> Add an .accessfn to the RNDR and RNDRRS system registers that traps reads to EL3 when SCR_EL3.TRNDR is set, as required by FEAT_RNG_TRAP. Mark SCR_EL3.TRNDR (bit 40) as a writable field in scr_write() when the CPU advertises the feature. The pseudocode in DDI0487 revision M.b shows the trap firing from EL0, EL1, EL2, and EL3, so there is no check of arm_current_el(). When FEAT_RNG_TRAP is implemented without FEAT_RNG, an RNDR/RNDRRS read with SCR_EL3.TRNDR=0 should UNDEF rather than succeed; handle that case in access_rndr(). Register the rndr_reginfo CP reg entries whenever either FEAT_RNG or FEAT_RNG_TRAP is implemented, so the accessfn fires even on a FEAT_RNG_TRAP-only CPU. When SCR_EL3.TRNDR is set, ID_AA64ISAR0_EL1.RNDR reads as 1 regardless of whether FEAT_RNG is implemented; give ID_AA64ISAR0_EL1 a readfn so it reports this at runtime, as we already do for ID_AA64PFR0_EL1. Suggested-by: Richard Henderson <richard.henderson@linaro.org> Suggested-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Jason Wright <wrigjl@proton.me> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 ++++ target/arm/helper.c | 58 +++++++++++++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64ISAR0, RNDR) != 0; } +static inline bool isar_feature_aa64_rng_trap(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64PFR1, RNDR_TRAP) != 0; +} + static inline bool isar_feature_aa64_tlbirange(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64ISAR0, TLB) == 2; diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) if (cpu_isar_feature(aa64_fpmr, cpu)) { valid_mask |= SCR_ENFPM; } + if (cpu_isar_feature(aa64_rng_trap, cpu)) { + valid_mask |= SCR_TRNDR; + } } else { valid_mask &= ~(SCR_RW | SCR_ST); if (cpu_isar_feature(aa32_ras, cpu)) { @@ -XXX,XX +XXX,XX @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri) } return pfr0; } + +static uint64_t id_aa64isar0_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + ARMCPU *cpu = env_archcpu(env); + uint64_t isar0 = GET_IDREG(&cpu->isar, ID_AA64ISAR0); + + /* + * When FEAT_RNG_TRAP is active (SCR_EL3.TRNDR set), ID_AA64ISAR0_EL1.RNDR + * reads as 1 regardless of whether FEAT_RNG is implemented. + */ + if (env->cp15.scr_el3 & SCR_TRNDR) { + isar0 = FIELD_DP64(isar0, ID_AA64ISAR0, RNDR, 1); + } + return isar0; +} #endif /* @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo pauth_reginfo[] = { .fieldoffset = offsetof(CPUARMState, keys.apib.hi) }, }; +static CPAccessResult access_rndr(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (env->cp15.scr_el3 & SCR_TRNDR) { + return CP_ACCESS_TRAP_EL3; + } + /* + * Note that FEAT_RNG_TRAP may be implemented without FEAT_RNG. + * In that case, if the trap is not enabled, the read undefs. + */ + if (!cpu_isar_feature(aa64_rndr, env_archcpu(env))) { + return CP_ACCESS_UNDEFINED; + } + return CP_ACCESS_OK; +} + static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri) { Error *err = NULL; @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo rndr_reginfo[] = { { .name = "RNDR", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO, .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 0, - .access = PL0_R, .readfn = rndr_readfn }, + .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn }, { .name = "RNDRRS", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO, .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 1, - .access = PL0_R, .readfn = rndr_readfn }, + .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn }, }; static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *ri, @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_tid3, .resetvalue = 0 }, + /* + * ID_AA64ISAR0_EL1 is not a plain ARM_CP_CONST in system + * emulation because the RNDR field depends on SCR_EL3.TRNDR + * at read time when FEAT_RNG_TRAP is implemented. + */ { .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0, - .access = PL1_R, .type = ARM_CP_CONST, + .access = PL1_R, +#ifdef CONFIG_USER_ONLY + .type = ARM_CP_CONST, + .resetvalue = GET_IDREG(isar, ID_AA64ISAR0) +#else + .type = ARM_CP_NO_RAW, .accessfn = access_tid3, - .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)}, + .readfn = id_aa64isar0_read, + .writefn = arm_cp_write_ignore +#endif + }, { .name = "ID_AA64ISAR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) if (cpu_isar_feature(aa64_pauth, cpu)) { define_arm_cp_regs(cpu, pauth_reginfo); } - if (cpu_isar_feature(aa64_rndr, cpu)) { + if (cpu_isar_feature(aa64_rndr, cpu) || + cpu_isar_feature(aa64_rng_trap, cpu)) { define_arm_cp_regs(cpu, rndr_reginfo); } /* Data Cache clean instructions up to PoP */ -- 2.43.0
From: Jason Wright <wrigjl@proton.me> Set ID_AA64PFR1.RNDR_TRAP=1 on the max CPU model so guests and firmware detect FEAT_RNG_TRAP, per the Arm Architecture Reference Manual for A-profile architecture (DDI 0487), and document the feature as emulated in docs/system/arm/emulation.rst. Signed-off-by: Jason Wright <wrigjl@proton.me> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 1 + target/arm/tcg/cpu64.c | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_RME (Realm Management Extension) (NB: support status in QEMU is experimental) - FEAT_RME_GPC2 (RME Granule Protection Check 2 Extension) - FEAT_RNG (Random number generator) +- FEAT_RNG_TRAP (Trapping support for RNDR/RNDRRS) - FEAT_RPRES (Increased precision of FRECPE and FRSQRTE) - FEAT_S1PIE (Stage 1 permission indirections) - FEAT_S2PIE (Stage 2 permission indirections) diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */ t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* FEAT_RASv1p1 + FEAT_DoubleFault */ t = FIELD_DP64(t, ID_AA64PFR1, SME, 2); /* FEAT_SME2 */ + t = FIELD_DP64(t, ID_AA64PFR1, RNDR_TRAP, 1); /* FEAT_RNG_TRAP */ t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_3 */ t = FIELD_DP64(t, ID_AA64PFR1, NMI, 1); /* FEAT_NMI */ t = FIELD_DP64(t, ID_AA64PFR1, GCS, 1); /* FEAT_GCS */ -- 2.43.0
The OMAP DMA device includes a lot of code which has been disabled via ifdefs for over a decade. Whatever this unfinished development work was, all knowledge of it is long gone, and we're unlikely to be doing any serious work on this device model in future. If we did, we'd likely have to start from scratch. Remove all the ifdeffed out code. We will fix up the indentation in a followup commit that has only whitespace changes. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260528152852.3349928-2-peter.maydell@linaro.org --- hw/dma/omap_dma.c | 94 ----------------------------------------------- 1 file changed, 94 deletions(-) diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c index XXXXXXX..XXXXXXX 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -XXX,XX +XXX,XX @@ static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma) struct omap_dma_channel_s *ch = dma->opaque; struct omap_dma_reg_set_s *a = &ch->active_set; int bytes = dma->bytes; -#ifdef MULTI_REQ - uint16_t status = ch->status; -#endif do { /* Transfer a single element */ @@ -XXX,XX +XXX,XX @@ static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma) a->dest += a->elem_delta[1]; a->element ++; -#ifndef MULTI_REQ if (a->element == a->elements) { /* End of Frame */ a->element = 0; @@ -XXX,XX +XXX,XX @@ static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma) ch->cpc = a->dest & 0xffff; } } while ((bytes -= ch->data_type)); -#else - /* If the channel is element synchronized, deactivate it */ - if (ch->sync && !ch->fs && !ch->bs) - omap_dma_deactivate_channel(s, ch); - - /* If it is the last frame, set the LAST_FRAME interrupt */ - if (a->element == 1 && a->frame == a->frames - 1) - if (ch->interrupts & LAST_FRAME_INTR) - ch->status |= LAST_FRAME_INTR; - - /* If the half of the frame was reached, set the HALF_FRAME - interrupt */ - if (a->element == (a->elements >> 1)) - if (ch->interrupts & HALF_FRAME_INTR) - ch->status |= HALF_FRAME_INTR; - - if (ch->fs && ch->bs) { - a->pck_element ++; - /* Check if a full packet has been transferred. */ - if (a->pck_element == a->pck_elements) { - a->pck_element = 0; - - /* Set the END_PKT interrupt */ - if ((ch->interrupts & END_PKT_INTR) && !ch->src_sync) - ch->status |= END_PKT_INTR; - - /* If the channel is packet-synchronized, deactivate it */ - if (ch->sync) - omap_dma_deactivate_channel(s, ch); - } - } - - if (a->element == a->elements) { - /* End of Frame */ - a->element = 0; - a->src += a->frame_delta[0]; - a->dest += a->frame_delta[1]; - a->frame ++; - - /* If the channel is frame synchronized, deactivate it */ - if (ch->sync && ch->fs && !ch->bs) - omap_dma_deactivate_channel(s, ch); - - /* If the channel is async, update cpc */ - if (!ch->sync) - ch->cpc = a->dest & 0xffff; - - /* Set the END_FRAME interrupt */ - if (ch->interrupts & END_FRAME_INTR) - ch->status |= END_FRAME_INTR; - - if (a->frame == a->frames) { - /* End of Block */ - /* Disable the channel */ - - if (!ch->auto_init) - omap_dma_disable_channel(s, ch); - else if (ch->repeat || ch->end_prog) - omap_dma_channel_load(ch); - else { - ch->waiting_end_prog = 1; - omap_dma_deactivate_channel(s, ch); - } - - if (ch->interrupts & END_BLOCK_INTR) - ch->status |= END_BLOCK_INTR; - } - } - } while (status == ch->status && ch->active); - - omap_dma_interrupts_update(s); -#endif } enum { @@ -XXX,XX +XXX,XX @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma) dest_p = &s->mpu->port[ch->port[1]]; if ((!ch->constant_fill && !src_p->addr_valid(s->mpu, a->src)) || (!dest_p->addr_valid(s->mpu, a->dest))) { -#if 0 - /* Bus time-out */ - if (ch->interrupts & TIMEOUT_INTR) - ch->status |= TIMEOUT_INTR; - omap_dma_deactivate_channel(s, ch); - continue; -#endif printf("%s: Bus time-out in DMA%i operation\n", __func__, dma->num); } @@ -XXX,XX +XXX,XX @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma) /* Set appropriate interrupts and/or deactivate channels */ -#ifdef MULTI_REQ - /* TODO: should all of this only be done if dma->update, and otherwise - * inside omap_dma_transfer_generic below - check what's faster. */ - if (dma->update) { -#endif /* If the channel is element synchronized, deactivate it */ if (min_elems == elements[omap_dma_intr_element_sync]) @@ -XXX,XX +XXX,XX @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma) /* TODO: check if we really need to update anything here or perhaps we * can skip part of this. */ -#ifndef MULTI_REQ if (dma->update) { -#endif a->element += min_elems; frames = a->element / a->elements; @@ -XXX,XX +XXX,XX @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma) /* TODO: if the destination port is IMIF or EMIFF, set the dirty * bits on it. */ -#ifndef MULTI_REQ } -#else - } -#endif omap_dma_interrupts_update(s); } -- 2.43.0
We're about to fix indent in a section of the omap_dma_transfer_setup() function, which will make checkpatch complain. Since we're touching the code anyway, fix the uses of if() with no braces and wrongly formatted multiline comments. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260528152852.3349928-3-peter.maydell@linaro.org --- hw/dma/omap_dma.c | 51 ++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c index XXXXXXX..XXXXXXX 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -XXX,XX +XXX,XX @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma) /* If the channel is element synchronized, deactivate it */ - if (min_elems == elements[omap_dma_intr_element_sync]) + if (min_elems == elements[omap_dma_intr_element_sync]) { omap_dma_deactivate_channel(s, ch); + } /* If it is the last frame, set the LAST_FRAME interrupt */ - if (min_elems == elements[omap_dma_intr_last_frame]) + if (min_elems == elements[omap_dma_intr_last_frame]) { ch->status |= LAST_FRAME_INTR; + } - /* If exactly half of the frame was reached, set the HALF_FRAME - interrupt */ - if (min_elems == elements[omap_dma_intr_half_frame]) + /* + * If exactly half of the frame was reached, set the HALF_FRAME + * interrupt + */ + if (min_elems == elements[omap_dma_intr_half_frame]) { ch->status |= HALF_FRAME_INTR; + } /* If a full packet has been transferred, set the END_PKT interrupt */ - if (min_elems == elements[omap_dma_intr_packet]) + if (min_elems == elements[omap_dma_intr_packet]) { ch->status |= END_PKT_INTR; + } /* If the channel is packet-synchronized, deactivate it */ - if (min_elems == elements[omap_dma_intr_packet_sync]) + if (min_elems == elements[omap_dma_intr_packet_sync]) { omap_dma_deactivate_channel(s, ch); + } /* If the channel is frame synchronized, deactivate it */ - if (min_elems == elements[omap_dma_intr_frame_sync]) + if (min_elems == elements[omap_dma_intr_frame_sync]) { omap_dma_deactivate_channel(s, ch); + } /* Set the END_FRAME interrupt */ - if (min_elems == elements[omap_dma_intr_frame]) + if (min_elems == elements[omap_dma_intr_frame]) { ch->status |= END_FRAME_INTR; + } if (min_elems == elements[omap_dma_intr_block]) { /* End of Block */ /* Disable the channel */ - if (!ch->auto_init) + if (!ch->auto_init) { omap_dma_disable_channel(s, ch); - else if (ch->repeat || ch->end_prog) + } else if (ch->repeat || ch->end_prog) { omap_dma_channel_load(ch); - else { + } else { ch->waiting_end_prog = 1; omap_dma_deactivate_channel(s, ch); } - if (ch->interrupts & END_BLOCK_INTR) + if (ch->interrupts & END_BLOCK_INTR) { ch->status |= END_BLOCK_INTR; + } } /* Update packet number */ @@ -XXX,XX +XXX,XX @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma) a->pck_element %= a->pck_elements; } - /* TODO: check if we really need to update anything here or perhaps we - * can skip part of this. */ + /* + * TODO: check if we really need to update anything here or perhaps we + * can skip part of this. + */ if (dma->update) { a->element += min_elems; @@ -XXX,XX +XXX,XX @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma) a->dest += min_elems * a->elem_delta[1] + frames * a->frame_delta[1]; /* If the channel is async, update cpc */ - if (!ch->sync && frames) + if (!ch->sync && frames) { ch->cpc = a->dest & 0xffff; + } - /* TODO: if the destination port is IMIF or EMIFF, set the dirty - * bits on it. */ + /* + * TODO: if the destination port is IMIF or EMIFF, set the dirty + * bits on it. + */ } omap_dma_interrupts_update(s); -- 2.43.0
Some of the ifdefs in omap_dma_transfer_setup() which we just removed had if() blocks in them. Now that the code inside them is always unconditional it has an extra unnecessary layer of indentation; fix this, as a whitespace only change. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260528152852.3349928-4-peter.maydell@linaro.org --- hw/dma/omap_dma.c | 156 +++++++++++++++++++++++----------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c index XXXXXXX..XXXXXXX 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -XXX,XX +XXX,XX @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma) /* Set appropriate interrupts and/or deactivate channels */ - /* If the channel is element synchronized, deactivate it */ - if (min_elems == elements[omap_dma_intr_element_sync]) { + /* If the channel is element synchronized, deactivate it */ + if (min_elems == elements[omap_dma_intr_element_sync]) { + omap_dma_deactivate_channel(s, ch); + } + + /* If it is the last frame, set the LAST_FRAME interrupt */ + if (min_elems == elements[omap_dma_intr_last_frame]) { + ch->status |= LAST_FRAME_INTR; + } + + /* + * If exactly half of the frame was reached, set the HALF_FRAME + * interrupt + */ + if (min_elems == elements[omap_dma_intr_half_frame]) { + ch->status |= HALF_FRAME_INTR; + } + + /* If a full packet has been transferred, set the END_PKT interrupt */ + if (min_elems == elements[omap_dma_intr_packet]) { + ch->status |= END_PKT_INTR; + } + + /* If the channel is packet-synchronized, deactivate it */ + if (min_elems == elements[omap_dma_intr_packet_sync]) { + omap_dma_deactivate_channel(s, ch); + } + + /* If the channel is frame synchronized, deactivate it */ + if (min_elems == elements[omap_dma_intr_frame_sync]) { + omap_dma_deactivate_channel(s, ch); + } + + /* Set the END_FRAME interrupt */ + if (min_elems == elements[omap_dma_intr_frame]) { + ch->status |= END_FRAME_INTR; + } + + if (min_elems == elements[omap_dma_intr_block]) { + /* End of Block */ + /* Disable the channel */ + + if (!ch->auto_init) { + omap_dma_disable_channel(s, ch); + } else if (ch->repeat || ch->end_prog) { + omap_dma_channel_load(ch); + } else { + ch->waiting_end_prog = 1; omap_dma_deactivate_channel(s, ch); } - /* If it is the last frame, set the LAST_FRAME interrupt */ - if (min_elems == elements[omap_dma_intr_last_frame]) { - ch->status |= LAST_FRAME_INTR; + if (ch->interrupts & END_BLOCK_INTR) { + ch->status |= END_BLOCK_INTR; + } + } + + /* Update packet number */ + if (ch->fs && ch->bs) { + a->pck_element += min_elems; + a->pck_element %= a->pck_elements; + } + + /* + * TODO: check if we really need to update anything here or perhaps we + * can skip part of this. + */ + if (dma->update) { + a->element += min_elems; + + frames = a->element / a->elements; + a->element = a->element % a->elements; + a->frame += frames; + a->src += min_elems * a->elem_delta[0] + frames * a->frame_delta[0]; + a->dest += min_elems * a->elem_delta[1] + frames * a->frame_delta[1]; + + /* If the channel is async, update cpc */ + if (!ch->sync && frames) { + ch->cpc = a->dest & 0xffff; } /* - * If exactly half of the frame was reached, set the HALF_FRAME - * interrupt + * TODO: if the destination port is IMIF or EMIFF, set the dirty + * bits on it. */ - if (min_elems == elements[omap_dma_intr_half_frame]) { - ch->status |= HALF_FRAME_INTR; - } - - /* If a full packet has been transferred, set the END_PKT interrupt */ - if (min_elems == elements[omap_dma_intr_packet]) { - ch->status |= END_PKT_INTR; - } - - /* If the channel is packet-synchronized, deactivate it */ - if (min_elems == elements[omap_dma_intr_packet_sync]) { - omap_dma_deactivate_channel(s, ch); - } - - /* If the channel is frame synchronized, deactivate it */ - if (min_elems == elements[omap_dma_intr_frame_sync]) { - omap_dma_deactivate_channel(s, ch); - } - - /* Set the END_FRAME interrupt */ - if (min_elems == elements[omap_dma_intr_frame]) { - ch->status |= END_FRAME_INTR; - } - - if (min_elems == elements[omap_dma_intr_block]) { - /* End of Block */ - /* Disable the channel */ - - if (!ch->auto_init) { - omap_dma_disable_channel(s, ch); - } else if (ch->repeat || ch->end_prog) { - omap_dma_channel_load(ch); - } else { - ch->waiting_end_prog = 1; - omap_dma_deactivate_channel(s, ch); - } - - if (ch->interrupts & END_BLOCK_INTR) { - ch->status |= END_BLOCK_INTR; - } - } - - /* Update packet number */ - if (ch->fs && ch->bs) { - a->pck_element += min_elems; - a->pck_element %= a->pck_elements; - } - - /* - * TODO: check if we really need to update anything here or perhaps we - * can skip part of this. - */ - if (dma->update) { - a->element += min_elems; - - frames = a->element / a->elements; - a->element = a->element % a->elements; - a->frame += frames; - a->src += min_elems * a->elem_delta[0] + frames * a->frame_delta[0]; - a->dest += min_elems * a->elem_delta[1] + frames * a->frame_delta[1]; - - /* If the channel is async, update cpc */ - if (!ch->sync && frames) { - ch->cpc = a->dest & 0xffff; - } - - /* - * TODO: if the destination port is IMIF or EMIFF, set the dirty - * bits on it. - */ - } + } omap_dma_interrupts_update(s); } -- 2.43.0
v3->v4: Windows headers define an INT type which clashed with an enum value name in arm_gicv3_its.c... The following changes since commit eae587e8e3694b1aceab23239493fb4c7e1a80f5: Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-09-13' into staging (2021-09-13 11:00:30 +0100) are available in the Git repository at: https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210913-3 for you to fetch changes up to 28e987a7e7edaa3ca7feeac65edca26145df8814: hw/arm/mps2.c: Mark internal-only I2C buses as 'full' (2021-09-13 21:01:08 +0100) ---------------------------------------------------------------- target-arm queue: * mark MPS2/MPS3 board-internal i2c buses as 'full' so that command line user-created devices are not plugged into them * Take an exception if PSTATE.IL is set * Support an emulated ITS in the virt board * Add support for kudo-bmc board * Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM * cadence_uart: Fix clock handling issues that prevented u-boot from running ---------------------------------------------------------------- Bin Meng (6): hw/misc: zynq_slcr: Correctly compute output clocks in the reset exit phase hw/char: cadence_uart: Disable transmit when input clock is disabled hw/char: cadence_uart: Move clock/reset check to uart_can_receive() hw/char: cadence_uart: Convert to memop_with_attrs() ops hw/char: cadence_uart: Ignore access when unclocked or in reset for uart_{read, write}() hw/char: cadence_uart: Log a guest error when device is unclocked or in reset Chris Rauer (1): hw/arm: Add support for kudo-bmc board. Marc Zyngier (1): hw/arm/virt: KVM: Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM Peter Maydell (5): target/arm: Take an exception if PSTATE.IL is set qdev: Support marking individual buses as 'full' hw/arm/mps2-tz.c: Add extra data parameter to MakeDevFn hw/arm/mps2-tz.c: Mark internal-only I2C buses as 'full' hw/arm/mps2.c: Mark internal-only I2C buses as 'full' Richard Henderson (1): target/arm: Merge disas_a64_insn into aarch64_tr_translate_insn Shashi Mallela (9): hw/intc: GICv3 ITS initial framework hw/intc: GICv3 ITS register definitions added hw/intc: GICv3 ITS command queue framework hw/intc: GICv3 ITS Command processing hw/intc: GICv3 ITS Feature enablement hw/intc: GICv3 redistributor ITS processing tests/data/acpi/virt: Add IORT files for ITS hw/arm/virt: add ITS support in virt GIC tests/data/acpi/virt: Update IORT files for ITS docs/system/arm/nuvoton.rst | 1 + hw/intc/gicv3_internal.h | 188 ++++- include/hw/arm/virt.h | 2 + include/hw/intc/arm_gicv3_common.h | 13 + include/hw/intc/arm_gicv3_its_common.h | 32 +- include/hw/qdev-core.h | 24 + target/arm/cpu.h | 1 + target/arm/kvm_arm.h | 4 +- target/arm/syndrome.h | 5 + target/arm/translate.h | 2 + hw/arm/mps2-tz.c | 92 ++- hw/arm/mps2.c | 12 +- hw/arm/npcm7xx_boards.c | 34 + hw/arm/virt.c | 29 +- hw/char/cadence_uart.c | 61 +- hw/intc/arm_gicv3.c | 14 + hw/intc/arm_gicv3_common.c | 13 + hw/intc/arm_gicv3_cpuif.c | 7 +- hw/intc/arm_gicv3_dist.c | 5 +- hw/intc/arm_gicv3_its.c | 1322 ++++++++++++++++++++++++++++++++ hw/intc/arm_gicv3_its_common.c | 7 +- hw/intc/arm_gicv3_its_kvm.c | 2 +- hw/intc/arm_gicv3_redist.c | 153 +++- hw/misc/zynq_slcr.c | 31 +- softmmu/qdev-monitor.c | 7 +- target/arm/helper-a64.c | 1 + target/arm/helper.c | 8 + target/arm/kvm.c | 7 +- target/arm/translate-a64.c | 255 +++--- target/arm/translate.c | 21 + hw/intc/meson.build | 1 + tests/data/acpi/virt/IORT | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.memhp | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.numamem | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.pxb | Bin 0 -> 124 bytes 35 files changed, 2144 insertions(+), 210 deletions(-) create mode 100644 hw/intc/arm_gicv3_its.c create mode 100644 tests/data/acpi/virt/IORT create mode 100644 tests/data/acpi/virt/IORT.memhp create mode 100644 tests/data/acpi/virt/IORT.numamem create mode 100644 tests/data/acpi/virt/IORT.pxb