* [PULL 01/21] target/arm: Enable REVD for SVE2.1
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 02/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff Peter Maydell
` (20 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 d04ef2dcfc..fb9d379184 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -2993,7 +2993,8 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 02/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
2026-05-29 11:47 ` [PULL 01/21] target/arm: Enable REVD for SVE2.1 Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 03/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization Peter Maydell
` (19 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 cf00aa863d..9708200760 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -247,7 +247,14 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 03/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
2026-05-29 11:47 ` [PULL 01/21] target/arm: Enable REVD for SVE2.1 Peter Maydell
2026-05-29 11:47 ` [PULL 02/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 04/21] hw/dma/zynq: Ensure PCFG_DONE bit remains set to indicate PL is in user mode Peter Maydell
` (18 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 9708200760..afe6ffd326 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -221,7 +221,9 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 04/21] hw/dma/zynq: Ensure PCFG_DONE bit remains set to indicate PL is in user mode
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (2 preceding siblings ...)
2026-05-29 11:47 ` [PULL 03/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 05/21] hw/dma/zynq-devcfg: Simulate dummy PL reset Peter Maydell
` (17 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 afe6ffd326..7370ab941f 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -188,6 +188,8 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 05/21] hw/dma/zynq-devcfg: Simulate dummy PL reset
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (3 preceding siblings ...)
2026-05-29 11:47 ` [PULL 04/21] hw/dma/zynq: Ensure PCFG_DONE bit remains set to indicate PL is in user mode Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 06/21] hw/dma/zynq-devcfg: Indicate power-up status of PL Peter Maydell
` (16 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 7370ab941f..6b1d96ff80 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -49,6 +49,7 @@
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)
@@ -116,6 +117,7 @@ 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)
@@ -204,6 +206,13 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 06/21] hw/dma/zynq-devcfg: Indicate power-up status of PL
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (4 preceding siblings ...)
2026-05-29 11:47 ` [PULL 05/21] hw/dma/zynq-devcfg: Simulate dummy PL reset Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 07/21] hw/misc: Add dummy ZYNQ DDR controller Peter Maydell
` (15 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 6b1d96ff80..5608460dc7 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -333,7 +333,8 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 07/21] hw/misc: Add dummy ZYNQ DDR controller
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (5 preceding siblings ...)
2026-05-29 11:47 ` [PULL 06/21] hw/dma/zynq-devcfg: Indicate power-up status of PL Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 08/21] hw/misc/zynq_slcr: Add logic for DCI configuration Peter Maydell
` (14 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 7eb5823da6..580a8ff12b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1144,8 +1144,10 @@ 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 5b198402d5..fb798ccbee 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -289,6 +289,7 @@ 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 9dcded9219..66a4480cc8 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -201,6 +201,17 @@ 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);
@@ -312,6 +323,8 @@ 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]);
@@ -393,9 +406,6 @@ 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 99bdf09219..1543ee6653 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -254,4 +254,7 @@ 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 fa6a961ac9..23265f6035 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -97,6 +97,7 @@ 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 0000000000..9e4f2f37a8
--- /dev/null
+++ b/hw/misc/xlnx-zynq-ddrc.c
@@ -0,0 +1,421 @@
+/*
+ * 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 0000000000..124bff27ac
--- /dev/null
+++ b/include/hw/misc/xlnx-zynq-ddrc.h
@@ -0,0 +1,147 @@
+/*
+ * 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 08/21] hw/misc/zynq_slcr: Add logic for DCI configuration
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (6 preceding siblings ...)
2026-05-29 11:47 ` [PULL 07/21] hw/misc: Add dummy ZYNQ DDR controller Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 09/21] hw/block/m25p80: Add HAS_SR_TB flag for is25lp016d Peter Maydell
` (13 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 faae98fa02..0ae5d607be 100644
--- a/hw/misc/zynq_slcr.c
+++ b/hw/misc/zynq_slcr.c
@@ -180,6 +180,12 @@ 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
@@ -193,6 +199,8 @@ struct ZynqSLCRState {
MemoryRegion iomem;
+ bool ddriob_dci_ctrl_reset_toggled;
+
uint32_t regs[ZYNQ_SLCR_NUM_REGS];
Clock *ps_clk;
@@ -331,6 +339,8 @@ 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;
@@ -418,6 +428,8 @@ 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)
@@ -554,6 +566,25 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 09/21] hw/block/m25p80: Add HAS_SR_TB flag for is25lp016d
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (7 preceding siblings ...)
2026-05-29 11:47 ` [PULL 08/21] hw/misc/zynq_slcr: Add logic for DCI configuration Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 10/21] hw/arm/xilinx_zynq: Split xilinx_zynq into header and implementation files Peter Maydell
` (12 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 b8a2543c0b..4a4cda6602 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -217,7 +217,8 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 10/21] hw/arm/xilinx_zynq: Split xilinx_zynq into header and implementation files
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (8 preceding siblings ...)
2026-05-29 11:47 ` [PULL 09/21] hw/block/m25p80: Add HAS_SR_TB flag for is25lp016d Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 11/21] target/arm: Add feature predicate for FEAT_CMPBR Peter Maydell
` (11 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 66a4480cc8..6c83439017 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -41,9 +41,7 @@
#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)
@@ -87,15 +85,6 @@ 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 0000000000..cefb7789ff
--- /dev/null
+++ b/include/hw/arm/xilinx_zynq.h
@@ -0,0 +1,30 @@
+/*
+ * 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 11/21] target/arm: Add feature predicate for FEAT_CMPBR
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (9 preceding siblings ...)
2026-05-29 11:47 ` [PULL 10/21] hw/arm/xilinx_zynq: Split xilinx_zynq into header and implementation files Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 12/21] target/arm: Implement CB, CBB, CBH Peter Maydell
` (10 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 f9c979d20b..4e8d844fea 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1061,6 +1061,11 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 12/21] target/arm: Implement CB, CBB, CBH
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (10 preceding siblings ...)
2026-05-29 11:47 ` [PULL 11/21] target/arm: Add feature predicate for FEAT_CMPBR Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 13/21] target/arm: Implement CB (immediate) Peter Maydell
` (9 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 02c7264cb9..a5a2a45a2f 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -208,6 +208,15 @@ 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 15b40090c0..94dad693eb 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -1774,6 +1774,49 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 13/21] target/arm: Implement CB (immediate)
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (11 preceding siblings ...)
2026-05-29 11:47 ` [PULL 12/21] target/arm: Implement CB, CBB, CBH Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 14/21] target/arm: Enable FEAT_CMPBR for -cpu max Peter Maydell
` (8 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 a5a2a45a2f..d8a3269573 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -217,6 +217,8 @@ 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 94dad693eb..765bc3f0b0 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -1817,6 +1817,49 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 14/21] target/arm: Enable FEAT_CMPBR for -cpu max
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (12 preceding siblings ...)
2026-05-29 11:47 ` [PULL 13/21] target/arm: Implement CB (immediate) Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 15/21] target/arm: Don't assert if 64-bit EL2 AT insn sees a Domain fault Peter Maydell
` (7 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 e44b3016be..37ca4e47b8 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -35,6 +35,7 @@ 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 ceeeee5315..228b593316 100644
--- a/linux-user/aarch64/elfload.c
+++ b/linux-user/aarch64/elfload.c
@@ -170,6 +170,7 @@ 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 a377f67b9c..ce76e09d52 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1262,7 +1262,7 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 15/21] target/arm: Don't assert if 64-bit EL2 AT insn sees a Domain fault
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (13 preceding siblings ...)
2026-05-29 11:47 ` [PULL 14/21] target/arm: Enable FEAT_CMPBR for -cpu max Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 16/21] target/arm: SME BFCVT, BFCVTN have "Alternate BFloat16 behaviors" Peter Maydell
` (6 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 ae5afc5362..f39a992012 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -893,6 +893,16 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 16/21] target/arm: SME BFCVT, BFCVTN have "Alternate BFloat16 behaviors"
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (14 preceding siblings ...)
2026-05-29 11:47 ` [PULL 15/21] target/arm: Don't assert if 64-bit EL2 AT insn sees a Domain fault Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 17/21] target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS Peter Maydell
` (5 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 e2d17de165..82aa14131b 100644
--- a/target/arm/tcg/translate-sme.c
+++ b/target/arm/tcg/translate-sme.c
@@ -1449,9 +1449,9 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 17/21] target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (15 preceding siblings ...)
2026-05-29 11:47 ` [PULL 16/21] target/arm: SME BFCVT, BFCVTN have "Alternate BFloat16 behaviors" Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 18/21] target/arm: advertise FEAT_RNG_TRAP on cortex-max Peter Maydell
` (4 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 4e8d844fea..38a695ded7 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -908,6 +908,11 @@ 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 34487eeaa3..9dd8fdfa41 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -790,6 +790,9 @@ 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)) {
@@ -5170,6 +5173,21 @@ 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
/*
@@ -5304,6 +5322,22 @@ 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;
@@ -5335,11 +5369,11 @@ 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,
@@ -6522,11 +6556,24 @@ 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,
@@ -7454,7 +7501,8 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 18/21] target/arm: advertise FEAT_RNG_TRAP on cortex-max
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (16 preceding siblings ...)
2026-05-29 11:47 ` [PULL 17/21] target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 19/21] hw/dma/omap_dma: Remove unused ifdeffed out code Peter Maydell
` (3 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 37ca4e47b8..18c6355967 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -136,6 +136,7 @@ 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 ce76e09d52..1a4f50486d 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1292,6 +1292,7 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 19/21] hw/dma/omap_dma: Remove unused ifdeffed out code
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (17 preceding siblings ...)
2026-05-29 11:47 ` [PULL 18/21] target/arm: advertise FEAT_RNG_TRAP on cortex-max Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 20/21] hw/dma/omap_dma: Fix coding style in omap_dma_transfer_setup() Peter Maydell
` (2 subsequent siblings)
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 b042e7c59c..a93d9ad196 100644
--- a/hw/dma/omap_dma.c
+++ b/hw/dma/omap_dma.c
@@ -343,9 +343,6 @@ 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 */
@@ -362,7 +359,6 @@ 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;
@@ -375,78 +371,6 @@ 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 {
@@ -475,13 +399,6 @@ 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);
}
@@ -552,11 +469,6 @@ 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])
@@ -612,9 +524,7 @@ 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;
@@ -629,11 +539,7 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 20/21] hw/dma/omap_dma: Fix coding style in omap_dma_transfer_setup()
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (18 preceding siblings ...)
2026-05-29 11:47 ` [PULL 19/21] hw/dma/omap_dma: Remove unused ifdeffed out code Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 11:47 ` [PULL 21/21] hw/dma/omap_dma: Fix indentation after ifdef removal Peter Maydell
2026-05-29 19:49 ` [PULL 00/21] target-arm queue Stefan Hajnoczi
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 a93d9ad196..b8bbb707c4 100644
--- a/hw/dma/omap_dma.c
+++ b/hw/dma/omap_dma.c
@@ -471,49 +471,59 @@ 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 */
@@ -522,8 +532,10 @@ 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;
@@ -534,11 +546,14 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PULL 21/21] hw/dma/omap_dma: Fix indentation after ifdef removal
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (19 preceding siblings ...)
2026-05-29 11:47 ` [PULL 20/21] hw/dma/omap_dma: Fix coding style in omap_dma_transfer_setup() Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
2026-05-29 19:49 ` [PULL 00/21] target-arm queue Stefan Hajnoczi
21 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
To: qemu-devel
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 b8bbb707c4..668fc49054 100644
--- a/hw/dma/omap_dma.c
+++ b/hw/dma/omap_dma.c
@@ -470,91 +470,91 @@ 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
^ permalink raw reply related [flat|nested] 45+ messages in thread* Re: [PULL 00/21] target-arm queue
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
` (20 preceding siblings ...)
2026-05-29 11:47 ` [PULL 21/21] hw/dma/omap_dma: Fix indentation after ifdef removal Peter Maydell
@ 2026-05-29 19:49 ` Stefan Hajnoczi
21 siblings, 0 replies; 45+ messages in thread
From: Stefan Hajnoczi @ 2026-05-29 19:49 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 116 bytes --]
Applied, thanks.
Please update the changelog at https://wiki.qemu.org/ChangeLog/11.1 for any user-visible changes.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 45+ messages in thread