qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/21] Hi,
@ 2025-03-18 13:07 Corvin Köhne
  2025-03-18 13:07 ` [PATCH 01/21] hw/timer: Make frequency configurable Corvin Köhne
                   ` (21 more replies)
  0 siblings, 22 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:07 UTC (permalink / raw)
  To: qemu-devel, Corvin Köhne, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Paolo Bonzini

From: Corvin Köhne <c.koehne@beckhoff.com>

Beckhoff has build a board, called CX7200, based on the Xilinx Zynq A9
platform. This commit series adds the Beckhoff CX7200 as new board variant to
QEMU.

The emulation is able to successfully boot an CX7200 image. The image includes
some self tests executed on every boot. Only the cache self test fails due to
QEMU emulating the cache as always being coherent. The self tests include f.e.:

* Network
* Flash
* CCAT DMA + EEPROM [1]
* TwinCAT (Beckhoff's automation control software [2])

[1] https://github.com/beckhoff/ccat
[2] https://www.beckhoff.com/en-us/products/automation/

Corvin Köhne (1):
  MAINTAINERS: add myself as reviewer for Beckhoff devices

YannickV (20):
  hw/timer: Make frequency configurable
  hw/timer: Make PERIPHCLK period configurable
  hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff
  hw/arm/zynq-devcfg: Prevent unintended unlock during initialization
  hw/dma/zynq: Notify devcfg on FPGA reset via SLCR control
  hw/dma/zynq-devcfg: Simulate dummy PL reset
  hw/dma/zynq-devcfg: Indicate power-up status of PL
  hw/dma/zynq-devcfg: Fix register memory
  hw/misc: Add dummy ZYNQ DDR controller
  hw/misc/zynq_slcr: Add logic for DCI configuration
  hw/misc: Add Beckhoff CCAT device
  hw/arm: Add new machine based on xilinx-zynq-a9 for Beckhoff CX7200
  hw/arm/beckhoff_CX7200: Remove second SD controller
  hw/arm/beckhoff_CX7200: Remove second GEM
  hw/arm/beckhoff_CX7200: Adjust Flashes and Busses
  hw/arm/beckhoff_CX7200: Remove usb interfaces
  hw/arm/beckhoff_CX7200: Remove unimplemented devices
  hw/arm/beckhoff_CX7200: Set CPU frequency and PERIPHCLK period
  hw/arm/beckhoff_CX7200: Add CCAT to CX7200
  hw/arm/beckhoff_CX7200: Add dummy DDR CTRL to CX7200

 MAINTAINERS                       |   7 +
 hw/arm/Kconfig                    |  18 ++
 hw/arm/beckhoff_CX7200.c          | 440 ++++++++++++++++++++++++++++++
 hw/arm/meson.build                |   1 +
 hw/dma/xlnx-zynq-devcfg.c         |  36 ++-
 hw/misc/Kconfig                   |   6 +
 hw/misc/beckhoff_ccat.c           | 365 +++++++++++++++++++++++++
 hw/misc/meson.build               |   2 +
 hw/misc/zynq_ddr-ctrl.c           | 331 ++++++++++++++++++++++
 hw/misc/zynq_slcr.c               |  47 ++++
 hw/timer/a9gtimer.c               |  25 +-
 hw/timer/arm_mptimer.c            |  33 ++-
 include/hw/dma/xlnx-zynq-devcfg.h |   3 +
 include/hw/timer/a9gtimer.h       |   2 +
 include/hw/timer/arm_mptimer.h    |   4 +
 15 files changed, 1309 insertions(+), 11 deletions(-)
 create mode 100644 hw/arm/beckhoff_CX7200.c
 create mode 100644 hw/misc/beckhoff_ccat.c
 create mode 100644 hw/misc/zynq_ddr-ctrl.c

-- 
2.49.0



^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 01/21] hw/timer: Make frequency configurable
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
@ 2025-03-18 13:07 ` Corvin Köhne
  2025-03-18 13:07 ` [PATCH 02/21] hw/timer: Make PERIPHCLK period configurable Corvin Köhne
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:07 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

The a9 global timer and arm mp timers rely on the PERIPHCLK as
their clock source. The current implementation does not take
that into account. That causes problems for applications assuming
other frequencies than 1 GHz.

We can now configure frequencies for the a9 global timer and
arm mp timer. By allowing these values to be set according to
the application's needs, we ensure that the timers behave
consistently with the expected system configuration.

The frequency can also be set via the command line, for example
for the a9 global timer:
-global driver=arm.cortex-a9-global-timer,
	property=cpu-freq,value=1000000000

Information can be found in the Zynq 7000 SoC Technical
Reference Manual under Timers.
https://docs.amd.com/r/en-US/ug585-zynq-7000-SoC-TRM

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/timer/a9gtimer.c            |  8 +++++---
 hw/timer/arm_mptimer.c         | 15 +++++++++++----
 include/hw/timer/a9gtimer.h    |  1 +
 include/hw/timer/arm_mptimer.h |  2 ++
 4 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/hw/timer/a9gtimer.c b/hw/timer/a9gtimer.c
index 9835c35483..a1f5540e75 100644
--- a/hw/timer/a9gtimer.c
+++ b/hw/timer/a9gtimer.c
@@ -63,9 +63,9 @@ static inline int a9_gtimer_get_current_cpu(A9GTimerState *s)
 static inline uint64_t a9_gtimer_get_conv(A9GTimerState *s)
 {
     uint64_t prescale = extract32(s->control, R_CONTROL_PRESCALER_SHIFT,
-                                  R_CONTROL_PRESCALER_LEN);
-
-    return (prescale + 1) * 10;
+                                  R_CONTROL_PRESCALER_LEN) + 1;
+    uint64_t ret = NANOSECONDS_PER_SECOND * prescale * 10;
+    return (uint32_t) (ret / s->cpu_clk_freq_hz);
 }
 
 static A9GTimerUpdate a9_gtimer_get_update(A9GTimerState *s)
@@ -374,6 +374,8 @@ static const VMStateDescription vmstate_a9_gtimer = {
 };
 
 static const Property a9_gtimer_properties[] = {
+    DEFINE_PROP_UINT64("cpu-freq", A9GTimerState, cpu_clk_freq_hz,
+                       NANOSECONDS_PER_SECOND),
     DEFINE_PROP_UINT32("num-cpu", A9GTimerState, num_cpu, 0),
 };
 
diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
index 803dad1e8a..a748b6ab1a 100644
--- a/hw/timer/arm_mptimer.c
+++ b/hw/timer/arm_mptimer.c
@@ -59,9 +59,11 @@ static inline void timerblock_update_irq(TimerBlock *tb)
 }
 
 /* Return conversion factor from mpcore timer ticks to qemu timer ticks.  */
-static inline uint32_t timerblock_scale(uint32_t control)
+static inline uint32_t timerblock_scale(TimerBlock *tb, uint32_t control)
 {
-    return (((control >> 8) & 0xff) + 1) * 10;
+    uint64_t prescale = (((control >> 8) & 0xff) + 1);
+    uint64_t ret = NANOSECONDS_PER_SECOND * prescale * 10;
+    return (uint32_t) (ret / tb->freq_hz);
 }
 
 /* Must be called within a ptimer transaction block */
@@ -155,7 +157,7 @@ static void timerblock_write(void *opaque, hwaddr addr,
             ptimer_stop(tb->timer);
         }
         if ((control & 0xff00) != (value & 0xff00)) {
-            ptimer_set_period(tb->timer, timerblock_scale(value));
+            ptimer_set_period(tb->timer, timerblock_scale(tb, value));
         }
         if (value & 1) {
             uint64_t count = ptimer_get_count(tb->timer);
@@ -222,7 +224,8 @@ static void timerblock_reset(TimerBlock *tb)
         ptimer_transaction_begin(tb->timer);
         ptimer_stop(tb->timer);
         ptimer_set_limit(tb->timer, 0, 1);
-        ptimer_set_period(tb->timer, timerblock_scale(0));
+        ptimer_set_period(tb->timer,
+            timerblock_scale(tb, tb->control));
         ptimer_transaction_commit(tb->timer);
     }
 }
@@ -269,6 +272,7 @@ static void arm_mptimer_realize(DeviceState *dev, Error **errp)
      */
     for (i = 0; i < s->num_cpu; i++) {
         TimerBlock *tb = &s->timerblock[i];
+        tb->freq_hz = s->clk_freq_hz;
         tb->timer = ptimer_init(timerblock_tick, tb, PTIMER_POLICY);
         sysbus_init_irq(sbd, &tb->irq);
         memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb,
@@ -283,6 +287,7 @@ static const VMStateDescription vmstate_timerblock = {
     .minimum_version_id = 3,
     .fields = (const VMStateField[]) {
         VMSTATE_UINT32(control, TimerBlock),
+        VMSTATE_UINT64(freq_hz, TimerBlock),
         VMSTATE_UINT32(status, TimerBlock),
         VMSTATE_PTIMER(timer, TimerBlock),
         VMSTATE_END_OF_LIST()
@@ -301,6 +306,8 @@ static const VMStateDescription vmstate_arm_mptimer = {
 };
 
 static const Property arm_mptimer_properties[] = {
+    DEFINE_PROP_UINT64("clk-freq", ARMMPTimerState, clk_freq_hz,
+                       NANOSECONDS_PER_SECOND),
     DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0),
 };
 
diff --git a/include/hw/timer/a9gtimer.h b/include/hw/timer/a9gtimer.h
index 6ae9122e4b..8ce507a793 100644
--- a/include/hw/timer/a9gtimer.h
+++ b/include/hw/timer/a9gtimer.h
@@ -76,6 +76,7 @@ struct A9GTimerState {
 
     MemoryRegion iomem;
     /* static props */
+    uint64_t cpu_clk_freq_hz;
     uint32_t num_cpu;
 
     QEMUTimer *timer;
diff --git a/include/hw/timer/arm_mptimer.h b/include/hw/timer/arm_mptimer.h
index 65a96e2a0d..8b936cceac 100644
--- a/include/hw/timer/arm_mptimer.h
+++ b/include/hw/timer/arm_mptimer.h
@@ -31,6 +31,7 @@ typedef struct {
     uint32_t control;
     uint32_t status;
     struct ptimer_state *timer;
+    uint64_t freq_hz;
     qemu_irq irq;
     MemoryRegion iomem;
 } TimerBlock;
@@ -43,6 +44,7 @@ struct ARMMPTimerState {
     SysBusDevice parent_obj;
     /*< public >*/
 
+    uint64_t clk_freq_hz;
     uint32_t num_cpu;
     TimerBlock timerblock[ARM_MPTIMER_MAX_CPUS];
     MemoryRegion iomem;
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 02/21] hw/timer: Make PERIPHCLK period configurable
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
  2025-03-18 13:07 ` [PATCH 01/21] hw/timer: Make frequency configurable Corvin Köhne
@ 2025-03-18 13:07 ` Corvin Köhne
  2025-03-18 13:07 ` [PATCH 03/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff Corvin Köhne
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:07 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

The a9 global timer and arm mp timer rely on the PERIPHCLK
as their clock source. The period of PERIPHCLK (denoted as N)
must be a multiple of the core CLK period, with N being equal
to or greater than two. However, the current implementation
does not take the PERIPHCLK period into account, leading to
unexpected behavior in systems where the application assumes
PERIPHCLK is clocked differently.

The property periphclk-period represents the period N, the CLK
is devided by to get the peripheral clock PERIPHCLK. We can now
configure clock properties for the a9 global timer and arm mp
timer. That ensures timers can behave according to the
applications needs.

The PERIPHCLK period can also be set via the command line, for
example for the a9 global timer:
-global driver=arm.cortex-a9-global-timer,
	       property=periphclk-period,value=2

Information can be found in the Zynq 7000 Soc Technical
Reference Manual under Timers.
https://docs.amd.com/r/en-US/ug585-zynq-7000-SoC-TRM

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/timer/a9gtimer.c            | 19 ++++++++++++++++++-
 hw/timer/arm_mptimer.c         | 20 +++++++++++++++++++-
 include/hw/timer/a9gtimer.h    |  1 +
 include/hw/timer/arm_mptimer.h |  2 ++
 4 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/hw/timer/a9gtimer.c b/hw/timer/a9gtimer.c
index a1f5540e75..83aa75889e 100644
--- a/hw/timer/a9gtimer.c
+++ b/hw/timer/a9gtimer.c
@@ -27,6 +27,7 @@
 #include "hw/timer/a9gtimer.h"
 #include "migration/vmstate.h"
 #include "qapi/error.h"
+#include "qemu/error-report.h"
 #include "qemu/timer.h"
 #include "qemu/bitops.h"
 #include "qemu/log.h"
@@ -62,9 +63,17 @@ static inline int a9_gtimer_get_current_cpu(A9GTimerState *s)
 
 static inline uint64_t a9_gtimer_get_conv(A9GTimerState *s)
 {
+    /*
+     * Referring to the ARM-Cortex-A9 MPCore TRM
+     * 
+     * The a9 global timer relies on the PERIPHCLK as its clock source.
+     * The PERIPHCLK clock period must be configured as a multiple of the
+     * main clock CLK. The conversion from the qemu clock (1GHz) to a9
+     * gtimer ticks can be calculated like this:
+     */
     uint64_t prescale = extract32(s->control, R_CONTROL_PRESCALER_SHIFT,
                                   R_CONTROL_PRESCALER_LEN) + 1;
-    uint64_t ret = NANOSECONDS_PER_SECOND * prescale * 10;
+    uint64_t ret = NANOSECONDS_PER_SECOND * prescale * s->periphclk_period;
     return (uint32_t) (ret / s->cpu_clk_freq_hz);
 }
 
@@ -312,6 +321,12 @@ static void a9_gtimer_realize(DeviceState *dev, Error **errp)
     sysbus_init_mmio(sbd, &s->iomem);
     s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, a9_gtimer_update_no_sync, s);
 
+    if (s->periphclk_period < 2) {
+        error_report("Invalid periphclk-period (%lu), must be >= 2",
+                     s->periphclk_period);
+        exit(1);
+    }
+
     for (i = 0; i < s->num_cpu; i++) {
         A9GTimerPerCPU *gtb = &s->per_cpu[i];
 
@@ -377,6 +392,8 @@ static const Property a9_gtimer_properties[] = {
     DEFINE_PROP_UINT64("cpu-freq", A9GTimerState, cpu_clk_freq_hz,
                        NANOSECONDS_PER_SECOND),
     DEFINE_PROP_UINT32("num-cpu", A9GTimerState, num_cpu, 0),
+    DEFINE_PROP_UINT64("periphclk-period", A9GTimerState,
+                       periphclk_period, 10),
 };
 
 static void a9_gtimer_class_init(ObjectClass *klass, void *data)
diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
index a748b6ab1a..767413c77a 100644
--- a/hw/timer/arm_mptimer.c
+++ b/hw/timer/arm_mptimer.c
@@ -27,6 +27,7 @@
 #include "hw/timer/arm_mptimer.h"
 #include "migration/vmstate.h"
 #include "qapi/error.h"
+#include "qemu/error-report.h"
 #include "qemu/module.h"
 #include "hw/core/cpu.h"
 
@@ -61,8 +62,16 @@ static inline void timerblock_update_irq(TimerBlock *tb)
 /* Return conversion factor from mpcore timer ticks to qemu timer ticks.  */
 static inline uint32_t timerblock_scale(TimerBlock *tb, uint32_t control)
 {
+    /*
+     * Referring to the ARM-Cortex-A9 MPCore TRM
+     * 
+     * The arm mp timer relies on the PERIPHCLK as its clock source.
+     * The PERIPHCLK clock period must be configured as a multiple of the
+     * main clock CLK. The conversion from the qemu clock (1GHz) to arm mp
+     * timer ticks can be calculated like this:
+     */
     uint64_t prescale = (((control >> 8) & 0xff) + 1);
-    uint64_t ret = NANOSECONDS_PER_SECOND * prescale * 10;
+    uint64_t ret = NANOSECONDS_PER_SECOND * prescale * tb->periphclk_period;
     return (uint32_t) (ret / tb->freq_hz);
 }
 
@@ -273,6 +282,12 @@ static void arm_mptimer_realize(DeviceState *dev, Error **errp)
     for (i = 0; i < s->num_cpu; i++) {
         TimerBlock *tb = &s->timerblock[i];
         tb->freq_hz = s->clk_freq_hz;
+        if (s->periphclk_period < 2) {
+            error_report("Invalid periphclk-period (%lu), must be >= 2",
+                         s->periphclk_period);
+            exit(1);
+        }
+        tb->periphclk_period = s->periphclk_period;
         tb->timer = ptimer_init(timerblock_tick, tb, PTIMER_POLICY);
         sysbus_init_irq(sbd, &tb->irq);
         memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb,
@@ -288,6 +303,7 @@ static const VMStateDescription vmstate_timerblock = {
     .fields = (const VMStateField[]) {
         VMSTATE_UINT32(control, TimerBlock),
         VMSTATE_UINT64(freq_hz, TimerBlock),
+        VMSTATE_UINT64(periphclk_period, TimerBlock),
         VMSTATE_UINT32(status, TimerBlock),
         VMSTATE_PTIMER(timer, TimerBlock),
         VMSTATE_END_OF_LIST()
@@ -309,6 +325,8 @@ static const Property arm_mptimer_properties[] = {
     DEFINE_PROP_UINT64("clk-freq", ARMMPTimerState, clk_freq_hz,
                        NANOSECONDS_PER_SECOND),
     DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0),
+    DEFINE_PROP_UINT64("periphclk-period", ARMMPTimerState,
+                       periphclk_period, 10),
 };
 
 static void arm_mptimer_class_init(ObjectClass *klass, void *data)
diff --git a/include/hw/timer/a9gtimer.h b/include/hw/timer/a9gtimer.h
index 8ce507a793..edb51f91e3 100644
--- a/include/hw/timer/a9gtimer.h
+++ b/include/hw/timer/a9gtimer.h
@@ -77,6 +77,7 @@ struct A9GTimerState {
     MemoryRegion iomem;
     /* static props */
     uint64_t cpu_clk_freq_hz;
+    uint64_t periphclk_period;
     uint32_t num_cpu;
 
     QEMUTimer *timer;
diff --git a/include/hw/timer/arm_mptimer.h b/include/hw/timer/arm_mptimer.h
index 8b936cceac..2c4cb5c1c3 100644
--- a/include/hw/timer/arm_mptimer.h
+++ b/include/hw/timer/arm_mptimer.h
@@ -32,6 +32,7 @@ typedef struct {
     uint32_t status;
     struct ptimer_state *timer;
     uint64_t freq_hz;
+    uint64_t periphclk_period;
     qemu_irq irq;
     MemoryRegion iomem;
 } TimerBlock;
@@ -45,6 +46,7 @@ struct ARMMPTimerState {
     /*< public >*/
 
     uint64_t clk_freq_hz;
+    uint64_t periphclk_period;
     uint32_t num_cpu;
     TimerBlock timerblock[ARM_MPTIMER_MAX_CPUS];
     MemoryRegion iomem;
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 03/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
  2025-03-18 13:07 ` [PATCH 01/21] hw/timer: Make frequency configurable Corvin Köhne
  2025-03-18 13:07 ` [PATCH 02/21] hw/timer: Make PERIPHCLK period configurable Corvin Köhne
@ 2025-03-18 13:07 ` Corvin Köhne
  2025-04-25 15:47   ` Edgar E. Iglesias
  2025-03-18 13:07 ` [PATCH 04/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization Corvin Köhne
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:07 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini, YannickV

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: Yannick Voßen <y.vossen@beckhoff.com>
---
 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 0fd0d23f57..b838c1c0d0 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.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 04/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (2 preceding siblings ...)
  2025-03-18 13:07 ` [PATCH 03/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff Corvin Köhne
@ 2025-03-18 13:07 ` Corvin Köhne
  2025-04-25 15:52   ` Edgar E. Iglesias
  2025-03-18 13:07 ` [PATCH 05/21] hw/dma/zynq: Notify devcfg on FPGA reset via SLCR control Corvin Köhne
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:07 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini, YannickV

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.

To address this, a property 'is_initialized' is introduced. It is set
to false during reset and updated to true once the initialization is
complete. The unlock function is simply ignored while 'is_initialized'
is false.

I have no idea how this ever worked. Nevertheless, this restores the
correct behavior.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/dma/xlnx-zynq-devcfg.c         | 6 +++++-
 include/hw/dma/xlnx-zynq-devcfg.h | 2 ++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index b838c1c0d0..03b5280228 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -143,9 +143,11 @@ static void xlnx_zynq_devcfg_reset(DeviceState *dev)
     XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(dev);
     int i;
 
+    s->is_initialized = false;
     for (i = 0; i < XLNX_ZYNQ_DEVCFG_R_MAX; ++i) {
         register_reset(&s->regs_info[i]);
     }
+    s->is_initialized = true;
 }
 
 static void xlnx_zynq_devcfg_dma_go(XlnxZynqDevcfg *s)
@@ -221,7 +223,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 (!s->is_initialized) {
+        return;
+    }
     if (val == R_UNLOCK_MAGIC) {
         DB_PRINT("successful unlock\n");
         s->regs[R_CTRL] |= R_CTRL_PCAP_PR_MASK;
diff --git a/include/hw/dma/xlnx-zynq-devcfg.h b/include/hw/dma/xlnx-zynq-devcfg.h
index e4cf085d70..2ab054e598 100644
--- a/include/hw/dma/xlnx-zynq-devcfg.h
+++ b/include/hw/dma/xlnx-zynq-devcfg.h
@@ -55,6 +55,8 @@ struct XlnxZynqDevcfg {
     XlnxZynqDevcfgDMACmd dma_cmd_fifo[XLNX_ZYNQ_DEVCFG_DMA_CMD_FIFO_LEN];
     uint8_t dma_cmd_fifo_num;
 
+    bool is_initialized;
+
     uint32_t regs[XLNX_ZYNQ_DEVCFG_R_MAX];
     RegisterInfo regs_info[XLNX_ZYNQ_DEVCFG_R_MAX];
 };
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 05/21] hw/dma/zynq: Notify devcfg on FPGA reset via SLCR control
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (3 preceding siblings ...)
  2025-03-18 13:07 ` [PATCH 04/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization Corvin Köhne
@ 2025-03-18 13:07 ` Corvin Köhne
  2025-04-25 16:11   ` Edgar E. Iglesias
  2025-03-18 13:07 ` [PATCH 06/21] hw/dma/zynq-devcfg: Simulate dummy PL reset Corvin Köhne
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:07 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

When the FPGA_RST_CTRL register in the SLCR (System Level Control
Register) is written to, the devcfg (Device Configuration) should
indicate the finished reset.

Problems occure when Loaders trigger a reset via SLCR and poll for
the done flag in devcfg. Since the flag will never be set, this can
result in an endless loop.

A callback function `slcr_reset_handler` is added to the
`XlnxZynqDevcfg` structure. The `slcr_reset` function sets the
`PCFG_DONE` flag when triggered by an FPGA reset in the SLCR.
The SLCR write handler calls the `slcr_reset` function when the
FPGA reset control register (`R_FPGA_RST_CTRL`) is written with
the reset value.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/dma/xlnx-zynq-devcfg.c         |  7 +++++++
 hw/misc/zynq_slcr.c               | 16 ++++++++++++++++
 include/hw/dma/xlnx-zynq-devcfg.h |  1 +
 3 files changed, 24 insertions(+)

diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index 03b5280228..611a57b4d4 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -138,6 +138,11 @@ static void xlnx_zynq_devcfg_update_ixr(XlnxZynqDevcfg *s)
     qemu_set_irq(s->irq, ~s->regs[R_INT_MASK] & s->regs[R_INT_STS]);
 }
 
+static void slcr_reset (DeviceState *dev) {
+    XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(dev);
+    s->regs[R_INT_STS] |= R_INT_STS_PCFG_DONE_MASK;
+}
+
 static void xlnx_zynq_devcfg_reset(DeviceState *dev)
 {
     XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(dev);
@@ -374,6 +379,8 @@ static void xlnx_zynq_devcfg_init(Object *obj)
     XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(obj);
     RegisterInfoArray *reg_array;
 
+    s->slcr_reset_handler = slcr_reset;
+
     sysbus_init_irq(sbd, &s->irq);
 
     memory_region_init(&s->iomem, obj, "devcfg", XLNX_ZYNQ_DEVCFG_R_MAX * 4);
diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
index a766bab182..9b3220f354 100644
--- a/hw/misc/zynq_slcr.c
+++ b/hw/misc/zynq_slcr.c
@@ -26,6 +26,7 @@
 #include "qom/object.h"
 #include "hw/qdev-properties.h"
 #include "qapi/error.h"
+#include "hw/dma/xlnx-zynq-devcfg.h"
 
 #ifndef ZYNQ_SLCR_ERR_DEBUG
 #define ZYNQ_SLCR_ERR_DEBUG 0
@@ -576,6 +577,21 @@ static void zynq_slcr_write(void *opaque, hwaddr offset,
         zynq_slcr_compute_clocks(s);
         zynq_slcr_propagate_clocks(s);
         break;
+    case R_FPGA_RST_CTRL:
+        if (val == 0) {
+            Object *devcfgObject =
+                    object_resolve_type_unambiguous("xlnx.ps7-dev-cfg", NULL);
+            if (!devcfgObject) {
+                break;
+            }
+            DeviceState *devcfg = OBJECT_CHECK(DeviceState, devcfgObject,
+                                               "xlnx.ps7-dev-cfg");
+            XlnxZynqDevcfg *zynqdevcfg = XLNX_ZYNQ_DEVCFG(devcfg);
+            if (zynqdevcfg) {
+                zynqdevcfg->slcr_reset_handler(devcfg);
+            }
+        }
+        break;
     }
 }
 
diff --git a/include/hw/dma/xlnx-zynq-devcfg.h b/include/hw/dma/xlnx-zynq-devcfg.h
index 2ab054e598..f48a630c5a 100644
--- a/include/hw/dma/xlnx-zynq-devcfg.h
+++ b/include/hw/dma/xlnx-zynq-devcfg.h
@@ -56,6 +56,7 @@ struct XlnxZynqDevcfg {
     uint8_t dma_cmd_fifo_num;
 
     bool is_initialized;
+    void (*slcr_reset_handler) (DeviceState *dev);
 
     uint32_t regs[XLNX_ZYNQ_DEVCFG_R_MAX];
     RegisterInfo regs_info[XLNX_ZYNQ_DEVCFG_R_MAX];
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 06/21] hw/dma/zynq-devcfg: Simulate dummy PL reset
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (4 preceding siblings ...)
  2025-03-18 13:07 ` [PATCH 05/21] hw/dma/zynq: Notify devcfg on FPGA reset via SLCR control Corvin Köhne
@ 2025-03-18 13:07 ` Corvin Köhne
  2025-04-25 16:20   ` Edgar E. Iglesias
  2025-03-18 13:07 ` [PATCH 07/21] hw/dma/zynq-devcfg: Indicate power-up status of PL Corvin Köhne
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:07 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini, YannickV

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: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/dma/xlnx-zynq-devcfg.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index 611a57b4d4..c44b802b22 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)
@@ -209,6 +211,14 @@ static uint64_t r_ctrl_pre_write(RegisterInfo *reg, uint64_t val)
             val |= lock_ctrl_map[i] & s->regs[R_CTRL];
         }
     }
+
+    uint32_t pcfg_prog_b = FIELD_EX32(val, CTRL, PCFG_PROG_B);
+    if (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.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 07/21] hw/dma/zynq-devcfg: Indicate power-up status of PL
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (5 preceding siblings ...)
  2025-03-18 13:07 ` [PATCH 06/21] hw/dma/zynq-devcfg: Simulate dummy PL reset Corvin Köhne
@ 2025-03-18 13:07 ` Corvin Köhne
  2025-04-25 16:24   ` Edgar E. Iglesias
  2025-03-18 13:07 ` [PATCH 08/21] hw/dma/zynq-devcfg: Fix register memory Corvin Köhne
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:07 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini, YannickV

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.

This commit is necessary for the Beckhoff CX7200 board emulation
that has a FPGA implemented in the PL.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/dma/xlnx-zynq-devcfg.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index c44b802b22..c595d090fa 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -339,7 +339,7 @@ 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 | 1 << R_MCTRL_PCFG_POR_B_SHIFT | R_MCTRL_QEMU_MASK,
        .ro = ~R_MCTRL_INT_PCAP_LPBK_MASK,
        .rsvd = 0x00f00303,
     },
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 08/21] hw/dma/zynq-devcfg: Fix register memory
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (6 preceding siblings ...)
  2025-03-18 13:07 ` [PATCH 07/21] hw/dma/zynq-devcfg: Indicate power-up status of PL Corvin Köhne
@ 2025-03-18 13:07 ` Corvin Köhne
  2025-04-25 16:27   ` Edgar E. Iglesias
  2025-03-18 13:08 ` [PATCH 09/21] hw/misc: Add dummy ZYNQ DDR controller Corvin Köhne
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:07 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

Registers are always 32 bit aligned. R_MAX is not the maximum
register address, it is the maximum register number. The memory
size can be determined by 4 * R_MAX.

Currently every register with an offset bigger than 0x40 will be
ignored, because the memory size is set wrong. This effects the
MCTRL register and makes it useless. This commit restores the
correct behaviour.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/dma/xlnx-zynq-devcfg.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index c595d090fa..24461677ef 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -400,7 +400,7 @@ static void xlnx_zynq_devcfg_init(Object *obj)
                               s->regs_info, s->regs,
                               &xlnx_zynq_devcfg_reg_ops,
                               XLNX_ZYNQ_DEVCFG_ERR_DEBUG,
-                              XLNX_ZYNQ_DEVCFG_R_MAX);
+                              XLNX_ZYNQ_DEVCFG_R_MAX * 4);
     memory_region_add_subregion(&s->iomem,
                                 A_CTRL,
                                 &reg_array->mem);
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 09/21] hw/misc: Add dummy ZYNQ DDR controller
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (7 preceding siblings ...)
  2025-03-18 13:07 ` [PATCH 08/21] hw/dma/zynq-devcfg: Fix register memory Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-04-25 16:45   ` Edgar E. Iglesias
  2025-03-18 13:08 ` [PATCH 10/21] hw/misc/zynq_slcr: Add logic for DCI configuration Corvin Köhne
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Yannick Voßen, Edgar E. Iglesias, qemu-arm, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini, YannickV

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: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/misc/Kconfig         |   3 +
 hw/misc/meson.build     |   1 +
 hw/misc/zynq_ddr-ctrl.c | 331 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 335 insertions(+)
 create mode 100644 hw/misc/zynq_ddr-ctrl.c

diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index ec0fa5aa9f..1bc4228572 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -222,4 +222,7 @@ config IOSB
 config XLNX_VERSAL_TRNG
     bool
 
+config DDR_CTRLR
+    bool
+
 source macio/Kconfig
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 6d47de482c..8d4c4279c4 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -91,6 +91,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_ZYNQ', if_true: files('zynq_ddr-ctrl.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/zynq_ddr-ctrl.c b/hw/misc/zynq_ddr-ctrl.c
new file mode 100644
index 0000000000..8cdf8be743
--- /dev/null
+++ b/hw/misc/zynq_ddr-ctrl.c
@@ -0,0 +1,331 @@
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/register.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "hw/registerfields.h"
+#include "system/block-backend.h"
+#include "exec/address-spaces.h"
+#include "exec/memory.h"
+#include "system/dma.h"
+
+#ifndef DDRCTRL_ERR_DEBUG
+#define DDRCTRL_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(level, ...) do { \
+    if (DDRCTRL_ERR_DEBUG > (level)) { \
+        fprintf(stderr,  ": %s: ", __func__); \
+        fprintf(stderr, ## __VA_ARGS__); \
+    } \
+} while (0)
+
+#define DB_PRINT(...) DB_PRINT_L(0, ## __VA_ARGS__)
+
+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_RDDA, 0x50)
+REG32(TA_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)
+
+#define TYPE_DDRCTRL "zynq.ddr-ctlr"
+#define DDRCTRL(obj) \
+    OBJECT_CHECK(DDRCTRLState, (obj), TYPE_DDRCTRL)
+
+typedef struct DDRCTRLState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion iomem;
+
+    uint32_t reg[ZYNQ_DDRCTRL_NUM_REG];
+} DDRCTRLState;
+
+
+static bool zynq_ddrctrl_check_addr(hwaddr addr, bool rnw)
+{
+    switch (addr) {
+    case R_PHY_DBG_REG:
+    case R_MODE_STS_REG:
+    case R_CHE_CORR_ECC_LOG_REG_OFFSET ...
+                    R_CHE_CORR_ECC_DATA_71_64_REG_OFFSET:
+    case R_CHE_UNCORR_ECC_ADDR_REG_OFFSET ...
+                    R_CHE_UNCORR_ECC_DATA_71_64_REG_OFFSET:
+    case R_CHE_ECC_CORR_BIT_MASK_31_0_REG_OFFSET:
+    case R_CHE_ECC_CORR_BIT_MASK_63_32_REG_OFFSET:
+    case R_REG69_6A0 ... R_AXI_ID:
+    case R_MODE_REG_READ:
+        return rnw;
+    default:
+        return true;
+    }
+}
+
+static void zynq_ddrctrl_reset_init(Object *obj, ResetType type)
+{
+    DDRCTRLState *s = DDRCTRL(obj);
+
+    DB_PRINT("RESET");
+
+    s->reg[R_DDRC_CTRL]                      = 0x00000200;
+    s->reg[R_TWO_RANK_CFG]                   = 0x000C1076;
+    s->reg[R_HPR_REG]                        = 0x03C0780F;
+    s->reg[R_LPR_REG]                        = 0x03C0780F;
+    s->reg[R_WR_REG]                         = 0x0007F80F;
+    s->reg[R_DRAM_PARAM_REG0]                = 0x00041016;
+    s->reg[R_DRAM_PARAM_REG1]                = 0x351B48D9;
+    s->reg[R_DRAM_PARAM_REG2]                = 0x83015904;
+    s->reg[R_DRAM_PARAM_REG3]                = 0x250882D0;
+    s->reg[R_DRAM_PARAM_REG4]                = 0x0000003C;
+    s->reg[R_DRAM_INIT_PARAM]                = 0x00002007;
+    s->reg[R_DRAM_EMR_REG]                   = 0x00000008;
+    s->reg[R_DRAM_EMR_MR_REG]                = 0x00000940;
+    s->reg[R_DRAM_BURST8_RDWR]               = 0x00020034;
+    s->reg[R_DRAM_ADDR_MAP_BANK]             = 0x00000F77;
+    s->reg[R_DRAM_ADDR_MAP_COL]              = 0xFFF00000;
+    s->reg[R_DRAM_ADDR_MAP_ROW]              = 0x0FF55555;
+    s->reg[R_DRAM_ODT_REG]                   = 0x00000249;
+    s->reg[R_PHY_CMD_TIMEOUT_RDDA]           = 0x00010200;
+    s->reg[R_DLL_CALIB]                      = 0x00000101;
+    s->reg[R_ODT_DELAY_HOLD]                 = 0x00000023;
+    s->reg[R_CTRL_REG1]                      = 0x0000003E;
+    s->reg[R_CTRL_REG2]                      = 0x00020000;
+    s->reg[R_CTRL_REG3]                      = 0x00284027;
+    s->reg[R_CTRL_REG4]                      = 0x00001610;
+    s->reg[R_CTRL_REG5]                      = 0x00455111;
+    s->reg[R_CTRL_REG6]                      = 0x00032222;
+    s->reg[R_CHE_REFRESH_TIMER0]             = 0x00008000;
+    s->reg[R_CHE_T_ZQ]                       = 0x10300802;
+    s->reg[R_CHE_T_ZQ_SHORT_INTERVAL_REG]    = 0x0020003A;
+    s->reg[R_REG_2D]                         = 0x00000200;
+    s->reg[R_DFI_TIMING]                     = 0x00200067;
+    s->reg[R_ECC_SCRUB]                      = 0x00000008;
+    s->reg[R_PHY_CONFIG0]                    = 0x40000001;
+    s->reg[R_PHY_CONFIG1]                    = 0x40000001;
+    s->reg[R_PHY_CONFIG2]                    = 0x40000001;
+    s->reg[R_PHY_CONFIG3]                    = 0x40000001;
+    s->reg[R_PHY_RD_DQS_CFG0]                = 0x00000040;
+    s->reg[R_PHY_RD_DQS_CFG1]                = 0x00000040;
+    s->reg[R_PHY_RD_DQS_CFG2]                = 0x00000040;
+    s->reg[R_PHY_RD_DQS_CFG3]                = 0x00000040;
+    s->reg[R_PHY_WE_CFG0]                    = 0x00000040;
+    s->reg[R_PHY_WE_CFG1]                    = 0x00000040;
+    s->reg[R_PHY_WE_CFG2]                    = 0x00000040;
+    s->reg[R_PHY_WE_CFG3]                    = 0x00000040;
+    s->reg[R_WR_DATA_SLV0]                   = 0x00000080;
+    s->reg[R_WR_DATA_SLV1]                   = 0x00000080;
+    s->reg[R_WR_DATA_SLV2]                   = 0x00000080;
+    s->reg[R_WR_DATA_SLV3]                   = 0x00000080;
+    s->reg[R_REG_64]                         = 0x10020000;
+    s->reg[R_AXI_PRIORITY_WR_PORT0]          = 0x000803FF;
+    s->reg[R_AXI_PRIORITY_WR_PORT1]          = 0x000803FF;
+    s->reg[R_AXI_PRIORITY_WR_PORT2]          = 0x000803FF;
+    s->reg[R_AXI_PRIORITY_WR_PORT3]          = 0x000803FF;
+    s->reg[R_AXI_PRIORITY_RD_PORT0]          = 0x000003FF;
+    s->reg[R_AXI_PRIORITY_RD_PORT1]          = 0x000003FF;
+    s->reg[R_AXI_PRIORITY_RD_PORT2]          = 0x000003FF;
+    s->reg[R_AXI_PRIORITY_RD_PORT3]          = 0x000003FF;
+    s->reg[R_LPDDR_CTRL2]                    = 0x003C0015;
+    s->reg[R_LPDDR_CTRL3]                    = 0x00000601;
+}
+
+static uint64_t zynq_ddrctrl_read(void *opaque, hwaddr addr, unsigned size)
+{
+    DDRCTRLState *s = opaque;
+    addr /= 4;
+    uint32_t ret = s->reg[addr];
+
+    if (!zynq_ddrctrl_check_addr(addr, true)) {
+        qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid read access to "
+                      " addr %" HWADDR_PRIx "\n", addr * 4);
+        return 0;
+    }
+
+    DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", addr * 4, ret);
+    return ret;
+}
+
+static void zynq_ddrctrl_write(void *opaque, hwaddr addr, uint64_t val,
+                               unsigned size)
+{
+    DDRCTRLState *s = opaque;
+    addr /= 4;
+
+    if (!zynq_ddrctrl_check_addr(addr, false)) {
+        qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid read access to "
+                      " addr %" HWADDR_PRIx "\n", addr * 4);
+        return;
+    }
+
+    DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx64 "\n", addr * 4, val);
+
+    switch (addr) {
+    case R_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;
+        }
+        break;
+    }
+
+    s->reg[addr] = val;
+}
+
+static const MemoryRegionOps ddrctrl_ops = {
+    .read = zynq_ddrctrl_read,
+    .write = zynq_ddrctrl_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void zynq_ddrctrl_init(Object *obj)
+{
+    DB_PRINT("Init\n");
+
+    DDRCTRLState *s = DDRCTRL(obj);
+
+    memory_region_init_io(&s->iomem, obj, &ddrctrl_ops, s, "ddrctrl",
+                          ZYNQ_DDRCTRL_MMIO_SIZE);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
+}
+
+static void zynq_ddrctrl_class_init(ObjectClass *klass, void *data)
+{
+    DB_PRINT("Class init\n");
+
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+    rc->phases.enter = zynq_ddrctrl_reset_init;
+}
+
+static const TypeInfo ddrctrl_info = {
+    .name = TYPE_DDRCTRL,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(DDRCTRLState),
+    .class_init = zynq_ddrctrl_class_init,
+    .instance_init = zynq_ddrctrl_init,
+};
+
+static void ddrctrl_register_types(void)
+{
+    type_register_static(&ddrctrl_info);
+}
+
+type_init(ddrctrl_register_types)
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 10/21] hw/misc/zynq_slcr: Add logic for DCI configuration
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (8 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 09/21] hw/misc: Add dummy ZYNQ DDR controller Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-04-25 19:56   ` Edgar E. Iglesias
  2025-03-18 13:08 ` [PATCH 11/21] hw/misc: Add Beckhoff CCAT device Corvin Köhne
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini, YannickV

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: Yannick Voßen <y.vossen@beckhoff.com>
---
 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 9b3220f354..10ef8ecee8 100644
--- a/hw/misc/zynq_slcr.c
+++ b/hw/misc/zynq_slcr.c
@@ -181,6 +181,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
@@ -194,6 +200,8 @@ struct ZynqSLCRState {
 
     MemoryRegion iomem;
 
+    bool ddriob_dci_ctrl_reset_toggled;
+
     uint32_t regs[ZYNQ_SLCR_NUM_REGS];
 
     Clock *ps_clk;
@@ -332,6 +340,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;
@@ -419,6 +429,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)
@@ -555,6 +567,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.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 11/21] hw/misc: Add Beckhoff CCAT device
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (9 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 10/21] hw/misc/zynq_slcr: Add logic for DCI configuration Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-03-18 13:08 ` [PATCH 12/21] hw/arm: Add new machine based on xilinx-zynq-a9 for Beckhoff CX7200 Corvin Köhne
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel, Corvin Köhne, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

This adds the Beckhoff Communication Controller (CCAT). The information
block, EEPROM interface and DMA controller are currently  implemented.

The EEPROM provides production information for Beckhoff Devices.
An EEPORM binary must therefor be handed over. It should be aligned to
a power of two. If no EEPROM binary is handed over an empty EEPROM of
size 4096 is initialized.

This device is needed for the Beckhoff CX7200 board emulation.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/misc/Kconfig         |   3 +
 hw/misc/beckhoff_ccat.c | 365 ++++++++++++++++++++++++++++++++++++++++
 hw/misc/meson.build     |   1 +
 3 files changed, 369 insertions(+)
 create mode 100644 hw/misc/beckhoff_ccat.c

diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 1bc4228572..c264862046 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -225,4 +225,7 @@ config XLNX_VERSAL_TRNG
 config DDR_CTRLR
     bool
 
+config BECKHOFF_CCAT
+    bool
+
 source macio/Kconfig
diff --git a/hw/misc/beckhoff_ccat.c b/hw/misc/beckhoff_ccat.c
new file mode 100644
index 0000000000..3ab1259702
--- /dev/null
+++ b/hw/misc/beckhoff_ccat.c
@@ -0,0 +1,365 @@
+/*
+ * Beckhoff Communication Controller Emulation
+ *
+ * Copyright (c) Beckhoff Automation GmbH. & Co. KG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/register.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "system/block-backend.h"
+#include "exec/address-spaces.h"
+#include "exec/memory.h"
+#include "system/dma.h"
+#include "qemu/error-report.h"
+#include "block/block.h"
+#include "block/block_int.h"
+#include "block/qdict.h"
+#include "hw/block/block.h"
+
+#ifndef CCAT_ERR_DEBUG
+#define CCAT_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(level, ...) do { \
+    if (CCAT_ERR_DEBUG > (level)) { \
+        fprintf(stderr,  ": %s: ", __func__); \
+        fprintf(stderr, ## __VA_ARGS__); \
+    } \
+} while (0)
+
+#define DB_PRINT(...) DB_PRINT_L(0, ## __VA_ARGS__)
+
+#define TYPE_BECKHOFF_CCAT "beckhoff-ccat"
+#define BECKHOFF_CCAT(obj) \
+    OBJECT_CHECK(BeckhoffCcat, (obj), TYPE_BECKHOFF_CCAT)
+
+#define MAX_NUM_SLOTS 32
+
+#define CCAT_EEPROM_OFFSET 0x100
+#define CCAT_DMA_OFFSET 0x8000
+
+#define CCAT_MEM_SIZE 0xFFFF
+#define CCAT_DMA_SIZE 0x800
+#define CCAT_EEPROM_SIZE 0x20
+
+#define EEPROM_MEMORY_SIZE 0x1000
+
+#define EEPROM_CMD_OFFSET (CCAT_EEPROM_OFFSET + 0x00)
+    #define EEPROM_CMD_WRITE_MASK 0x2
+    #define EEPROM_CMD_READ_MASK 0x1
+#define EEPROM_ADR_OFFSET (CCAT_EEPROM_OFFSET + 0x04)
+#define EEPROM_DATA_OFFSET (CCAT_EEPROM_OFFSET + 0x08)
+
+#define DMA_BUFFER_OFFSET (CCAT_DMA_OFFSET + 0x00)
+#define DMA_DIRECTION_OFFSET (CCAT_DMA_OFFSET + 0x7c0)
+    #define DMA_DIRECTION_MASK 1
+#define DMA_TRANSFER_OFFSET (CCAT_DMA_OFFSET + 0x7c4)
+#define DMA_HOST_ADR_OFFSET (CCAT_DMA_OFFSET + 0x7c8)
+#define DMA_TRANSFER_LENGTH_OFFSET (CCAT_DMA_OFFSET + 0x7cc)
+
+/*
+ * The informationblock  is always located at address 0x0.
+ * Address and size are therefor replaced by two identifiers.
+ * The Parameter give information about the maximal number of
+ * function slots and the creation date (in this case 01.01.2001)
+ */
+#define CCAT_ID_1 0x88a4
+#define CCAT_ID_2 0x54414343
+#define CCAT_INFO_BLOCK_PARAMS (MAX_NUM_SLOTS << 0) | (0x1 << 8) | \
+                              (0x1 << 16) | (0x1 << 24)
+
+#define CCAT_FUN_TYPE_ENTRY 0x0001
+#define CCAT_FUN_TYPE_EEPROM 0x0012
+#define CCAT_FUN_TYPE_DMA 0x0013
+
+typedef struct BeckhoffCcat {
+    SysBusDevice parent_obj;
+
+    MemoryRegion iomem;
+
+    uint8_t mem[CCAT_MEM_SIZE];
+
+    BlockBackend *eeprom_blk;
+    uint8_t *eeprom_storage;
+    int64_t eeprom_size;
+} BeckhoffCcat;
+
+typedef struct __attribute__((packed)) CcatFunctionBlock {
+    uint16_t type;
+    uint16_t revision;
+    uint32_t parameter;
+    uint32_t address_offset;
+    uint32_t size;
+} CcatFunctionBlock;
+
+static void sync_eeprom(BeckhoffCcat *s)
+{
+    if (!s->eeprom_blk) {
+        return;
+    }
+    blk_pwrite(s->eeprom_blk, 0, s->eeprom_size, s->eeprom_storage, 0);
+}
+
+static uint64_t beckhoff_ccat_eeprom_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    BeckhoffCcat *s = opaque;
+    uint64_t val = 0;
+    memcpy(&val, &s->mem[addr], size);
+    return val;
+}
+
+static void beckhoff_ccat_eeprom_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned size)
+{
+    BeckhoffCcat *s = opaque;
+    uint64_t eeprom_adr;
+    switch (addr) {
+    case EEPROM_CMD_OFFSET:
+        eeprom_adr = *(uint32_t *)&s->mem[EEPROM_ADR_OFFSET];
+        eeprom_adr = (eeprom_adr * 2) % s->eeprom_size;
+        if (val & EEPROM_CMD_READ_MASK) {
+            uint64_t buf = 0;
+            uint32_t bytes_to_read = 8;
+            if (eeprom_adr > s->eeprom_size - 8) {
+                bytes_to_read = s->eeprom_size - eeprom_adr;
+            }
+            memcpy(&buf, s->eeprom_storage + eeprom_adr, bytes_to_read);
+            *(uint64_t *)&s->mem[EEPROM_DATA_OFFSET] = buf;
+
+        } else if (val & EEPROM_CMD_WRITE_MASK) {
+            uint32_t buf = *(uint32_t *)&s->mem[EEPROM_DATA_OFFSET];
+            memcpy(s->eeprom_storage + eeprom_adr, &buf, 2);
+            sync_eeprom(s);
+        }
+        break;
+    default:
+            memcpy(&s->mem[addr], &val, size);
+    }
+}
+
+static uint64_t beckhoff_ccat_dma_read(void *opaque, hwaddr addr, unsigned size)
+{
+    BeckhoffCcat *s = opaque;
+    uint64_t val = 0;
+
+    switch (addr) {
+    case DMA_TRANSFER_OFFSET:
+        if (s->mem[DMA_TRANSFER_OFFSET] & 0x1) {
+            DB_PRINT("DMA transfer finished\n");
+            s->mem[DMA_TRANSFER_OFFSET] = 0;
+        }
+        break;
+    }
+    memcpy(&val, &s->mem[addr], size);
+    return val;
+}
+
+static void beckhoff_ccat_dma_write(void *opaque, hwaddr addr, uint64_t val,
+                           unsigned size)
+{
+    BeckhoffCcat *s = opaque;
+    switch (addr) {
+    case DMA_TRANSFER_OFFSET:
+        uint8_t len = s->mem[DMA_TRANSFER_LENGTH_OFFSET];
+        uint8_t *mem_buf = &s->mem[DMA_BUFFER_OFFSET];
+
+        if (s->mem[DMA_DIRECTION_OFFSET] & DMA_DIRECTION_MASK) {
+            dma_addr_t dmaAddr = *(uint32_t *)&s->mem[DMA_HOST_ADR_OFFSET];
+            dma_memory_read(&address_space_memory, dmaAddr,
+                            mem_buf, len * 8, MEMTXATTRS_UNSPECIFIED);
+        } else {
+            dma_addr_t dmaAddr = *(uint32_t *)&s->mem[DMA_HOST_ADR_OFFSET];
+            dma_memory_write(&address_space_memory, dmaAddr + 8,
+                                mem_buf, len * 8, MEMTXATTRS_UNSPECIFIED);
+        }
+        break;
+    }
+    memcpy(&s->mem[addr], &val, size);
+}
+static uint64_t beckhoff_ccat_read(void *opaque, hwaddr addr, unsigned size)
+{
+    DB_PRINT("CCAT_READ addr=0x%lx size=%u\n", addr, size);
+
+    BeckhoffCcat *s = opaque;
+    uint64_t val = 0;
+
+    if (addr > CCAT_MEM_SIZE - size) {
+        error_report("Overflow. Address or size is too large.\n");
+        exit(1);
+    }
+
+    if (addr >= CCAT_EEPROM_OFFSET &&
+                        addr <= CCAT_EEPROM_OFFSET + s->eeprom_size) {
+        return beckhoff_ccat_eeprom_read(opaque, addr, size);
+    } else if (addr >= CCAT_DMA_OFFSET &&
+                        addr <= CCAT_DMA_OFFSET + CCAT_DMA_SIZE) {
+        return beckhoff_ccat_dma_read(opaque, addr, size);
+    } else {
+         memcpy(&val, &s->mem[addr], size);
+    }
+
+    return val;
+}
+
+static void beckhoff_ccat_write(void *opaque, hwaddr addr, uint64_t val,
+                                unsigned size)
+{
+    DB_PRINT("CCAT_WRITE addr=0x%lx size=%u val=0x%lx\n", addr, size, val);
+
+    BeckhoffCcat *s = opaque;
+
+    if (addr > CCAT_MEM_SIZE - size) {
+        error_report("Overflow. Address or size is too large.\n");
+        exit(1);
+    }
+
+    if (addr >= CCAT_EEPROM_OFFSET &&
+                        addr <= CCAT_EEPROM_OFFSET + s->eeprom_size) {
+        beckhoff_ccat_eeprom_write(opaque, addr, val, size);
+    } else if (addr >= CCAT_DMA_OFFSET &&
+                        addr <= CCAT_DMA_OFFSET + CCAT_DMA_SIZE) {
+        beckhoff_ccat_dma_write(opaque, addr, val, size);
+    } else {
+        memcpy(&s->mem[addr], &val, size);
+    }
+}
+
+static const MemoryRegionOps beckhoff_ccat_ops = {
+    .read = beckhoff_ccat_read,
+    .write = beckhoff_ccat_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 8,
+    },
+};
+
+
+static void beckhoff_ccat_reset(DeviceState *dev)
+{
+    BeckhoffCcat *s = BECKHOFF_CCAT(dev);
+
+    CcatFunctionBlock function_blocks[MAX_NUM_SLOTS] = {0};
+
+    CcatFunctionBlock info_block = {
+        .type = CCAT_FUN_TYPE_ENTRY,
+        .revision = 0x0001,
+        .parameter = CCAT_INFO_BLOCK_PARAMS,
+        .address_offset = CCAT_ID_1,
+        .size = CCAT_ID_2
+    };
+    CcatFunctionBlock eeprom_block = {
+        .type = CCAT_FUN_TYPE_EEPROM,
+        .revision = 0x0001,
+        .parameter = 0,
+        .address_offset = CCAT_EEPROM_OFFSET,
+        .size = CCAT_EEPROM_SIZE
+    };
+    CcatFunctionBlock dma_block = {
+        .type = CCAT_FUN_TYPE_DMA,
+        .revision = 0x0000,
+        .parameter = 0,
+        .address_offset = CCAT_DMA_OFFSET,
+        .size = CCAT_DMA_SIZE
+    };
+
+    /*
+     * The EEPROM interface is usually at function slot 11.
+     * The DMA controller is usually at function slot 15.
+     */
+    function_blocks[0] = info_block;
+    function_blocks[11] = eeprom_block;
+    function_blocks[15] = dma_block;
+
+    memcpy(&s->mem[0], function_blocks, sizeof(function_blocks));
+}
+
+static void beckhoff_ccat_realize(DeviceState *dev, Error **errp)
+{
+    BeckhoffCcat *s = BECKHOFF_CCAT(dev);
+    BlockBackend *blk;
+
+    blk = blk_by_name("ccat-eeprom");
+
+    if (blk) {
+        uint64_t blk_size = blk_getlength(blk);
+        if (!is_power_of_2(blk_size)) {
+            error_report("Blockend size is not a power of two.");
+        }
+
+        if (blk_size < 512) {
+            error_report("Blockend size is too small. Using backup.");
+            s->eeprom_size = EEPROM_MEMORY_SIZE;
+            s->eeprom_storage = blk_blockalign(NULL, s->eeprom_size);
+            memset(s->eeprom_storage, 0x00, s->eeprom_size);
+        } else {
+            DB_PRINT("EEPROM block backend found\n");
+            blk_set_perm(blk, BLK_PERM_WRITE, BLK_PERM_ALL, errp);
+
+            s->eeprom_size = blk_size;
+            s->eeprom_blk = blk;
+            s->eeprom_storage = blk_blockalign(s->eeprom_blk, s->eeprom_size);
+
+            if (!blk_check_size_and_read_all(s->eeprom_blk, DEVICE(s),
+                                             s->eeprom_storage, s->eeprom_size,
+                                             errp)) {
+                exit(1);
+            }
+        }
+    } else {
+        s->eeprom_size = EEPROM_MEMORY_SIZE;
+        s->eeprom_storage = blk_blockalign(NULL, s->eeprom_size);
+        memset(s->eeprom_storage, 0x00, s->eeprom_size);
+    }
+
+    beckhoff_ccat_reset(dev);
+}
+
+static void beckhoff_ccat_init(Object *obj)
+{
+    BeckhoffCcat *s = BECKHOFF_CCAT(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+    memory_region_init_io(&s->iomem, obj, &beckhoff_ccat_ops, s,
+                          TYPE_BECKHOFF_CCAT, CCAT_MEM_SIZE);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void beckhoff_ccat_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->realize = beckhoff_ccat_realize;
+}
+
+static const TypeInfo beckhoff_ccat_info = {
+ .name = TYPE_BECKHOFF_CCAT,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(BeckhoffCcat),
+ .class_init = beckhoff_ccat_class_init,
+ .instance_init = beckhoff_ccat_init,
+};
+
+static void beckhoff_ccat_register_types(void)
+{
+    type_register_static(&beckhoff_ccat_info);
+}
+
+type_init(beckhoff_ccat_register_types)
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 8d4c4279c4..ca0b261715 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -14,6 +14,7 @@ system_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c'))
 system_ss.add(when: 'CONFIG_INTEGRATOR_DEBUG', if_true: files('arm_integrator_debug.c'))
 system_ss.add(when: 'CONFIG_A9SCU', if_true: files('a9scu.c'))
 system_ss.add(when: 'CONFIG_ARM11SCU', if_true: files('arm11scu.c'))
+system_ss.add(when: 'CONFIG_BECKHOFF_CCAT', if_true: files('beckhoff_ccat.c'))
 
 system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_ras.c'))
 
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 12/21] hw/arm: Add new machine based on xilinx-zynq-a9 for Beckhoff CX7200
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (10 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 11/21] hw/misc: Add Beckhoff CCAT device Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-03-18 13:08 ` [PATCH 13/21] hw/arm/beckhoff_CX7200: Remove second SD controller Corvin Köhne
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel, Corvin Köhne, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

This commit introduces a new machine, derived from xilinx-zynq-a9,
as a starting point for the Beckhoff CX7200 integration. Functions
and structs are renamed to delimit the CX7200 board emulation from
the existing Zynq emulation.

At this stage, the new machine is a direct copy of hw/arm/xilinx_zynq.c.
Future commits will adapt it to match the CX7200 hardware requirements.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/arm/Kconfig           |  18 ++
 hw/arm/beckhoff_CX7200.c | 496 +++++++++++++++++++++++++++++++++++++++
 hw/arm/meson.build       |   1 +
 3 files changed, 515 insertions(+)
 create mode 100644 hw/arm/beckhoff_CX7200.c

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 15200a2d7e..8727b3e837 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -311,6 +311,24 @@ config ZYNQ
     select XILINX_SPIPS
     select ZYNQ_DEVCFG
 
+config BECK_CX7200
+    bool
+    default y
+    depends on TCG && ARM
+    select A9MPCORE
+    select CADENCE # UART
+    select PFLASH_CFI02
+    select PL310 # cache controller
+    select PL330
+    select SDHCI
+    select SSI_M25P80
+    select USB_EHCI_SYSBUS
+    select XILINX # UART
+    select XILINX_AXI
+    select XILINX_SPI
+    select XILINX_SPIPS
+    select ZYNQ_DEVCFG
+
 config ARM_V7M
     bool
     # currently v7M must be included in a TCG build due to translate.c
diff --git a/hw/arm/beckhoff_CX7200.c b/hw/arm/beckhoff_CX7200.c
new file mode 100644
index 0000000000..89466cfdd8
--- /dev/null
+++ b/hw/arm/beckhoff_CX7200.c
@@ -0,0 +1,496 @@
+/*
+ * Modified Xilinx Zynq Baseboard System emulation for Beckhoff CX7200.
+ *
+ * Based on /hw/arm/xilinx_zynq.c:
+ * Copyright (c) 2010 Xilinx.
+ * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.croshtwaite@petalogix.com)
+ * Copyright (c) 2012 Petalogix Pty Ltd.
+ * Original code by Haibing Ma.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
+#include "hw/sysbus.h"
+#include "hw/arm/boot.h"
+#include "net/net.h"
+#include "system/system.h"
+#include "hw/boards.h"
+#include "hw/block/flash.h"
+#include "hw/loader.h"
+#include "hw/adc/zynq-xadc.h"
+#include "hw/ssi/ssi.h"
+#include "hw/usb/chipidea.h"
+#include "qemu/error-report.h"
+#include "hw/sd/sdhci.h"
+#include "hw/char/cadence_uart.h"
+#include "hw/net/cadence_gem.h"
+#include "hw/cpu/a9mpcore.h"
+#include "hw/qdev-clock.h"
+#include "hw/misc/unimp.h"
+#include "system/reset.h"
+#include "qom/object.h"
+#include "exec/tswap.h"
+#include "target/arm/cpu-qom.h"
+#include "qapi/visitor.h"
+
+#define TYPE_CX7200_MACHINE MACHINE_TYPE_NAME("beckhoff-cx7200")
+OBJECT_DECLARE_SIMPLE_TYPE(CX7200MachineState, CX7200_MACHINE)
+
+/* board base frequency: 33.333333 MHz */
+#define PS_CLK_FREQUENCY (100 * 1000 * 1000 / 3)
+
+#define NUM_SPI_FLASHES 4
+#define NUM_QSPI_FLASHES 2
+#define NUM_QSPI_BUSSES 2
+
+#define FLASH_SIZE (64 * 1024 * 1024)
+#define FLASH_SECTOR_SIZE (128 * 1024)
+
+#define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
+
+#define MPCORE_PERIPHBASE 0xF8F00000
+#define ZYNQ_BOARD_MIDR 0x413FC090
+
+static const int dma_irqs[8] = {
+    46, 47, 48, 49, 72, 73, 74, 75
+};
+
+#define BOARD_SETUP_ADDR        0x100
+
+#define SLCR_LOCK_OFFSET        0x004
+#define SLCR_UNLOCK_OFFSET      0x008
+#define SLCR_ARM_PLL_OFFSET     0x100
+
+#define SLCR_XILINX_UNLOCK_KEY  0xdf0d
+#define SLCR_XILINX_LOCK_KEY    0x767b
+
+#define ZYNQ_SDHCI_CAPABILITIES 0x69ec0080  /* Datasheet: UG585 (v1.12.1) */
+
+#define ARMV7_IMM16(x) (extract32((x),  0, 12) | \
+                        extract32((x), 12,  4) << 16)
+
+/*
+ * Write immediate val to address r0 + addr. r0 should contain base offset
+ * of the SLCR block. Clobbers r1.
+ */
+
+#define SLCR_WRITE(addr, val) \
+    0xe3001000 + ARMV7_IMM16(extract32((val),  0, 16)), /* movw r1 ... */ \
+    0xe3401000 + ARMV7_IMM16(extract32((val), 16, 16)), /* movt r1 ... */ \
+    0xe5801000 + (addr)
+
+#define ZYNQ_MAX_CPUS 2
+
+struct CX7200MachineState {
+    MachineState parent;
+    Clock *ps_clk;
+    ARMCPU *cpu[ZYNQ_MAX_CPUS];
+    uint8_t boot_mode;
+};
+
+static void beckhoff_cx7200_write_board_setup(ARMCPU *cpu,
+                                   const struct arm_boot_info *info)
+{
+    int n;
+    uint32_t board_setup_blob[] = {
+        0xe3a004f8, /* mov r0, #0xf8000000 */
+        SLCR_WRITE(SLCR_UNLOCK_OFFSET, SLCR_XILINX_UNLOCK_KEY),
+        SLCR_WRITE(SLCR_ARM_PLL_OFFSET, 0x00014008),
+        SLCR_WRITE(SLCR_LOCK_OFFSET, SLCR_XILINX_LOCK_KEY),
+        0xe12fff1e, /* bx lr */
+    };
+    for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) {
+        board_setup_blob[n] = tswap32(board_setup_blob[n]);
+    }
+    rom_add_blob_fixed("board-setup", board_setup_blob,
+                       sizeof(board_setup_blob), BOARD_SETUP_ADDR);
+}
+
+static struct arm_boot_info beckhoff_cx7200_binfo = {};
+
+static void gem_init(uint32_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_new(TYPE_CADENCE_GEM);
+    qemu_configure_nic_device(dev, true, NULL);
+    object_property_set_int(OBJECT(dev), "phy-addr", 7, &error_abort);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_realize_and_unref(s, &error_fatal);
+    sysbus_mmio_map(s, 0, base);
+    sysbus_connect_irq(s, 0, irq);
+}
+
+static inline int beckhoff_cx7200_init_spi_flashes(uint32_t base_addr,
+                                        qemu_irq irq, bool is_qspi, int unit0)
+{
+    int unit = unit0;
+    DeviceState *dev;
+    SysBusDevice *busdev;
+    SSIBus *spi;
+    DeviceState *flash_dev;
+    int i, j;
+    int num_busses =  is_qspi ? NUM_QSPI_BUSSES : 1;
+    int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES;
+
+    dev = qdev_new(is_qspi ? "xlnx.ps7-qspi" : "xlnx.ps7-spi");
+    qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1);
+    qdev_prop_set_uint8(dev, "num-ss-bits", num_ss);
+    qdev_prop_set_uint8(dev, "num-busses", num_busses);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_realize_and_unref(busdev, &error_fatal);
+    sysbus_mmio_map(busdev, 0, base_addr);
+    if (is_qspi) {
+        sysbus_mmio_map(busdev, 1, 0xFC000000);
+    }
+    sysbus_connect_irq(busdev, 0, irq);
+
+    for (i = 0; i < num_busses; ++i) {
+        char bus_name[16];
+        qemu_irq cs_line;
+
+        snprintf(bus_name, 16, "spi%d", i);
+        spi = (SSIBus *)qdev_get_child_bus(dev, bus_name);
+
+        for (j = 0; j < num_ss; ++j) {
+            DriveInfo *dinfo = drive_get(IF_MTD, 0, unit++);
+            flash_dev = qdev_new("n25q128");
+            if (dinfo) {
+                qdev_prop_set_drive_err(flash_dev, "drive",
+                                        blk_by_legacy_dinfo(dinfo),
+                                        &error_fatal);
+            }
+            qdev_prop_set_uint8(flash_dev, "cs", j);
+            qdev_realize_and_unref(flash_dev, BUS(spi), &error_fatal);
+
+            cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
+            sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
+        }
+    }
+
+    return unit;
+}
+
+static void beckhoff_cx7200_set_boot_mode(Object *obj, const char *str,
+                                               Error **errp)
+{
+    CX7200MachineState *m = CX7200_MACHINE(obj);
+    uint8_t mode = 0;
+
+    if (!strncasecmp(str, "qspi", 4)) {
+        mode = 1;
+    } else if (!strncasecmp(str, "sd", 2)) {
+        mode = 5;
+    } else if (!strncasecmp(str, "nor", 3)) {
+        mode = 2;
+    } else if (!strncasecmp(str, "jtag", 4)) {
+        mode = 0;
+    } else {
+        error_setg(errp, "%s boot mode not supported", str);
+        return;
+    }
+    m->boot_mode = mode;
+}
+
+static void beckhoff_cx7200_init(MachineState *machine)
+{
+    CX7200MachineState *cx7200_machine = CX7200_MACHINE(machine);
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
+    DeviceState *dev, *slcr;
+    SysBusDevice *busdev;
+    qemu_irq pic[64];
+    int n;
+    unsigned int smp_cpus = machine->smp.cpus;
+
+    /* max 2GB ram */
+    if (machine->ram_size > 2 * GiB) {
+        error_report("RAM size more than 2 GiB is not supported");
+        exit(EXIT_FAILURE);
+    }
+
+    for (n = 0; n < smp_cpus; n++) {
+        Object *cpuobj = object_new(machine->cpu_type);
+
+        object_property_set_int(cpuobj, "midr", ZYNQ_BOARD_MIDR,
+                                &error_fatal);
+        object_property_set_int(cpuobj, "reset-cbar", MPCORE_PERIPHBASE,
+                                &error_fatal);
+
+        qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
+
+        cx7200_machine->cpu[n] = ARM_CPU(cpuobj);
+    }
+
+    /* DDR remapped to address zero.  */
+    memory_region_add_subregion(address_space_mem, 0, machine->ram);
+
+    /* 256K of on-chip memory */
+    memory_region_init_ram(ocm_ram, NULL, "zynq.ocm_ram", 256 * KiB,
+                           &error_fatal);
+    memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram);
+
+    DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
+
+    /* AMD */
+    pflash_cfi02_register(0xe2000000, "zynq.pflash", FLASH_SIZE,
+                          dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
+                          FLASH_SECTOR_SIZE, 1,
+                          1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa,
+                          0);
+
+    /* Create the main clock source, and feed slcr with it */
+    cx7200_machine->ps_clk = CLOCK(object_new(TYPE_CLOCK));
+    object_property_add_child(OBJECT(cx7200_machine), "ps_clk",
+                              OBJECT(cx7200_machine->ps_clk));
+    object_unref(OBJECT(cx7200_machine->ps_clk));
+    clock_set_hz(cx7200_machine->ps_clk, PS_CLK_FREQUENCY);
+
+    /* Create slcr, keep a pointer to connect clocks */
+    slcr = qdev_new("xilinx-zynq_slcr");
+    qdev_connect_clock_in(slcr, "ps_clk", cx7200_machine->ps_clk);
+    qdev_prop_set_uint8(slcr, "boot-mode", cx7200_machine->boot_mode);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(slcr), &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(slcr), 0, 0xF8000000);
+
+    dev = qdev_new(TYPE_A9MPCORE_PRIV);
+    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_realize_and_unref(busdev, &error_fatal);
+    sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
+    beckhoff_cx7200_binfo.gic_cpu_if_addr = MPCORE_PERIPHBASE + 0x100;
+    sysbus_create_varargs("l2x0", MPCORE_PERIPHBASE + 0x2000, NULL);
+    for (n = 0; n < smp_cpus; n++) {
+        /* See "hw/intc/arm_gic.h" for the IRQ line association */
+        DeviceState *cpudev = DEVICE(cx7200_machine->cpu[n]);
+        sysbus_connect_irq(busdev, n,
+                           qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
+        sysbus_connect_irq(busdev, smp_cpus + n,
+                           qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+    }
+
+    for (n = 0; n < 64; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    n = beckhoff_cx7200_init_spi_flashes(0xE0006000, pic[58 - IRQ_OFFSET],
+                                         false, 0);
+    n = beckhoff_cx7200_init_spi_flashes(0xE0007000, pic[81 - IRQ_OFFSET],
+                                         false, n);
+    n = beckhoff_cx7200_init_spi_flashes(0xE000D000, pic[51 - IRQ_OFFSET],
+                                         true, n);
+
+    sysbus_create_simple(TYPE_CHIPIDEA, 0xE0002000, pic[53 - IRQ_OFFSET]);
+    sysbus_create_simple(TYPE_CHIPIDEA, 0xE0003000, pic[76 - IRQ_OFFSET]);
+
+    dev = qdev_new(TYPE_CADENCE_UART);
+    busdev = SYS_BUS_DEVICE(dev);
+    qdev_prop_set_chr(dev, "chardev", serial_hd(0));
+    qdev_connect_clock_in(dev, "refclk",
+                          qdev_get_clock_out(slcr, "uart0_ref_clk"));
+    sysbus_realize_and_unref(busdev, &error_fatal);
+    sysbus_mmio_map(busdev, 0, 0xE0000000);
+    sysbus_connect_irq(busdev, 0, pic[59 - IRQ_OFFSET]);
+    dev = qdev_new(TYPE_CADENCE_UART);
+    busdev = SYS_BUS_DEVICE(dev);
+    qdev_prop_set_chr(dev, "chardev", serial_hd(1));
+    qdev_connect_clock_in(dev, "refclk",
+                          qdev_get_clock_out(slcr, "uart1_ref_clk"));
+    sysbus_realize_and_unref(busdev, &error_fatal);
+    sysbus_mmio_map(busdev, 0, 0xE0001000);
+    sysbus_connect_irq(busdev, 0, pic[82 - IRQ_OFFSET]);
+
+    sysbus_create_varargs("cadence_ttc", 0xF8001000, pic[42 - IRQ_OFFSET],
+                          pic[43 - IRQ_OFFSET], pic[44 - IRQ_OFFSET], NULL);
+    sysbus_create_varargs("cadence_ttc", 0xF8002000, pic[69 - IRQ_OFFSET],
+                          pic[70 - IRQ_OFFSET], pic[71 - IRQ_OFFSET], NULL);
+
+    gem_init(0xE000B000, pic[54 - IRQ_OFFSET]);
+    gem_init(0xE000C000, pic[77 - IRQ_OFFSET]);
+
+    for (n = 0; n < 2; n++) {
+        int hci_irq = n ? 79 : 56;
+        hwaddr hci_addr = n ? 0xE0101000 : 0xE0100000;
+        DriveInfo *di;
+        BlockBackend *blk;
+        DeviceState *carddev;
+
+        /*
+         * Compatible with:
+         * - SD Host Controller Specification Version 2.0 Part A2
+         * - SDIO Specification Version 2.0
+         * - MMC Specification Version 3.31
+         */
+        dev = qdev_new(TYPE_SYSBUS_SDHCI);
+        qdev_prop_set_uint8(dev, "sd-spec-version", 2);
+        qdev_prop_set_uint64(dev, "capareg", ZYNQ_SDHCI_CAPABILITIES);
+        sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, hci_addr);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[hci_irq - IRQ_OFFSET]);
+
+        di = drive_get(IF_SD, 0, n);
+        blk = di ? blk_by_legacy_dinfo(di) : NULL;
+        carddev = qdev_new(TYPE_SD_CARD);
+        qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
+        qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"),
+                               &error_fatal);
+    }
+
+    dev = qdev_new(TYPE_ZYNQ_XADC);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[39 - IRQ_OFFSET]);
+
+    dev = qdev_new("pl330");
+    object_property_set_link(OBJECT(dev), "memory",
+                             OBJECT(address_space_mem),
+                             &error_fatal);
+    qdev_prop_set_uint8(dev, "num_chnls",  8);
+    qdev_prop_set_uint8(dev, "num_periph_req",  4);
+    qdev_prop_set_uint8(dev, "num_events",  16);
+
+    qdev_prop_set_uint8(dev, "data_width",  64);
+    qdev_prop_set_uint8(dev, "wr_cap",  8);
+    qdev_prop_set_uint8(dev, "wr_q_dep",  16);
+    qdev_prop_set_uint8(dev, "rd_cap",  8);
+    qdev_prop_set_uint8(dev, "rd_q_dep",  16);
+    qdev_prop_set_uint16(dev, "data_buffer_dep",  256);
+
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_realize_and_unref(busdev, &error_fatal);
+    sysbus_mmio_map(busdev, 0, 0xF8003000);
+    sysbus_connect_irq(busdev, 0, pic[45 - IRQ_OFFSET]); /* abort irq line */
+    for (n = 0; n < ARRAY_SIZE(dma_irqs); ++n) { /* event irqs */
+        sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]);
+    }
+
+    dev = qdev_new("xlnx.ps7-dev-cfg");
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_realize_and_unref(busdev, &error_fatal);
+    sysbus_connect_irq(busdev, 0, pic[40 - IRQ_OFFSET]);
+    sysbus_mmio_map(busdev, 0, 0xF8007000);
+
+    /*
+     * Refer to the ug585-Zynq-7000-TRM manual B.3 (Module Summary) and
+     * the zynq-7000.dtsi. Add placeholders for unimplemented devices.
+     */
+    create_unimplemented_device("zynq.i2c0", 0xE0004000, 4 * KiB);
+    create_unimplemented_device("zynq.i2c1", 0xE0005000, 4 * KiB);
+    create_unimplemented_device("zynq.can0", 0xE0008000, 4 * KiB);
+    create_unimplemented_device("zynq.can1", 0xE0009000, 4 * KiB);
+    create_unimplemented_device("zynq.gpio", 0xE000A000, 4 * KiB);
+    create_unimplemented_device("zynq.smcc", 0xE000E000, 4 * KiB);
+
+    /* Direct Memory Access Controller, PL330, Non-Secure Mode */
+    create_unimplemented_device("zynq.dma_ns", 0xF8004000, 4 * KiB);
+
+    /* 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);
+    create_unimplemented_device("zynq.axi_hp2", 0xF800A000, 0x28);
+    create_unimplemented_device("zynq.axi_hp3", 0xF800B000, 0x28);
+
+    create_unimplemented_device("zynq.efuse", 0xF800d000, 0x20);
+
+    /* Embedded Trace Buffer */
+    create_unimplemented_device("zynq.etb", 0xF8801000, 4 * KiB);
+
+    /* Cross Trigger Interface, ETB and TPIU */
+    create_unimplemented_device("zynq.cti_etb_tpiu", 0xF8802000, 4 * KiB);
+
+    /* Trace Port Interface Unit */
+    create_unimplemented_device("zynq.tpiu", 0xF8803000, 4 * KiB);
+
+    /* CoreSight Trace Funnel */
+    create_unimplemented_device("zynq.funnel", 0xF8804000, 4 * KiB);
+
+    /* Instrumentation Trace Macrocell */
+    create_unimplemented_device("zynq.itm", 0xF8805000, 4 * KiB);
+
+    /* Cross Trigger Interface, FTM */
+    create_unimplemented_device("zynq.cti_ftm", 0xF8809000, 4 * KiB);
+
+    /* Fabric Trace Macrocell */
+    create_unimplemented_device("zynq.ftm", 0xF880B000, 4 * KiB);
+
+    /* Cortex A9 Performance Monitoring Unit, CPU */
+    create_unimplemented_device("cortex-a9.pmu0", 0xF8891000, 4 * KiB);
+    create_unimplemented_device("cortex-a9.pmu1", 0xF8893000, 4 * KiB);
+
+    /* Cross Trigger Interface, CPU */
+    create_unimplemented_device("zynq.cpu_cti0", 0xF8898000, 4 * KiB);
+    create_unimplemented_device("zynq.cpu_cti1", 0xF8899000, 4 * KiB);
+
+    /* CoreSight PTM-A9, CPU */
+    create_unimplemented_device("cortex-a9.ptm0", 0xF889c000, 4 * KiB);
+    create_unimplemented_device("cortex-a9.ptm1", 0xF889d000, 4 * KiB);
+
+    /* AMBA NIC301 TrustZone */
+    create_unimplemented_device("zynq.trustZone", 0xF8900000, 0x20);
+
+    /* AMBA Network Interconnect Advanced Quality of Service (QoS-301) */
+    create_unimplemented_device("zynq.qos301_cpu", 0xF8946000, 0x130);
+    create_unimplemented_device("zynq.qos301_dmac", 0xF8947000, 0x130);
+    create_unimplemented_device("zynq.qos301_iou", 0xF8948000, 0x130);
+
+    beckhoff_cx7200_binfo.ram_size = machine->ram_size;
+    beckhoff_cx7200_binfo.board_id = 0xd32;
+    beckhoff_cx7200_binfo.loader_start = 0;
+    beckhoff_cx7200_binfo.board_setup_addr = BOARD_SETUP_ADDR;
+    beckhoff_cx7200_binfo.write_board_setup = beckhoff_cx7200_write_board_setup;
+
+    arm_load_kernel(cx7200_machine->cpu[0], machine, &beckhoff_cx7200_binfo);
+}
+
+static void beckhoff_cx7200_machine_class_init(ObjectClass *oc, void *data)
+{
+    static const char * const valid_cpu_types[] = {
+        ARM_CPU_TYPE_NAME("cortex-a9"),
+        NULL
+    };
+    MachineClass *mc = MACHINE_CLASS(oc);
+    ObjectProperty *prop;
+    mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9";
+    mc->init = beckhoff_cx7200_init;
+    mc->max_cpus = ZYNQ_MAX_CPUS;
+    mc->no_sdcard = 1;
+    mc->ignore_memory_transaction_failures = true;
+    mc->valid_cpu_types = valid_cpu_types;
+    mc->default_ram_id = "zynq.ext_ram";
+    prop = object_class_property_add_str(oc, "boot-mode", NULL,
+                                         beckhoff_cx7200_set_boot_mode);
+    object_class_property_set_description(oc, "boot-mode",
+                                          "Supported boot modes:"
+                                          " jtag qspi sd nor");
+    object_property_set_default_str(prop, "qspi");
+}
+
+static const TypeInfo beckhoff_cx7200_machine_type = {
+    .name = TYPE_CX7200_MACHINE,
+    .parent = TYPE_MACHINE,
+    .class_init = beckhoff_cx7200_machine_class_init,
+    .instance_size = sizeof(CX7200MachineState),
+};
+
+static void beckhoff_cx7200_machine_register_types(void)
+{
+    type_register_static(&beckhoff_cx7200_machine_type);
+}
+
+type_init(beckhoff_cx7200_machine_register_types)
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
index ac473ce7cd..c862e9c88e 100644
--- a/hw/arm/meson.build
+++ b/hw/arm/meson.build
@@ -18,6 +18,7 @@ arm_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c'))
 arm_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c'))
 arm_ss.add(when: 'CONFIG_STM32VLDISCOVERY', if_true: files('stm32vldiscovery.c'))
 arm_ss.add(when: 'CONFIG_ZYNQ', if_true: files('xilinx_zynq.c'))
+arm_ss.add(when: 'CONFIG_BECK_CX7200', if_true: files('beckhoff_CX7200.c'))
 arm_ss.add(when: 'CONFIG_SABRELITE', if_true: files('sabrelite.c'))
 
 arm_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m.c'))
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 13/21] hw/arm/beckhoff_CX7200: Remove second SD controller
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (11 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 12/21] hw/arm: Add new machine based on xilinx-zynq-a9 for Beckhoff CX7200 Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-05-06 13:17   ` Peter Maydell
  2025-03-18 13:08 ` [PATCH 14/21] hw/arm/beckhoff_CX7200: Remove second GEM Corvin Köhne
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel, Corvin Köhne, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

The CX7200 has one SD controller connected to address 0xE0101000.
The controller connected to address 0xE0100000 can be removed.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/arm/beckhoff_CX7200.c | 48 ++++++++++++++++++----------------------
 1 file changed, 21 insertions(+), 27 deletions(-)

diff --git a/hw/arm/beckhoff_CX7200.c b/hw/arm/beckhoff_CX7200.c
index 89466cfdd8..bf3c66e5a4 100644
--- a/hw/arm/beckhoff_CX7200.c
+++ b/hw/arm/beckhoff_CX7200.c
@@ -207,11 +207,13 @@ static void beckhoff_cx7200_init(MachineState *machine)
     CX7200MachineState *cx7200_machine = CX7200_MACHINE(machine);
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
-    DeviceState *dev, *slcr;
+    DeviceState *carddev, *dev, *slcr;
     SysBusDevice *busdev;
     qemu_irq pic[64];
     int n;
     unsigned int smp_cpus = machine->smp.cpus;
+    DriveInfo *di;
+    BlockBackend *blk;
 
     /* max 2GB ram */
     if (machine->ram_size > 2 * GiB) {
@@ -318,33 +320,25 @@ static void beckhoff_cx7200_init(MachineState *machine)
     gem_init(0xE000B000, pic[54 - IRQ_OFFSET]);
     gem_init(0xE000C000, pic[77 - IRQ_OFFSET]);
 
-    for (n = 0; n < 2; n++) {
-        int hci_irq = n ? 79 : 56;
-        hwaddr hci_addr = n ? 0xE0101000 : 0xE0100000;
-        DriveInfo *di;
-        BlockBackend *blk;
-        DeviceState *carddev;
+    /*
+     * Compatible with:
+     * - SD Host Controller Specification Version 2.0 Part A2
+     * - SDIO Specification Version 2.0
+     * - MMC Specification Version 3.31
+     */
+    dev = qdev_new(TYPE_SYSBUS_SDHCI);
+    qdev_prop_set_uint8(dev, "sd-spec-version", 2);
+    qdev_prop_set_uint64(dev, "capareg", ZYNQ_SDHCI_CAPABILITIES);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79 - IRQ_OFFSET]);
 
-        /*
-         * Compatible with:
-         * - SD Host Controller Specification Version 2.0 Part A2
-         * - SDIO Specification Version 2.0
-         * - MMC Specification Version 3.31
-         */
-        dev = qdev_new(TYPE_SYSBUS_SDHCI);
-        qdev_prop_set_uint8(dev, "sd-spec-version", 2);
-        qdev_prop_set_uint64(dev, "capareg", ZYNQ_SDHCI_CAPABILITIES);
-        sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, hci_addr);
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[hci_irq - IRQ_OFFSET]);
-
-        di = drive_get(IF_SD, 0, n);
-        blk = di ? blk_by_legacy_dinfo(di) : NULL;
-        carddev = qdev_new(TYPE_SD_CARD);
-        qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
-        qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"),
-                               &error_fatal);
-    }
+    di = drive_get(IF_SD, 0, 0);
+    blk = di ? blk_by_legacy_dinfo(di) : NULL;
+    carddev = qdev_new(TYPE_SD_CARD);
+    qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
+    qdev_realize_and_unref(carddev, qdev_get_child_bus(dev, "sd-bus"),
+                       &error_fatal);
 
     dev = qdev_new(TYPE_ZYNQ_XADC);
     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 14/21] hw/arm/beckhoff_CX7200: Remove second GEM
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (12 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 13/21] hw/arm/beckhoff_CX7200: Remove second SD controller Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-03-18 13:08 ` [PATCH 15/21] hw/arm/beckhoff_CX7200: Adjust Flashes and Busses Corvin Köhne
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel, Corvin Köhne, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

The CX7200 has one Gigabit Ethernet MAC connected to address
0xE000C000. The one connected to address 0xE000B000 can be
removed.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/arm/beckhoff_CX7200.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/hw/arm/beckhoff_CX7200.c b/hw/arm/beckhoff_CX7200.c
index bf3c66e5a4..3ceccaa9e6 100644
--- a/hw/arm/beckhoff_CX7200.c
+++ b/hw/arm/beckhoff_CX7200.c
@@ -317,7 +317,6 @@ static void beckhoff_cx7200_init(MachineState *machine)
     sysbus_create_varargs("cadence_ttc", 0xF8002000, pic[69 - IRQ_OFFSET],
                           pic[70 - IRQ_OFFSET], pic[71 - IRQ_OFFSET], NULL);
 
-    gem_init(0xE000B000, pic[54 - IRQ_OFFSET]);
     gem_init(0xE000C000, pic[77 - IRQ_OFFSET]);
 
     /*
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 15/21] hw/arm/beckhoff_CX7200: Adjust Flashes and Busses
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (13 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 14/21] hw/arm/beckhoff_CX7200: Remove second GEM Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-03-18 13:08 ` [PATCH 16/21] hw/arm/beckhoff_CX7200: Remove usb interfaces Corvin Köhne
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel, Corvin Köhne, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

The CX7200 has one QSPI flash connected to the QSPI bus. The
defines are adjusted accordingly. The QSPI flash is a is25lp016d.
There is no parallel flash.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/arm/beckhoff_CX7200.c | 20 ++++----------------
 1 file changed, 4 insertions(+), 16 deletions(-)

diff --git a/hw/arm/beckhoff_CX7200.c b/hw/arm/beckhoff_CX7200.c
index 3ceccaa9e6..1e7152e871 100644
--- a/hw/arm/beckhoff_CX7200.c
+++ b/hw/arm/beckhoff_CX7200.c
@@ -48,12 +48,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(CX7200MachineState, CX7200_MACHINE)
 /* board base frequency: 33.333333 MHz */
 #define PS_CLK_FREQUENCY (100 * 1000 * 1000 / 3)
 
-#define NUM_SPI_FLASHES 4
-#define NUM_QSPI_FLASHES 2
-#define NUM_QSPI_BUSSES 2
-
-#define FLASH_SIZE (64 * 1024 * 1024)
-#define FLASH_SECTOR_SIZE (128 * 1024)
+#define NUM_SPI_FLASHES 0
+#define NUM_QSPI_FLASHES 1
+#define NUM_QSPI_BUSSES 1
 
 #define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
 
@@ -164,7 +161,7 @@ static inline int beckhoff_cx7200_init_spi_flashes(uint32_t base_addr,
 
         for (j = 0; j < num_ss; ++j) {
             DriveInfo *dinfo = drive_get(IF_MTD, 0, unit++);
-            flash_dev = qdev_new("n25q128");
+            flash_dev = qdev_new("is25lp016d");
             if (dinfo) {
                 qdev_prop_set_drive_err(flash_dev, "drive",
                                         blk_by_legacy_dinfo(dinfo),
@@ -242,15 +239,6 @@ static void beckhoff_cx7200_init(MachineState *machine)
                            &error_fatal);
     memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram);
 
-    DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
-
-    /* AMD */
-    pflash_cfi02_register(0xe2000000, "zynq.pflash", FLASH_SIZE,
-                          dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
-                          FLASH_SECTOR_SIZE, 1,
-                          1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa,
-                          0);
-
     /* Create the main clock source, and feed slcr with it */
     cx7200_machine->ps_clk = CLOCK(object_new(TYPE_CLOCK));
     object_property_add_child(OBJECT(cx7200_machine), "ps_clk",
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 16/21] hw/arm/beckhoff_CX7200: Remove usb interfaces
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (14 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 15/21] hw/arm/beckhoff_CX7200: Adjust Flashes and Busses Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-03-18 13:08 ` [PATCH 17/21] hw/arm/beckhoff_CX7200: Remove unimplemented devices Corvin Köhne
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel, Corvin Köhne, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

The CX7200 does not support usb interfaces. That is why they
are removed.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/arm/Kconfig           | 1 -
 hw/arm/beckhoff_CX7200.c | 4 ----
 2 files changed, 5 deletions(-)

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 8727b3e837..a8648b9edf 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -322,7 +322,6 @@ config BECK_CX7200
     select PL330
     select SDHCI
     select SSI_M25P80
-    select USB_EHCI_SYSBUS
     select XILINX # UART
     select XILINX_AXI
     select XILINX_SPI
diff --git a/hw/arm/beckhoff_CX7200.c b/hw/arm/beckhoff_CX7200.c
index 1e7152e871..efce3be395 100644
--- a/hw/arm/beckhoff_CX7200.c
+++ b/hw/arm/beckhoff_CX7200.c
@@ -28,7 +28,6 @@
 #include "hw/loader.h"
 #include "hw/adc/zynq-xadc.h"
 #include "hw/ssi/ssi.h"
-#include "hw/usb/chipidea.h"
 #include "qemu/error-report.h"
 #include "hw/sd/sdhci.h"
 #include "hw/char/cadence_uart.h"
@@ -280,9 +279,6 @@ static void beckhoff_cx7200_init(MachineState *machine)
     n = beckhoff_cx7200_init_spi_flashes(0xE000D000, pic[51 - IRQ_OFFSET],
                                          true, n);
 
-    sysbus_create_simple(TYPE_CHIPIDEA, 0xE0002000, pic[53 - IRQ_OFFSET]);
-    sysbus_create_simple(TYPE_CHIPIDEA, 0xE0003000, pic[76 - IRQ_OFFSET]);
-
     dev = qdev_new(TYPE_CADENCE_UART);
     busdev = SYS_BUS_DEVICE(dev);
     qdev_prop_set_chr(dev, "chardev", serial_hd(0));
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 17/21] hw/arm/beckhoff_CX7200: Remove unimplemented devices
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (15 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 16/21] hw/arm/beckhoff_CX7200: Remove usb interfaces Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-03-18 13:08 ` [PATCH 18/21] hw/arm/beckhoff_CX7200: Set CPU frequency and PERIPHCLK period Corvin Köhne
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel, Corvin Köhne, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

Some unimplemented devices do not exist for the CX7200. All
unimplemented devices have been removed for better overview
and the fact that they are not necessary for a CX7200 emulation.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/arm/beckhoff_CX7200.c | 69 ----------------------------------------
 1 file changed, 69 deletions(-)

diff --git a/hw/arm/beckhoff_CX7200.c b/hw/arm/beckhoff_CX7200.c
index efce3be395..a3f4045560 100644
--- a/hw/arm/beckhoff_CX7200.c
+++ b/hw/arm/beckhoff_CX7200.c
@@ -357,75 +357,6 @@ static void beckhoff_cx7200_init(MachineState *machine)
     sysbus_connect_irq(busdev, 0, pic[40 - IRQ_OFFSET]);
     sysbus_mmio_map(busdev, 0, 0xF8007000);
 
-    /*
-     * Refer to the ug585-Zynq-7000-TRM manual B.3 (Module Summary) and
-     * the zynq-7000.dtsi. Add placeholders for unimplemented devices.
-     */
-    create_unimplemented_device("zynq.i2c0", 0xE0004000, 4 * KiB);
-    create_unimplemented_device("zynq.i2c1", 0xE0005000, 4 * KiB);
-    create_unimplemented_device("zynq.can0", 0xE0008000, 4 * KiB);
-    create_unimplemented_device("zynq.can1", 0xE0009000, 4 * KiB);
-    create_unimplemented_device("zynq.gpio", 0xE000A000, 4 * KiB);
-    create_unimplemented_device("zynq.smcc", 0xE000E000, 4 * KiB);
-
-    /* Direct Memory Access Controller, PL330, Non-Secure Mode */
-    create_unimplemented_device("zynq.dma_ns", 0xF8004000, 4 * KiB);
-
-    /* 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);
-    create_unimplemented_device("zynq.axi_hp2", 0xF800A000, 0x28);
-    create_unimplemented_device("zynq.axi_hp3", 0xF800B000, 0x28);
-
-    create_unimplemented_device("zynq.efuse", 0xF800d000, 0x20);
-
-    /* Embedded Trace Buffer */
-    create_unimplemented_device("zynq.etb", 0xF8801000, 4 * KiB);
-
-    /* Cross Trigger Interface, ETB and TPIU */
-    create_unimplemented_device("zynq.cti_etb_tpiu", 0xF8802000, 4 * KiB);
-
-    /* Trace Port Interface Unit */
-    create_unimplemented_device("zynq.tpiu", 0xF8803000, 4 * KiB);
-
-    /* CoreSight Trace Funnel */
-    create_unimplemented_device("zynq.funnel", 0xF8804000, 4 * KiB);
-
-    /* Instrumentation Trace Macrocell */
-    create_unimplemented_device("zynq.itm", 0xF8805000, 4 * KiB);
-
-    /* Cross Trigger Interface, FTM */
-    create_unimplemented_device("zynq.cti_ftm", 0xF8809000, 4 * KiB);
-
-    /* Fabric Trace Macrocell */
-    create_unimplemented_device("zynq.ftm", 0xF880B000, 4 * KiB);
-
-    /* Cortex A9 Performance Monitoring Unit, CPU */
-    create_unimplemented_device("cortex-a9.pmu0", 0xF8891000, 4 * KiB);
-    create_unimplemented_device("cortex-a9.pmu1", 0xF8893000, 4 * KiB);
-
-    /* Cross Trigger Interface, CPU */
-    create_unimplemented_device("zynq.cpu_cti0", 0xF8898000, 4 * KiB);
-    create_unimplemented_device("zynq.cpu_cti1", 0xF8899000, 4 * KiB);
-
-    /* CoreSight PTM-A9, CPU */
-    create_unimplemented_device("cortex-a9.ptm0", 0xF889c000, 4 * KiB);
-    create_unimplemented_device("cortex-a9.ptm1", 0xF889d000, 4 * KiB);
-
-    /* AMBA NIC301 TrustZone */
-    create_unimplemented_device("zynq.trustZone", 0xF8900000, 0x20);
-
-    /* AMBA Network Interconnect Advanced Quality of Service (QoS-301) */
-    create_unimplemented_device("zynq.qos301_cpu", 0xF8946000, 0x130);
-    create_unimplemented_device("zynq.qos301_dmac", 0xF8947000, 0x130);
-    create_unimplemented_device("zynq.qos301_iou", 0xF8948000, 0x130);
-
     beckhoff_cx7200_binfo.ram_size = machine->ram_size;
     beckhoff_cx7200_binfo.board_id = 0xd32;
     beckhoff_cx7200_binfo.loader_start = 0;
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 18/21] hw/arm/beckhoff_CX7200: Set CPU frequency and PERIPHCLK period
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (16 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 17/21] hw/arm/beckhoff_CX7200: Remove unimplemented devices Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-03-18 13:08 ` [PATCH 19/21] hw/arm/beckhoff_CX7200: Add CCAT to CX7200 Corvin Köhne
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel, Corvin Köhne, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

The CPU frequency for the CX7200 is set to 720 MHz, with the
peripheral clock running at half of the CPU frequency. That
is why the PERIPHCLK_PERIOD is set to two. These values are
forwarded to the A9 global timer, watchdog timer and MP Timer.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/arm/beckhoff_CX7200.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/hw/arm/beckhoff_CX7200.c b/hw/arm/beckhoff_CX7200.c
index a3f4045560..0f99cbf554 100644
--- a/hw/arm/beckhoff_CX7200.c
+++ b/hw/arm/beckhoff_CX7200.c
@@ -47,6 +47,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(CX7200MachineState, CX7200_MACHINE)
 /* board base frequency: 33.333333 MHz */
 #define PS_CLK_FREQUENCY (100 * 1000 * 1000 / 3)
 
+#define PERIPHCLK_PERIOD 2
+#define PS7_CPU_CLK_FREQUENCY 720000000
+
 #define NUM_SPI_FLASHES 0
 #define NUM_QSPI_FLASHES 1
 #define NUM_QSPI_BUSSES 1
@@ -254,6 +257,13 @@ static void beckhoff_cx7200_init(MachineState *machine)
 
     dev = qdev_new(TYPE_A9MPCORE_PRIV);
     qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+    A9MPPrivState *a9mp_priv_state = A9MPCORE_PRIV(dev);
+    a9mp_priv_state->gtimer.cpu_clk_freq_hz = PS7_CPU_CLK_FREQUENCY;
+    a9mp_priv_state->gtimer.periphclk_period = PERIPHCLK_PERIOD;
+    a9mp_priv_state->mptimer.clk_freq_hz = PS7_CPU_CLK_FREQUENCY;
+    a9mp_priv_state->mptimer.periphclk_period = PERIPHCLK_PERIOD;
+    a9mp_priv_state->wdt.clk_freq_hz = PS7_CPU_CLK_FREQUENCY;
+    a9mp_priv_state->wdt.periphclk_period = PERIPHCLK_PERIOD;
     busdev = SYS_BUS_DEVICE(dev);
     sysbus_realize_and_unref(busdev, &error_fatal);
     sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 19/21] hw/arm/beckhoff_CX7200: Add CCAT to CX7200
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (17 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 18/21] hw/arm/beckhoff_CX7200: Set CPU frequency and PERIPHCLK period Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-03-18 13:08 ` [PATCH 20/21] hw/arm/beckhoff_CX7200: Add dummy DDR CTRL " Corvin Köhne
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel, Corvin Köhne, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

The Beckhoff CX7200 is based on the Xilinx Zynq-7000 SoC.
It integrates the Beckhoff Communication Controller (CCAT),
which is implemented as an FPGA within the Zynq's programmable
logic (PL).

This commit adds the CCAT as an MMIO device to the CX7200
machine in QEMU, enabling its emulation and interaction with
the system.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/arm/Kconfig           |  1 +
 hw/arm/beckhoff_CX7200.c | 13 +++++++++++++
 2 files changed, 14 insertions(+)

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index a8648b9edf..782da4c22a 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -327,6 +327,7 @@ config BECK_CX7200
     select XILINX_SPI
     select XILINX_SPIPS
     select ZYNQ_DEVCFG
+    select BECKHOFF_CCAT
 
 config ARM_V7M
     bool
diff --git a/hw/arm/beckhoff_CX7200.c b/hw/arm/beckhoff_CX7200.c
index 0f99cbf554..0fe03f570f 100644
--- a/hw/arm/beckhoff_CX7200.c
+++ b/hw/arm/beckhoff_CX7200.c
@@ -130,6 +130,17 @@ static void gem_init(uint32_t base, qemu_irq irq)
     sysbus_connect_irq(s, 0, irq);
 }
 
+static void ccat_init(uint32_t base)
+{
+    DeviceState *dev;
+    SysBusDevice *busdev;
+
+    dev = qdev_new("beckhoff-ccat");
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_realize_and_unref(busdev, &error_fatal);
+    sysbus_mmio_map(busdev, 0, base);
+}
+
 static inline int beckhoff_cx7200_init_spi_flashes(uint32_t base_addr,
                                         qemu_irq irq, bool is_qspi, int unit0)
 {
@@ -313,6 +324,8 @@ static void beckhoff_cx7200_init(MachineState *machine)
 
     gem_init(0xE000C000, pic[77 - IRQ_OFFSET]);
 
+    ccat_init(0x40000000);
+
     /*
      * Compatible with:
      * - SD Host Controller Specification Version 2.0 Part A2
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 20/21] hw/arm/beckhoff_CX7200: Add dummy DDR CTRL to CX7200
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (18 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 19/21] hw/arm/beckhoff_CX7200: Add CCAT to CX7200 Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-03-18 13:08 ` [PATCH 21/21] MAINTAINERS: add myself as reviewer for Beckhoff devices Corvin Köhne
  2025-04-24 10:48 ` [PATCH 00/21] hw/arm: add CX7200 board emulation Corvin Köhne
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel, Corvin Köhne, qemu-arm
  Cc: Yannick Voßen, Edgar E. Iglesias, Peter Maydell,
	Alistair Francis, Paolo Bonzini, YannickV

From: YannickV <Y.Vossen@beckhoff.com>

The CX7200 polls for statusregisters in the DDR Controller.
To avaid endless polling loops, a dummy DDR Controller is
added.

Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
---
 hw/arm/beckhoff_CX7200.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/hw/arm/beckhoff_CX7200.c b/hw/arm/beckhoff_CX7200.c
index 0fe03f570f..8c1379aab4 100644
--- a/hw/arm/beckhoff_CX7200.c
+++ b/hw/arm/beckhoff_CX7200.c
@@ -141,6 +141,17 @@ static void ccat_init(uint32_t base)
     sysbus_mmio_map(busdev, 0, base);
 }
 
+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 inline int beckhoff_cx7200_init_spi_flashes(uint32_t base_addr,
                                         qemu_irq irq, bool is_qspi, int unit0)
 {
@@ -326,6 +337,8 @@ static void beckhoff_cx7200_init(MachineState *machine)
 
     ccat_init(0x40000000);
 
+    ddr_ctrl_init(0xF8006000);
+
     /*
      * Compatible with:
      * - SD Host Controller Specification Version 2.0 Part A2
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 21/21] MAINTAINERS: add myself as reviewer for Beckhoff devices
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (19 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 20/21] hw/arm/beckhoff_CX7200: Add dummy DDR CTRL " Corvin Köhne
@ 2025-03-18 13:08 ` Corvin Köhne
  2025-04-24 10:48 ` [PATCH 00/21] hw/arm: add CX7200 board emulation Corvin Köhne
  21 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-03-18 13:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Yannick Voßen, Edgar E. Iglesias, qemu-arm, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini

From: Corvin Köhne <c.koehne@beckhoff.com>

I don't have commit privileges, so I can't merge any changes. However, someone
from Beckhoff should review changes made to their board emulations.

Signed-off-by: Corvin Köhne <c.koehne@beckhoff.com>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 8f470a1c9b..88d1d51e2a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -720,6 +720,13 @@ F: hw/arm/b-l475e-iot01a.c
 F: hw/display/dm163.c
 F: tests/qtest/dm163-test.c
 
+Beckhoff CX7200
+R: Corvin Köhne <c.koehne@beckhoff.com>
+L: qemu-arm@nongnu.org
+S: Supported
+F: hw/arm/beckhoff_CX7200.c
+F: hw/misc/beckhoff_ccat.c
+
 Exynos
 M: Igor Mitsyanko <i.mitsyanko@gmail.com>
 M: Peter Maydell <peter.maydell@linaro.org>
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH 00/21] hw/arm: add CX7200 board emulation
  2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
                   ` (20 preceding siblings ...)
  2025-03-18 13:08 ` [PATCH 21/21] MAINTAINERS: add myself as reviewer for Beckhoff devices Corvin Köhne
@ 2025-04-24 10:48 ` Corvin Köhne
  2025-04-25 19:59   ` Edgar E. Iglesias
  21 siblings, 1 reply; 36+ messages in thread
From: Corvin Köhne @ 2025-04-24 10:48 UTC (permalink / raw)
  To: qemu-devel@nongnu.org, qemu-arm@nongnu.org
  Cc: Yannick Voßen, peter.maydell@linaro.org, pbonzini@redhat.com,
	alistair@alistair23.me, edgar.iglesias@gmail.com

[-- Attachment #1: Type: text/plain, Size: 3714 bytes --]

On Tue, 2025-03-18 at 14:07 +0100, Corvin Köhne wrote:
> CAUTION: External Email!!
> From: Corvin Köhne <c.koehne@beckhoff.com>
> 
> Beckhoff has build a board, called CX7200, based on the Xilinx Zynq A9
> platform. This commit series adds the Beckhoff CX7200 as new board variant to
> QEMU.
> 
> The emulation is able to successfully boot an CX7200 image. The image includes
> some self tests executed on every boot. Only the cache self test fails due to
> QEMU emulating the cache as always being coherent. The self tests include
> f.e.:
> 
> * Network
> * Flash
> * CCAT DMA + EEPROM [1]
> * TwinCAT (Beckhoff's automation control software [2])
> 
> [1] https://github.com/beckhoff/ccat
> [2] https://www.beckhoff.com/en-us/products/automation/
> 
> Corvin Köhne (1):
>   MAINTAINERS: add myself as reviewer for Beckhoff devices
> 
> YannickV (20):
>   hw/timer: Make frequency configurable
>   hw/timer: Make PERIPHCLK period configurable
>   hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff
>   hw/arm/zynq-devcfg: Prevent unintended unlock during initialization
>   hw/dma/zynq: Notify devcfg on FPGA reset via SLCR control
>   hw/dma/zynq-devcfg: Simulate dummy PL reset
>   hw/dma/zynq-devcfg: Indicate power-up status of PL
>   hw/dma/zynq-devcfg: Fix register memory
>   hw/misc: Add dummy ZYNQ DDR controller
>   hw/misc/zynq_slcr: Add logic for DCI configuration
>   hw/misc: Add Beckhoff CCAT device
>   hw/arm: Add new machine based on xilinx-zynq-a9 for Beckhoff CX7200
>   hw/arm/beckhoff_CX7200: Remove second SD controller
>   hw/arm/beckhoff_CX7200: Remove second GEM
>   hw/arm/beckhoff_CX7200: Adjust Flashes and Busses
>   hw/arm/beckhoff_CX7200: Remove usb interfaces
>   hw/arm/beckhoff_CX7200: Remove unimplemented devices
>   hw/arm/beckhoff_CX7200: Set CPU frequency and PERIPHCLK period
>   hw/arm/beckhoff_CX7200: Add CCAT to CX7200
>   hw/arm/beckhoff_CX7200: Add dummy DDR CTRL to CX7200
> 
>  MAINTAINERS                       |   7 +
>  hw/arm/Kconfig                    |  18 ++
>  hw/arm/beckhoff_CX7200.c          | 440 ++++++++++++++++++++++++++++++
>  hw/arm/
> https://nospamproxywebp.beckhoff.com/enQsig/link?id=BAgAAACF1PqAcgZXNGoAAACSdE
> 7DUYKKiipqQsJl32BC_vIVe3kQ23Cr-DKSrQn5Y_I0ZnsAu8qZHVUsGVmYwKL0amQboD-LYv9rWN-
> mvEPUf2y-CZ1qrggzKI9xgbKnOi8XSPZVd2G0Lro-8fGR9tAuNB-3CWjEaKli0                
> |   1 +
>  hw/dma/xlnx-zynq-devcfg.c         |  36 ++-
>  hw/misc/Kconfig                   |   6 +
>  hw/misc/beckhoff_ccat.c           | 365 +++++++++++++++++++++++++
>  hw/misc/
> https://nospamproxywebp.beckhoff.com/enQsig/link?id=BAgAAACF1PqAcgZXNGoAAACSdE
> 7DUYKKiipqQsJl32BC_vIVe3kQ23Cr-DKSrQn5Y_I0ZnsAu8qZHVUsGVmYwKL0amQboD-LYv9rWN-
> mvEPUf2y-CZ1qrggzKI9xgbKnOi8XSPZVd2G0Lro-8fGR9tAuNB-3CWjEaKli0               
> |   2 +
>  hw/misc/zynq_ddr-ctrl.c           | 331 ++++++++++++++++++++++
>  hw/misc/zynq_slcr.c               |  47 ++++
>  hw/timer/a9gtimer.c               |  25 +-
>  hw/timer/arm_mptimer.c            |  33 ++-
>  include/hw/dma/xlnx-zynq-devcfg.h |   3 +
>  include/hw/timer/a9gtimer.h       |   2 +
>  include/hw/timer/arm_mptimer.h    |   4 +
>  15 files changed, 1309 insertions(+), 11 deletions(-)
>  create mode 100644 hw/arm/beckhoff_CX7200.c
>  create mode 100644 hw/misc/beckhoff_ccat.c
>  create mode 100644 hw/misc/zynq_ddr-ctrl.c

Hi,

any feedback for those commits?


-- 
Kind regards,
Corvin

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 03/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff
  2025-03-18 13:07 ` [PATCH 03/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff Corvin Köhne
@ 2025-04-25 15:47   ` Edgar E. Iglesias
  0 siblings, 0 replies; 36+ messages in thread
From: Edgar E. Iglesias @ 2025-04-25 15:47 UTC (permalink / raw)
  To: Corvin Köhne
  Cc: qemu-devel, qemu-arm, Yannick Voßen, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini

On Tue, Mar 18, 2025 at 02:07:54PM +0100, Corvin Köhne wrote:
> 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.

Thanks, LGTM:
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>



> 
> Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
> ---
>  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 0fd0d23f57..b838c1c0d0 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.49.0
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 04/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization
  2025-03-18 13:07 ` [PATCH 04/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization Corvin Köhne
@ 2025-04-25 15:52   ` Edgar E. Iglesias
  0 siblings, 0 replies; 36+ messages in thread
From: Edgar E. Iglesias @ 2025-04-25 15:52 UTC (permalink / raw)
  To: Corvin Köhne
  Cc: qemu-devel, qemu-arm, Yannick Voßen, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini

On Tue, Mar 18, 2025 at 02:07:55PM +0100, Corvin Köhne wrote:
> 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.
> 
> To address this, a property 'is_initialized' is introduced. It is set
> to false during reset and updated to true once the initialization is
> complete. The unlock function is simply ignored while 'is_initialized'
> is false.
> 
> I have no idea how this ever worked. Nevertheless, this restores the
> correct behavior.
> 
> Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
> ---
>  hw/dma/xlnx-zynq-devcfg.c         | 6 +++++-
>  include/hw/dma/xlnx-zynq-devcfg.h | 2 ++
>  2 files changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
> index b838c1c0d0..03b5280228 100644
> --- a/hw/dma/xlnx-zynq-devcfg.c
> +++ b/hw/dma/xlnx-zynq-devcfg.c
> @@ -143,9 +143,11 @@ static void xlnx_zynq_devcfg_reset(DeviceState *dev)
>      XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(dev);
>      int i;
>  
> +    s->is_initialized = false;
>      for (i = 0; i < XLNX_ZYNQ_DEVCFG_R_MAX; ++i) {
>          register_reset(&s->regs_info[i]);
>      }
> +    s->is_initialized = true;
>  }
>  
>  static void xlnx_zynq_devcfg_dma_go(XlnxZynqDevcfg *s)
> @@ -221,7 +223,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 (!s->is_initialized) {


I think you can use device_is_in_reset(DEVICE(s))
and get rid of is_initialized alltogether?




> +        return;
> +    }
>      if (val == R_UNLOCK_MAGIC) {
>          DB_PRINT("successful unlock\n");
>          s->regs[R_CTRL] |= R_CTRL_PCAP_PR_MASK;
> diff --git a/include/hw/dma/xlnx-zynq-devcfg.h b/include/hw/dma/xlnx-zynq-devcfg.h
> index e4cf085d70..2ab054e598 100644
> --- a/include/hw/dma/xlnx-zynq-devcfg.h
> +++ b/include/hw/dma/xlnx-zynq-devcfg.h
> @@ -55,6 +55,8 @@ struct XlnxZynqDevcfg {
>      XlnxZynqDevcfgDMACmd dma_cmd_fifo[XLNX_ZYNQ_DEVCFG_DMA_CMD_FIFO_LEN];
>      uint8_t dma_cmd_fifo_num;
>  
> +    bool is_initialized;
> +
>      uint32_t regs[XLNX_ZYNQ_DEVCFG_R_MAX];
>      RegisterInfo regs_info[XLNX_ZYNQ_DEVCFG_R_MAX];
>  };
> -- 
> 2.49.0
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 05/21] hw/dma/zynq: Notify devcfg on FPGA reset via SLCR control
  2025-03-18 13:07 ` [PATCH 05/21] hw/dma/zynq: Notify devcfg on FPGA reset via SLCR control Corvin Köhne
@ 2025-04-25 16:11   ` Edgar E. Iglesias
  2025-05-13  7:04     ` Corvin Köhne
  0 siblings, 1 reply; 36+ messages in thread
From: Edgar E. Iglesias @ 2025-04-25 16:11 UTC (permalink / raw)
  To: Corvin Köhne
  Cc: qemu-devel, qemu-arm, Yannick Voßen, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini

On Tue, Mar 18, 2025 at 02:07:56PM +0100, Corvin Köhne wrote:
> From: YannickV <Y.Vossen@beckhoff.com>
> 
> When the FPGA_RST_CTRL register in the SLCR (System Level Control
> Register) is written to, the devcfg (Device Configuration) should
> indicate the finished reset.
> 
> Problems occure when Loaders trigger a reset via SLCR and poll for
> the done flag in devcfg. Since the flag will never be set, this can
> result in an endless loop.
> 
> A callback function `slcr_reset_handler` is added to the
> `XlnxZynqDevcfg` structure. The `slcr_reset` function sets the
> `PCFG_DONE` flag when triggered by an FPGA reset in the SLCR.
> The SLCR write handler calls the `slcr_reset` function when the
> FPGA reset control register (`R_FPGA_RST_CTRL`) is written with
> the reset value.

Could you please refer to the specs where this is described?
I couldn't find it...



> 
> Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
> ---
>  hw/dma/xlnx-zynq-devcfg.c         |  7 +++++++
>  hw/misc/zynq_slcr.c               | 16 ++++++++++++++++
>  include/hw/dma/xlnx-zynq-devcfg.h |  1 +
>  3 files changed, 24 insertions(+)
> 
> diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
> index 03b5280228..611a57b4d4 100644
> --- a/hw/dma/xlnx-zynq-devcfg.c
> +++ b/hw/dma/xlnx-zynq-devcfg.c
> @@ -138,6 +138,11 @@ static void xlnx_zynq_devcfg_update_ixr(XlnxZynqDevcfg *s)
>      qemu_set_irq(s->irq, ~s->regs[R_INT_MASK] & s->regs[R_INT_STS]);
>  }
>  
> +static void slcr_reset (DeviceState *dev) {
> +    XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(dev);
> +    s->regs[R_INT_STS] |= R_INT_STS_PCFG_DONE_MASK;
> +}
> +
>  static void xlnx_zynq_devcfg_reset(DeviceState *dev)
>  {
>      XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(dev);
> @@ -374,6 +379,8 @@ static void xlnx_zynq_devcfg_init(Object *obj)
>      XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(obj);
>      RegisterInfoArray *reg_array;
>  
> +    s->slcr_reset_handler = slcr_reset;
> +
>      sysbus_init_irq(sbd, &s->irq);
>  
>      memory_region_init(&s->iomem, obj, "devcfg", XLNX_ZYNQ_DEVCFG_R_MAX * 4);
> diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
> index a766bab182..9b3220f354 100644
> --- a/hw/misc/zynq_slcr.c
> +++ b/hw/misc/zynq_slcr.c
> @@ -26,6 +26,7 @@
>  #include "qom/object.h"
>  #include "hw/qdev-properties.h"
>  #include "qapi/error.h"
> +#include "hw/dma/xlnx-zynq-devcfg.h"
>  
>  #ifndef ZYNQ_SLCR_ERR_DEBUG
>  #define ZYNQ_SLCR_ERR_DEBUG 0
> @@ -576,6 +577,21 @@ static void zynq_slcr_write(void *opaque, hwaddr offset,
>          zynq_slcr_compute_clocks(s);
>          zynq_slcr_propagate_clocks(s);
>          break;
> +    case R_FPGA_RST_CTRL:
> +        if (val == 0) {
> +            Object *devcfgObject =
> +                    object_resolve_type_unambiguous("xlnx.ps7-dev-cfg", NULL);
> +            if (!devcfgObject) {
> +                break;
> +            }
> +            DeviceState *devcfg = OBJECT_CHECK(DeviceState, devcfgObject,
> +                                               "xlnx.ps7-dev-cfg");
> +            XlnxZynqDevcfg *zynqdevcfg = XLNX_ZYNQ_DEVCFG(devcfg);
> +            if (zynqdevcfg) {
> +                zynqdevcfg->slcr_reset_handler(devcfg);
> +            }
> +        }
> +        break;
>      }
>  }
>  
> diff --git a/include/hw/dma/xlnx-zynq-devcfg.h b/include/hw/dma/xlnx-zynq-devcfg.h
> index 2ab054e598..f48a630c5a 100644
> --- a/include/hw/dma/xlnx-zynq-devcfg.h
> +++ b/include/hw/dma/xlnx-zynq-devcfg.h
> @@ -56,6 +56,7 @@ struct XlnxZynqDevcfg {
>      uint8_t dma_cmd_fifo_num;
>  
>      bool is_initialized;
> +    void (*slcr_reset_handler) (DeviceState *dev);
>  
>      uint32_t regs[XLNX_ZYNQ_DEVCFG_R_MAX];
>      RegisterInfo regs_info[XLNX_ZYNQ_DEVCFG_R_MAX];
> -- 
> 2.49.0
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 06/21] hw/dma/zynq-devcfg: Simulate dummy PL reset
  2025-03-18 13:07 ` [PATCH 06/21] hw/dma/zynq-devcfg: Simulate dummy PL reset Corvin Köhne
@ 2025-04-25 16:20   ` Edgar E. Iglesias
  0 siblings, 0 replies; 36+ messages in thread
From: Edgar E. Iglesias @ 2025-04-25 16:20 UTC (permalink / raw)
  To: Corvin Köhne
  Cc: qemu-devel, qemu-arm, Yannick Voßen, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini

On Tue, Mar 18, 2025 at 02:07:57PM +0100, Corvin Köhne wrote:
> 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: Yannick Voßen <y.vossen@beckhoff.com>
> ---
>  hw/dma/xlnx-zynq-devcfg.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
> index 611a57b4d4..c44b802b22 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)
> @@ -209,6 +211,14 @@ static uint64_t r_ctrl_pre_write(RegisterInfo *reg, uint64_t val)
>              val |= lock_ctrl_map[i] & s->regs[R_CTRL];
>          }
>      }
> +
> +    uint32_t pcfg_prog_b = FIELD_EX32(val, CTRL, PCFG_PROG_B);

The declaration of pcfg_prog_b shouldn't be in the middle of a block.
Since PCFG_PROG_B is a single bit, better to use bool.
Or just skip the variable all together and do:

    if (FIELD_EX32(val, CTRL, PCFG_PROG_B)) {



> +    if (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.49.0
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 07/21] hw/dma/zynq-devcfg: Indicate power-up status of PL
  2025-03-18 13:07 ` [PATCH 07/21] hw/dma/zynq-devcfg: Indicate power-up status of PL Corvin Köhne
@ 2025-04-25 16:24   ` Edgar E. Iglesias
  0 siblings, 0 replies; 36+ messages in thread
From: Edgar E. Iglesias @ 2025-04-25 16:24 UTC (permalink / raw)
  To: Corvin Köhne
  Cc: qemu-devel, qemu-arm, Yannick Voßen, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini

On Tue, Mar 18, 2025 at 02:07:58PM +0100, Corvin Köhne wrote:
> 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.
> 
> This commit is necessary for the Beckhoff CX7200 board emulation
> that has a FPGA implemented in the PL.
> 
> Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>
> ---
>  hw/dma/xlnx-zynq-devcfg.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
> index c44b802b22..c595d090fa 100644
> --- a/hw/dma/xlnx-zynq-devcfg.c
> +++ b/hw/dma/xlnx-zynq-devcfg.c
> @@ -339,7 +339,7 @@ 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 | 1 << R_MCTRL_PCFG_POR_B_SHIFT | R_MCTRL_QEMU_MASK,

This line is too long, ./scripts/checkpatch will complain.
You can use R_MCTRL_PCFG_POR_B_MASK here instead of the shift.




>         .ro = ~R_MCTRL_INT_PCAP_LPBK_MASK,
>         .rsvd = 0x00f00303,
>      },
> -- 
> 2.49.0
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 08/21] hw/dma/zynq-devcfg: Fix register memory
  2025-03-18 13:07 ` [PATCH 08/21] hw/dma/zynq-devcfg: Fix register memory Corvin Köhne
@ 2025-04-25 16:27   ` Edgar E. Iglesias
  0 siblings, 0 replies; 36+ messages in thread
From: Edgar E. Iglesias @ 2025-04-25 16:27 UTC (permalink / raw)
  To: Corvin Köhne
  Cc: qemu-devel, qemu-arm, Yannick Voßen, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini

On Tue, Mar 18, 2025 at 02:07:59PM +0100, Corvin Köhne wrote:
> From: YannickV <Y.Vossen@beckhoff.com>
> 
> Registers are always 32 bit aligned. R_MAX is not the maximum
> register address, it is the maximum register number. The memory
> size can be determined by 4 * R_MAX.
> 
> Currently every register with an offset bigger than 0x40 will be
> ignored, because the memory size is set wrong. This effects the
> MCTRL register and makes it useless. This commit restores the
> correct behaviour.
> 
> Signed-off-by: Yannick Voßen <y.vossen@beckhoff.com>

Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>


> ---
>  hw/dma/xlnx-zynq-devcfg.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
> index c595d090fa..24461677ef 100644
> --- a/hw/dma/xlnx-zynq-devcfg.c
> +++ b/hw/dma/xlnx-zynq-devcfg.c
> @@ -400,7 +400,7 @@ static void xlnx_zynq_devcfg_init(Object *obj)
>                                s->regs_info, s->regs,
>                                &xlnx_zynq_devcfg_reg_ops,
>                                XLNX_ZYNQ_DEVCFG_ERR_DEBUG,
> -                              XLNX_ZYNQ_DEVCFG_R_MAX);
> +                              XLNX_ZYNQ_DEVCFG_R_MAX * 4);
>      memory_region_add_subregion(&s->iomem,
>                                  A_CTRL,
>                                  &reg_array->mem);
> -- 
> 2.49.0
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 09/21] hw/misc: Add dummy ZYNQ DDR controller
  2025-03-18 13:08 ` [PATCH 09/21] hw/misc: Add dummy ZYNQ DDR controller Corvin Köhne
@ 2025-04-25 16:45   ` Edgar E. Iglesias
  2025-05-05  9:01     ` Corvin Köhne
  0 siblings, 1 reply; 36+ messages in thread
From: Edgar E. Iglesias @ 2025-04-25 16:45 UTC (permalink / raw)
  To: Corvin Köhne
  Cc: qemu-devel, Yannick Voßen, qemu-arm, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini

On Tue, Mar 18, 2025 at 02:08:00PM +0100, Corvin Köhne wrote:
> 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: Yannick Voßen <y.vossen@beckhoff.com>
> ---
>  hw/misc/Kconfig         |   3 +
>  hw/misc/meson.build     |   1 +
>  hw/misc/zynq_ddr-ctrl.c | 331 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 335 insertions(+)
>  create mode 100644 hw/misc/zynq_ddr-ctrl.c
> 
> diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
> index ec0fa5aa9f..1bc4228572 100644
> --- a/hw/misc/Kconfig
> +++ b/hw/misc/Kconfig
> @@ -222,4 +222,7 @@ config IOSB
>  config XLNX_VERSAL_TRNG
>      bool
>  
> +config DDR_CTRLR

I suggest XLNX_ZYNQ_DDRC ?

And name the file accordingly, e.g xlnx-zynq-ddrc.c.

You may also want to consider using the register API, see for example
hw/misc/xlnx-versal-xramc.c, modelling another memory controller.


> +    bool
> +
>  source macio/Kconfig
> diff --git a/hw/misc/meson.build b/hw/misc/meson.build
> index 6d47de482c..8d4c4279c4 100644
> --- a/hw/misc/meson.build
> +++ b/hw/misc/meson.build
> @@ -91,6 +91,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_ZYNQ', if_true: files('zynq_ddr-ctrl.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/zynq_ddr-ctrl.c b/hw/misc/zynq_ddr-ctrl.c
> new file mode 100644
> index 0000000000..8cdf8be743
> --- /dev/null
> +++ b/hw/misc/zynq_ddr-ctrl.c
> @@ -0,0 +1,331 @@
> +#include "qemu/osdep.h"
> +#include "hw/sysbus.h"
> +#include "hw/register.h"
> +#include "qemu/bitops.h"
> +#include "qemu/log.h"
> +#include "qapi/error.h"
> +#include "hw/registerfields.h"
> +#include "system/block-backend.h"
> +#include "exec/address-spaces.h"
> +#include "exec/memory.h"
> +#include "system/dma.h"
> +
> +#ifndef DDRCTRL_ERR_DEBUG
> +#define DDRCTRL_ERR_DEBUG 0
> +#endif
> +
> +#define DB_PRINT_L(level, ...) do { \
> +    if (DDRCTRL_ERR_DEBUG > (level)) { \
> +        fprintf(stderr,  ": %s: ", __func__); \
> +        fprintf(stderr, ## __VA_ARGS__); \
> +    } \
> +} while (0)
> +
> +#define DB_PRINT(...) DB_PRINT_L(0, ## __VA_ARGS__)
> +
> +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_RDDA, 0x50)
> +REG32(TA_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)
> +
> +#define TYPE_DDRCTRL "zynq.ddr-ctlr"
> +#define DDRCTRL(obj) \
> +    OBJECT_CHECK(DDRCTRLState, (obj), TYPE_DDRCTRL)
> +
> +typedef struct DDRCTRLState {
> +    SysBusDevice parent_obj;
> +
> +    MemoryRegion iomem;
> +
> +    uint32_t reg[ZYNQ_DDRCTRL_NUM_REG];
> +} DDRCTRLState;
> +
> +
> +static bool zynq_ddrctrl_check_addr(hwaddr addr, bool rnw)

Since we always return true fore reads, I would suggest removing
the rnw argument, rename the function to check..._write or
moving this logic to zynq_ddrctrl_write().


> +{
> +    switch (addr) {
> +    case R_PHY_DBG_REG:
> +    case R_MODE_STS_REG:
> +    case R_CHE_CORR_ECC_LOG_REG_OFFSET ...
> +                    R_CHE_CORR_ECC_DATA_71_64_REG_OFFSET:
> +    case R_CHE_UNCORR_ECC_ADDR_REG_OFFSET ...
> +                    R_CHE_UNCORR_ECC_DATA_71_64_REG_OFFSET:
> +    case R_CHE_ECC_CORR_BIT_MASK_31_0_REG_OFFSET:
> +    case R_CHE_ECC_CORR_BIT_MASK_63_32_REG_OFFSET:
> +    case R_REG69_6A0 ... R_AXI_ID:
> +    case R_MODE_REG_READ:
> +        return rnw;
> +    default:
> +        return true;
> +    }
> +}
> +
> +static void zynq_ddrctrl_reset_init(Object *obj, ResetType type)
> +{
> +    DDRCTRLState *s = DDRCTRL(obj);
> +
> +    DB_PRINT("RESET");
> +
> +    s->reg[R_DDRC_CTRL]                      = 0x00000200;
> +    s->reg[R_TWO_RANK_CFG]                   = 0x000C1076;
> +    s->reg[R_HPR_REG]                        = 0x03C0780F;
> +    s->reg[R_LPR_REG]                        = 0x03C0780F;
> +    s->reg[R_WR_REG]                         = 0x0007F80F;
> +    s->reg[R_DRAM_PARAM_REG0]                = 0x00041016;
> +    s->reg[R_DRAM_PARAM_REG1]                = 0x351B48D9;
> +    s->reg[R_DRAM_PARAM_REG2]                = 0x83015904;
> +    s->reg[R_DRAM_PARAM_REG3]                = 0x250882D0;
> +    s->reg[R_DRAM_PARAM_REG4]                = 0x0000003C;
> +    s->reg[R_DRAM_INIT_PARAM]                = 0x00002007;
> +    s->reg[R_DRAM_EMR_REG]                   = 0x00000008;
> +    s->reg[R_DRAM_EMR_MR_REG]                = 0x00000940;
> +    s->reg[R_DRAM_BURST8_RDWR]               = 0x00020034;
> +    s->reg[R_DRAM_ADDR_MAP_BANK]             = 0x00000F77;
> +    s->reg[R_DRAM_ADDR_MAP_COL]              = 0xFFF00000;
> +    s->reg[R_DRAM_ADDR_MAP_ROW]              = 0x0FF55555;
> +    s->reg[R_DRAM_ODT_REG]                   = 0x00000249;
> +    s->reg[R_PHY_CMD_TIMEOUT_RDDA]           = 0x00010200;
> +    s->reg[R_DLL_CALIB]                      = 0x00000101;
> +    s->reg[R_ODT_DELAY_HOLD]                 = 0x00000023;
> +    s->reg[R_CTRL_REG1]                      = 0x0000003E;
> +    s->reg[R_CTRL_REG2]                      = 0x00020000;
> +    s->reg[R_CTRL_REG3]                      = 0x00284027;
> +    s->reg[R_CTRL_REG4]                      = 0x00001610;
> +    s->reg[R_CTRL_REG5]                      = 0x00455111;
> +    s->reg[R_CTRL_REG6]                      = 0x00032222;
> +    s->reg[R_CHE_REFRESH_TIMER0]             = 0x00008000;
> +    s->reg[R_CHE_T_ZQ]                       = 0x10300802;
> +    s->reg[R_CHE_T_ZQ_SHORT_INTERVAL_REG]    = 0x0020003A;
> +    s->reg[R_REG_2D]                         = 0x00000200;
> +    s->reg[R_DFI_TIMING]                     = 0x00200067;
> +    s->reg[R_ECC_SCRUB]                      = 0x00000008;
> +    s->reg[R_PHY_CONFIG0]                    = 0x40000001;
> +    s->reg[R_PHY_CONFIG1]                    = 0x40000001;
> +    s->reg[R_PHY_CONFIG2]                    = 0x40000001;
> +    s->reg[R_PHY_CONFIG3]                    = 0x40000001;
> +    s->reg[R_PHY_RD_DQS_CFG0]                = 0x00000040;
> +    s->reg[R_PHY_RD_DQS_CFG1]                = 0x00000040;
> +    s->reg[R_PHY_RD_DQS_CFG2]                = 0x00000040;
> +    s->reg[R_PHY_RD_DQS_CFG3]                = 0x00000040;
> +    s->reg[R_PHY_WE_CFG0]                    = 0x00000040;
> +    s->reg[R_PHY_WE_CFG1]                    = 0x00000040;
> +    s->reg[R_PHY_WE_CFG2]                    = 0x00000040;
> +    s->reg[R_PHY_WE_CFG3]                    = 0x00000040;
> +    s->reg[R_WR_DATA_SLV0]                   = 0x00000080;
> +    s->reg[R_WR_DATA_SLV1]                   = 0x00000080;
> +    s->reg[R_WR_DATA_SLV2]                   = 0x00000080;
> +    s->reg[R_WR_DATA_SLV3]                   = 0x00000080;
> +    s->reg[R_REG_64]                         = 0x10020000;
> +    s->reg[R_AXI_PRIORITY_WR_PORT0]          = 0x000803FF;
> +    s->reg[R_AXI_PRIORITY_WR_PORT1]          = 0x000803FF;
> +    s->reg[R_AXI_PRIORITY_WR_PORT2]          = 0x000803FF;
> +    s->reg[R_AXI_PRIORITY_WR_PORT3]          = 0x000803FF;
> +    s->reg[R_AXI_PRIORITY_RD_PORT0]          = 0x000003FF;
> +    s->reg[R_AXI_PRIORITY_RD_PORT1]          = 0x000003FF;
> +    s->reg[R_AXI_PRIORITY_RD_PORT2]          = 0x000003FF;
> +    s->reg[R_AXI_PRIORITY_RD_PORT3]          = 0x000003FF;
> +    s->reg[R_LPDDR_CTRL2]                    = 0x003C0015;
> +    s->reg[R_LPDDR_CTRL3]                    = 0x00000601;
> +}
> +
> +static uint64_t zynq_ddrctrl_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    DDRCTRLState *s = opaque;
> +    addr /= 4;
> +    uint32_t ret = s->reg[addr];

Declarations at the top.


> +
> +    if (!zynq_ddrctrl_check_addr(addr, true)) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid read access to "
> +                      " addr %" HWADDR_PRIx "\n", addr * 4);
> +        return 0;
> +    }
> +
> +    DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", addr * 4, ret);
> +    return ret;
> +}
> +
> +static void zynq_ddrctrl_write(void *opaque, hwaddr addr, uint64_t val,
> +                               unsigned size)
> +{
> +    DDRCTRLState *s = opaque;
> +    addr /= 4;
> +
> +    if (!zynq_ddrctrl_check_addr(addr, false)) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid read access to "

Invalid write access to....

> +                      " addr %" HWADDR_PRIx "\n", addr * 4);
> +        return;
> +    }
> +
> +    DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx64 "\n", addr * 4, val);
> +
> +    switch (addr) {
> +    case R_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;
> +        }
> +        break;
> +    }
> +
> +    s->reg[addr] = val;
> +}
> +
> +static const MemoryRegionOps ddrctrl_ops = {
> +    .read = zynq_ddrctrl_read,
> +    .write = zynq_ddrctrl_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void zynq_ddrctrl_init(Object *obj)
> +{
> +    DB_PRINT("Init\n");
> +
> +    DDRCTRLState *s = DDRCTRL(obj);

Declarations at the start of a block.


> +
> +    memory_region_init_io(&s->iomem, obj, &ddrctrl_ops, s, "ddrctrl",
> +                          ZYNQ_DDRCTRL_MMIO_SIZE);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
> +}
> +
> +static void zynq_ddrctrl_class_init(ObjectClass *klass, void *data)
> +{
> +    DB_PRINT("Class init\n");
> +
> +    ResettableClass *rc = RESETTABLE_CLASS(klass);

Declarations at the start of a block.


> +
> +    rc->phases.enter = zynq_ddrctrl_reset_init;
> +}
> +
> +static const TypeInfo ddrctrl_info = {
> +    .name = TYPE_DDRCTRL,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(DDRCTRLState),
> +    .class_init = zynq_ddrctrl_class_init,
> +    .instance_init = zynq_ddrctrl_init,
> +};
> +
> +static void ddrctrl_register_types(void)
> +{
> +    type_register_static(&ddrctrl_info);
> +}
> +
> +type_init(ddrctrl_register_types)
> -- 
> 2.49.0
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 10/21] hw/misc/zynq_slcr: Add logic for DCI configuration
  2025-03-18 13:08 ` [PATCH 10/21] hw/misc/zynq_slcr: Add logic for DCI configuration Corvin Köhne
@ 2025-04-25 19:56   ` Edgar E. Iglesias
  0 siblings, 0 replies; 36+ messages in thread
From: Edgar E. Iglesias @ 2025-04-25 19:56 UTC (permalink / raw)
  To: Corvin Köhne
  Cc: qemu-devel, qemu-arm, Yannick Voßen, Peter Maydell,
	Alistair Francis, Corvin Köhne, Paolo Bonzini

On Tue, Mar 18, 2025 at 02:08:01PM +0100, Corvin Köhne wrote:
> 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: Yannick Voßen <y.vossen@beckhoff.com>

LGTM:
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>




> ---
>  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 9b3220f354..10ef8ecee8 100644
> --- a/hw/misc/zynq_slcr.c
> +++ b/hw/misc/zynq_slcr.c
> @@ -181,6 +181,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
> @@ -194,6 +200,8 @@ struct ZynqSLCRState {
>  
>      MemoryRegion iomem;
>  
> +    bool ddriob_dci_ctrl_reset_toggled;
> +
>      uint32_t regs[ZYNQ_SLCR_NUM_REGS];
>  
>      Clock *ps_clk;
> @@ -332,6 +340,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;
> @@ -419,6 +429,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)
> @@ -555,6 +567,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.49.0
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 00/21] hw/arm: add CX7200 board emulation
  2025-04-24 10:48 ` [PATCH 00/21] hw/arm: add CX7200 board emulation Corvin Köhne
@ 2025-04-25 19:59   ` Edgar E. Iglesias
  2025-05-05  8:57     ` Corvin Köhne
  0 siblings, 1 reply; 36+ messages in thread
From: Edgar E. Iglesias @ 2025-04-25 19:59 UTC (permalink / raw)
  To: Corvin Köhne
  Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org, Yannick Voßen,
	peter.maydell@linaro.org, pbonzini@redhat.com,
	alistair@alistair23.me

On Thu, Apr 24, 2025 at 10:48:17AM +0000, Corvin Köhne wrote:
> On Tue, 2025-03-18 at 14:07 +0100, Corvin Köhne wrote:
> > CAUTION: External Email!!
> > From: Corvin Köhne <c.koehne@beckhoff.com>
> > 
> > Beckhoff has build a board, called CX7200, based on the Xilinx Zynq A9
> > platform. This commit series adds the Beckhoff CX7200 as new board variant to
> > QEMU.
> > 
> > The emulation is able to successfully boot an CX7200 image. The image includes
> > some self tests executed on every boot. Only the cache self test fails due to
> > QEMU emulating the cache as always being coherent. The self tests include
> > f.e.:
> > 
> > * Network
> > * Flash
> > * CCAT DMA + EEPROM [1]
> > * TwinCAT (Beckhoff's automation control software [2])
> > 
> > [1] https://github.com/beckhoff/ccat
> > [2] https://www.beckhoff.com/en-us/products/automation/
> > 
> > Corvin Köhne (1):
> >   MAINTAINERS: add myself as reviewer for Beckhoff devices
> > 
> > YannickV (20):
> >   hw/timer: Make frequency configurable
> >   hw/timer: Make PERIPHCLK period configurable
> >   hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff
> >   hw/arm/zynq-devcfg: Prevent unintended unlock during initialization
> >   hw/dma/zynq: Notify devcfg on FPGA reset via SLCR control
> >   hw/dma/zynq-devcfg: Simulate dummy PL reset
> >   hw/dma/zynq-devcfg: Indicate power-up status of PL
> >   hw/dma/zynq-devcfg: Fix register memory
> >   hw/misc: Add dummy ZYNQ DDR controller
> >   hw/misc/zynq_slcr: Add logic for DCI configuration
> >   hw/misc: Add Beckhoff CCAT device
> >   hw/arm: Add new machine based on xilinx-zynq-a9 for Beckhoff CX7200
> >   hw/arm/beckhoff_CX7200: Remove second SD controller
> >   hw/arm/beckhoff_CX7200: Remove second GEM
> >   hw/arm/beckhoff_CX7200: Adjust Flashes and Busses
> >   hw/arm/beckhoff_CX7200: Remove usb interfaces
> >   hw/arm/beckhoff_CX7200: Remove unimplemented devices
> >   hw/arm/beckhoff_CX7200: Set CPU frequency and PERIPHCLK period
> >   hw/arm/beckhoff_CX7200: Add CCAT to CX7200
> >   hw/arm/beckhoff_CX7200: Add dummy DDR CTRL to CX7200
> > 
> >  MAINTAINERS                       |   7 +
> >  hw/arm/Kconfig                    |  18 ++
> >  hw/arm/beckhoff_CX7200.c          | 440 ++++++++++++++++++++++++++++++
> >  hw/arm/
> > https://nospamproxywebp.beckhoff.com/enQsig/link?id=BAgAAACF1PqAcgZXNGoAAACSdE
> > 7DUYKKiipqQsJl32BC_vIVe3kQ23Cr-DKSrQn5Y_I0ZnsAu8qZHVUsGVmYwKL0amQboD-LYv9rWN-
> > mvEPUf2y-CZ1qrggzKI9xgbKnOi8XSPZVd2G0Lro-8fGR9tAuNB-3CWjEaKli0                
> > |   1 +
> >  hw/dma/xlnx-zynq-devcfg.c         |  36 ++-
> >  hw/misc/Kconfig                   |   6 +
> >  hw/misc/beckhoff_ccat.c           | 365 +++++++++++++++++++++++++
> >  hw/misc/
> > https://nospamproxywebp.beckhoff.com/enQsig/link?id=BAgAAACF1PqAcgZXNGoAAACSdE
> > 7DUYKKiipqQsJl32BC_vIVe3kQ23Cr-DKSrQn5Y_I0ZnsAu8qZHVUsGVmYwKL0amQboD-LYv9rWN-
> > mvEPUf2y-CZ1qrggzKI9xgbKnOi8XSPZVd2G0Lro-8fGR9tAuNB-3CWjEaKli0               
> > |   2 +
> >  hw/misc/zynq_ddr-ctrl.c           | 331 ++++++++++++++++++++++
> >  hw/misc/zynq_slcr.c               |  47 ++++
> >  hw/timer/a9gtimer.c               |  25 +-
> >  hw/timer/arm_mptimer.c            |  33 ++-
> >  include/hw/dma/xlnx-zynq-devcfg.h |   3 +
> >  include/hw/timer/a9gtimer.h       |   2 +
> >  include/hw/timer/arm_mptimer.h    |   4 +
> >  15 files changed, 1309 insertions(+), 11 deletions(-)
> >  create mode 100644 hw/arm/beckhoff_CX7200.c
> >  create mode 100644 hw/misc/beckhoff_ccat.c
> >  create mode 100644 hw/misc/zynq_ddr-ctrl.c
> 
> Hi,
> 
> any feedback for those commits?
>

Hi Corvin,

Thanks for the reminder and sorry for the delay! I started reviewing and
sending comments today. Cool work!

It would be great if you could include a patch to docs/system/arm/
describing how to test this machine.

Cheers,
Edgar


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 00/21] hw/arm: add CX7200 board emulation
  2025-04-25 19:59   ` Edgar E. Iglesias
@ 2025-05-05  8:57     ` Corvin Köhne
  0 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-05-05  8:57 UTC (permalink / raw)
  To: edgar.iglesias@gmail.com
  Cc: Yannick Voßen, peter.maydell@linaro.org, pbonzini@redhat.com,
	alistair@alistair23.me, qemu-devel@nongnu.org,
	qemu-arm@nongnu.org

[-- Attachment #1: Type: text/plain, Size: 4595 bytes --]

On Fri, 2025-04-25 at 21:59 +0200, Edgar E. Iglesias wrote:
> CAUTION: External Email!!
> On Thu, Apr 24, 2025 at 10:48:17AM +0000, Corvin Köhne wrote:
> > On Tue, 2025-03-18 at 14:07 +0100, Corvin Köhne wrote:
> > > CAUTION: External Email!!
> > > From: Corvin Köhne <c.koehne@beckhoff.com>
> > > 
> > > Beckhoff has build a board, called CX7200, based on the Xilinx Zynq A9
> > > platform. This commit series adds the Beckhoff CX7200 as new board variant
> > > to
> > > QEMU.
> > > 
> > > The emulation is able to successfully boot an CX7200 image. The image
> > > includes
> > > some self tests executed on every boot. Only the cache self test fails due
> > > to
> > > QEMU emulating the cache as always being coherent. The self tests include
> > > f.e.:
> > > 
> > > * Network
> > > * Flash
> > > * CCAT DMA + EEPROM [1]
> > > * TwinCAT (Beckhoff's automation control software [2])
> > > 
> > > [1] https://github.com/beckhoff/ccat
> > > [2] https://www.beckhoff.com/en-us/products/automation/
> > > 
> > > Corvin Köhne (1):
> > >   MAINTAINERS: add myself as reviewer for Beckhoff devices
> > > 
> > > YannickV (20):
> > >   hw/timer: Make frequency configurable
> > >   hw/timer: Make PERIPHCLK period configurable
> > >   hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff
> > >   hw/arm/zynq-devcfg: Prevent unintended unlock during initialization
> > >   hw/dma/zynq: Notify devcfg on FPGA reset via SLCR control
> > >   hw/dma/zynq-devcfg: Simulate dummy PL reset
> > >   hw/dma/zynq-devcfg: Indicate power-up status of PL
> > >   hw/dma/zynq-devcfg: Fix register memory
> > >   hw/misc: Add dummy ZYNQ DDR controller
> > >   hw/misc/zynq_slcr: Add logic for DCI configuration
> > >   hw/misc: Add Beckhoff CCAT device
> > >   hw/arm: Add new machine based on xilinx-zynq-a9 for Beckhoff CX7200
> > >   hw/arm/beckhoff_CX7200: Remove second SD controller
> > >   hw/arm/beckhoff_CX7200: Remove second GEM
> > >   hw/arm/beckhoff_CX7200: Adjust Flashes and Busses
> > >   hw/arm/beckhoff_CX7200: Remove usb interfaces
> > >   hw/arm/beckhoff_CX7200: Remove unimplemented devices
> > >   hw/arm/beckhoff_CX7200: Set CPU frequency and PERIPHCLK period
> > >   hw/arm/beckhoff_CX7200: Add CCAT to CX7200
> > >   hw/arm/beckhoff_CX7200: Add dummy DDR CTRL to CX7200
> > > 
> > >  MAINTAINERS                       |   7 +
> > >  hw/arm/Kconfig                    |  18 ++
> > >  hw/arm/beckhoff_CX7200.c          | 440 ++++++++++++++++++++++++++++++
> > >  hw/arm/
> > > https://nospamproxywebp.beckhoff.com/enQsig/link?id=BAgAAACF1PqAcgZXNGoAAACSdE
> > > 7DUYKKiipqQsJl32BC_vIVe3kQ23Cr-DKSrQn5Y_I0ZnsAu8qZHVUsGVmYwKL0amQboD-
> > > LYv9rWN-
> > > mvEPUf2y-CZ1qrggzKI9xgbKnOi8XSPZVd2G0Lro-8fGR9tAuNB-
> > > 3CWjEaKli0                
> > > >    1 +
> > >  hw/dma/xlnx-zynq-devcfg.c         |  36 ++-
> > >  hw/misc/Kconfig                   |   6 +
> > >  hw/misc/beckhoff_ccat.c           | 365 +++++++++++++++++++++++++
> > >  hw/misc/
> > > https://nospamproxywebp.beckhoff.com/enQsig/link?id=BAgAAACF1PqAcgZXNGoAAACSdE
> > > 7DUYKKiipqQsJl32BC_vIVe3kQ23Cr-DKSrQn5Y_I0ZnsAu8qZHVUsGVmYwKL0amQboD-
> > > LYv9rWN-
> > > mvEPUf2y-CZ1qrggzKI9xgbKnOi8XSPZVd2G0Lro-8fGR9tAuNB-
> > > 3CWjEaKli0               
> > > >    2 +
> > >  hw/misc/zynq_ddr-ctrl.c           | 331 ++++++++++++++++++++++
> > >  hw/misc/zynq_slcr.c               |  47 ++++
> > >  hw/timer/a9gtimer.c               |  25 +-
> > >  hw/timer/arm_mptimer.c            |  33 ++-
> > >  include/hw/dma/xlnx-zynq-devcfg.h |   3 +
> > >  include/hw/timer/a9gtimer.h       |   2 +
> > >  include/hw/timer/arm_mptimer.h    |   4 +
> > >  15 files changed, 1309 insertions(+), 11 deletions(-)
> > >  create mode 100644 hw/arm/beckhoff_CX7200.c
> > >  create mode 100644 hw/misc/beckhoff_ccat.c
> > >  create mode 100644 hw/misc/zynq_ddr-ctrl.c
> > 
> > Hi,
> > 
> > any feedback for those commits?
> > 
> 
> Hi Corvin,
> 
> Thanks for the reminder and sorry for the delay! I started reviewing and
> sending comments today. Cool work!
> 
> It would be great if you could include a patch to docs/system/arm/
> describing how to test this machine.
> 
> Cheers,
> Edgar

Hi Edgar,

thanks for your review! I'm going to add some instructions in v2.


-- 
Kind regards,
Corvin

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 09/21] hw/misc: Add dummy ZYNQ DDR controller
  2025-04-25 16:45   ` Edgar E. Iglesias
@ 2025-05-05  9:01     ` Corvin Köhne
  0 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-05-05  9:01 UTC (permalink / raw)
  To: edgar.iglesias@gmail.com
  Cc: Yannick Voßen, peter.maydell@linaro.org, pbonzini@redhat.com,
	alistair@alistair23.me, qemu-devel@nongnu.org,
	qemu-arm@nongnu.org

[-- Attachment #1: Type: text/plain, Size: 1696 bytes --]

On Fri, 2025-04-25 at 18:45 +0200, Edgar E. Iglesias wrote:
> CAUTION: External Email!!
> On Tue, Mar 18, 2025 at 02:08:00PM +0100, Corvin Köhne wrote:
> > 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: Yannick Voßen <y.vossen@beckhoff.com>
> > ---
> >  hw/misc/Kconfig         |   3 +
> >  hw/misc/
> > https://nospamproxywebp.beckhoff.com/enQsig/link?id=BAgAAADa4z1g3ukVnmoAAAAr
> > l_jkhWbCv_PHtUJpY7yEY601k79a77UyCbfaGco2JPpcaCOybQdhjR0cGnyWEZqCNC3PiECWlYa1
> > 3TZ7D5x6Yi5GY1Ud-M0zCSTuJ2WblH0OX92Mv4EAFobjbqz_a8r85TtpkZfrrOoa0      |   1
> > +
> >  hw/misc/zynq_ddr-ctrl.c | 331 ++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 335 insertions(+)
> >  create mode 100644 hw/misc/zynq_ddr-ctrl.c
> > 
> > diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
> > index ec0fa5aa9f..1bc4228572 100644
> > --- a/hw/misc/Kconfig
> > +++ b/hw/misc/Kconfig
> > @@ -222,4 +222,7 @@ config IOSB
> >  config XLNX_VERSAL_TRNG
> >      bool
> >  
> > +config DDR_CTRLR
> 
> I suggest XLNX_ZYNQ_DDRC ?
> 
> And name the file accordingly, e.g xlnx-zynq-ddrc.c.
> 
> You may also want to consider using the register API, see for example
> hw/misc/xlnx-versal-xramc.c, modelling another memory controller.
> 
> 

Thanks for the hint. Will take a look into it.


-- 
Kind regards,
Corvin

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 13/21] hw/arm/beckhoff_CX7200: Remove second SD controller
  2025-03-18 13:08 ` [PATCH 13/21] hw/arm/beckhoff_CX7200: Remove second SD controller Corvin Köhne
@ 2025-05-06 13:17   ` Peter Maydell
  0 siblings, 0 replies; 36+ messages in thread
From: Peter Maydell @ 2025-05-06 13:17 UTC (permalink / raw)
  To: Corvin Köhne
  Cc: qemu-devel, Corvin Köhne, qemu-arm, Yannick Voßen,
	Edgar E. Iglesias, Alistair Francis, Paolo Bonzini

On Tue, 18 Mar 2025 at 13:11, Corvin Köhne <corvin.koehne@gmail.com> wrote:
>
> From: YannickV <Y.Vossen@beckhoff.com>
>
> The CX7200 has one SD controller connected to address 0xE0101000.
> The controller connected to address 0xE0100000 can be removed.

Hi -- I see Edgar has done some review on the first part
of this patchset, but looking quickly over the second half
I notice that it has quite a few commits like this that
are removing/changing code that was just added in an
earlier patch in the series.

Please don't structure the patchset this way. If the board
has only one SD controller, then send a patchset that puts
in one SD controller, not one that puts in 2 and then
removes 1 of them.

Similarly for most of these other "remove" or "adjust" patches.

(If you want to add a board in a way that breaks it down into
smaller patches for easier review, one way to do this is
that you start with a "skeleton" version of the board with
e.g. just the CPU and one or two devices, and then in
later patches you add more devices. But in this case the
board code looks small enough that that's not necessary.)

thanks
-- PMM


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 05/21] hw/dma/zynq: Notify devcfg on FPGA reset via SLCR control
  2025-04-25 16:11   ` Edgar E. Iglesias
@ 2025-05-13  7:04     ` Corvin Köhne
  0 siblings, 0 replies; 36+ messages in thread
From: Corvin Köhne @ 2025-05-13  7:04 UTC (permalink / raw)
  To: edgar.iglesias@gmail.com
  Cc: Yannick Voßen, peter.maydell@linaro.org, pbonzini@redhat.com,
	alistair@alistair23.me, qemu-devel@nongnu.org,
	qemu-arm@nongnu.org

[-- Attachment #1: Type: text/plain, Size: 1498 bytes --]

On Fri, 2025-04-25 at 18:11 +0200, Edgar E. Iglesias wrote:
> CAUTION: External Email!!
> On Tue, Mar 18, 2025 at 02:07:56PM +0100, Corvin Köhne wrote:
> > From: YannickV <Y.Vossen@beckhoff.com>
> > 
> > When the FPGA_RST_CTRL register in the SLCR (System Level Control
> > Register) is written to, the devcfg (Device Configuration) should
> > indicate the finished reset.
> > 
> > Problems occure when Loaders trigger a reset via SLCR and poll for
> > the done flag in devcfg. Since the flag will never be set, this can
> > result in an endless loop.
> > 
> > A callback function `slcr_reset_handler` is added to the
> > `XlnxZynqDevcfg` structure. The `slcr_reset` function sets the
> > `PCFG_DONE` flag when triggered by an FPGA reset in the SLCR.
> > The SLCR write handler calls the `slcr_reset` function when the
> > FPGA reset control register (`R_FPGA_RST_CTRL`) is written with
> > the reset value.
> 
> Could you please refer to the specs where this is described?
> I couldn't find it...
> 
> 

Looks like we've misread the specs and our loader code. Our loader writes a one
to PCFG_DONE and FPGA_RST_CTRL and then polls PCFG_DONE, so we thought that it's
related. However, we've rechecked it and on hardware PCFG_DONE isn't reset on
this write. According to the spec, PCFG_DONE is a Write 1 to Clear register but
it won't reset when the condition for setting PCFG_DONE is still true. We're
going to fix this in v2, thanks.


-- 
Kind regards,
Corvin

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2025-05-13  7:05 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-18 13:07 [PATCH 00/21] Hi, Corvin Köhne
2025-03-18 13:07 ` [PATCH 01/21] hw/timer: Make frequency configurable Corvin Köhne
2025-03-18 13:07 ` [PATCH 02/21] hw/timer: Make PERIPHCLK period configurable Corvin Köhne
2025-03-18 13:07 ` [PATCH 03/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff Corvin Köhne
2025-04-25 15:47   ` Edgar E. Iglesias
2025-03-18 13:07 ` [PATCH 04/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization Corvin Köhne
2025-04-25 15:52   ` Edgar E. Iglesias
2025-03-18 13:07 ` [PATCH 05/21] hw/dma/zynq: Notify devcfg on FPGA reset via SLCR control Corvin Köhne
2025-04-25 16:11   ` Edgar E. Iglesias
2025-05-13  7:04     ` Corvin Köhne
2025-03-18 13:07 ` [PATCH 06/21] hw/dma/zynq-devcfg: Simulate dummy PL reset Corvin Köhne
2025-04-25 16:20   ` Edgar E. Iglesias
2025-03-18 13:07 ` [PATCH 07/21] hw/dma/zynq-devcfg: Indicate power-up status of PL Corvin Köhne
2025-04-25 16:24   ` Edgar E. Iglesias
2025-03-18 13:07 ` [PATCH 08/21] hw/dma/zynq-devcfg: Fix register memory Corvin Köhne
2025-04-25 16:27   ` Edgar E. Iglesias
2025-03-18 13:08 ` [PATCH 09/21] hw/misc: Add dummy ZYNQ DDR controller Corvin Köhne
2025-04-25 16:45   ` Edgar E. Iglesias
2025-05-05  9:01     ` Corvin Köhne
2025-03-18 13:08 ` [PATCH 10/21] hw/misc/zynq_slcr: Add logic for DCI configuration Corvin Köhne
2025-04-25 19:56   ` Edgar E. Iglesias
2025-03-18 13:08 ` [PATCH 11/21] hw/misc: Add Beckhoff CCAT device Corvin Köhne
2025-03-18 13:08 ` [PATCH 12/21] hw/arm: Add new machine based on xilinx-zynq-a9 for Beckhoff CX7200 Corvin Köhne
2025-03-18 13:08 ` [PATCH 13/21] hw/arm/beckhoff_CX7200: Remove second SD controller Corvin Köhne
2025-05-06 13:17   ` Peter Maydell
2025-03-18 13:08 ` [PATCH 14/21] hw/arm/beckhoff_CX7200: Remove second GEM Corvin Köhne
2025-03-18 13:08 ` [PATCH 15/21] hw/arm/beckhoff_CX7200: Adjust Flashes and Busses Corvin Köhne
2025-03-18 13:08 ` [PATCH 16/21] hw/arm/beckhoff_CX7200: Remove usb interfaces Corvin Köhne
2025-03-18 13:08 ` [PATCH 17/21] hw/arm/beckhoff_CX7200: Remove unimplemented devices Corvin Köhne
2025-03-18 13:08 ` [PATCH 18/21] hw/arm/beckhoff_CX7200: Set CPU frequency and PERIPHCLK period Corvin Köhne
2025-03-18 13:08 ` [PATCH 19/21] hw/arm/beckhoff_CX7200: Add CCAT to CX7200 Corvin Köhne
2025-03-18 13:08 ` [PATCH 20/21] hw/arm/beckhoff_CX7200: Add dummy DDR CTRL " Corvin Köhne
2025-03-18 13:08 ` [PATCH 21/21] MAINTAINERS: add myself as reviewer for Beckhoff devices Corvin Köhne
2025-04-24 10:48 ` [PATCH 00/21] hw/arm: add CX7200 board emulation Corvin Köhne
2025-04-25 19:59   ` Edgar E. Iglesias
2025-05-05  8:57     ` Corvin Köhne

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).