All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/5] hw/arm: zynqmp: Implement a CSU DMA model and connect it with GQSPI
@ 2021-02-10 10:10 Bin Meng
  2021-02-10 10:10 ` [PATCH v3 1/5] hw/dma: xlnx_csu_dma: Implement a basic XLNX CSU DMA model Bin Meng
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Bin Meng @ 2021-02-10 10:10 UTC (permalink / raw)
  To: Alistair Francis, Edgar E . Iglesias, Peter Maydell
  Cc: Bin Meng, Francisco Iglesias, qemu-arm, qemu-devel

From: Bin Meng <bin.meng@windriver.com>

ZynqMP QSPI supports SPI transfer using DMA mode, but currently this
is unimplemented. When QSPI is programmed to use DMA mode, QEMU will
crash. This is observed when testing VxWorks 7.

We added a basic CSU DMA model and the implementation is based on
https://github.com/Xilinx/qemu/blob/master/hw/dma/csu_stream_dma.c

Unfortunately the Xilinx fork of QEMU does not boot VxWorks. It looks
like the fork has quite a lot of difference from the upstream QEMU.

The CSU DMA model in the Xilinx fork seems to be quite complicated
and has lots of functionalities. However right now our goal is to
implement a minimum model that could be used to work with the GQSPI
model to make the QSPI DMA functionality work.

The model implements only the basic DMA transfer function of the DST
part, verified along with ZynqMP GQSPI model. Other advanced features
are not implemented.

Changes in v3:
- Implement DMA as a separate CSU DMA model
- new patch: xlnx-zynqmp: Clean up coding convention issues
- new patch: xlnx-zynqmp: Add XLNX CSU DMA module
- new patch: xilinx_spips: Remove DMA related code from zynqmp_qspips

Changes in v2:
- Remove unconnected TYPE_STREAM_SINK link property
- Add a TYPE_MEMORY_REGION link property, to allow board codes to tell
  the device what its view of the world that it is doing DMA to is
- Replace cpu_physical_memory_write() with address_space_write()

Xuzhou Cheng (5):
  hw/dma: xlnx_csu_dma: Implement a basic XLNX CSU DMA model
  hw/arm: xlnx-zynqmp: Clean up coding convention issues
  hw/arm: xlnx-zynqmp: Add XLNX CSU DMA module
  hw/ssi: xilinx_spips: Clean up coding convention issues
  hw/ssi: xilinx_spips: Remove DMA related code from zynqmp_qspips

 include/hw/arm/xlnx-zynqmp.h  |   5 +-
 include/hw/dma/xlnx_csu_dma.h |  39 ++++
 hw/arm/xlnx-zynqmp.c          |  25 ++-
 hw/dma/xlnx_csu_dma.c         | 444 ++++++++++++++++++++++++++++++++++++++++++
 hw/ssi/xilinx_spips.c         |  33 ++--
 hw/arm/Kconfig                |   1 +
 hw/dma/Kconfig                |   4 +
 hw/dma/meson.build            |   1 +
 8 files changed, 528 insertions(+), 24 deletions(-)
 create mode 100644 include/hw/dma/xlnx_csu_dma.h
 create mode 100644 hw/dma/xlnx_csu_dma.c

-- 
2.7.4



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

* [PATCH v3 1/5] hw/dma: xlnx_csu_dma: Implement a basic XLNX CSU DMA model
  2021-02-10 10:10 [PATCH v3 0/5] hw/arm: zynqmp: Implement a CSU DMA model and connect it with GQSPI Bin Meng
@ 2021-02-10 10:10 ` Bin Meng
  2021-02-10 11:52   ` Edgar E. Iglesias
  2021-02-10 10:10 ` [PATCH v3 2/5] hw/arm: xlnx-zynqmp: Clean up coding convention issues Bin Meng
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Bin Meng @ 2021-02-10 10:10 UTC (permalink / raw)
  To: Alistair Francis, Edgar E . Iglesias, Peter Maydell
  Cc: Bin Meng, Francisco Iglesias, qemu-arm, qemu-devel, Xuzhou Cheng

From: Xuzhou Cheng <xuzhou.cheng@windriver.com>

ZynqMP QSPI supports SPI transfer using DMA mode, but currently this
is unimplemented. When QSPI is programmed to use DMA mode, QEMU will
crash. This is observed when testing VxWorks 7.

This adds a basic CSU DMA model and the implementation is based on
https://github.com/Xilinx/qemu/blob/master/hw/dma/csu_stream_dma.c

The model implements only the basic DMA transfer function of the DST
part, verified along with ZynqMP GQSPI model. Other advanced features
are not implemented.

Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v3:
- Implement DMA as a separate CSU DMA model

Changes in v2:
- Remove unconnected TYPE_STREAM_SINK link property
- Add a TYPE_MEMORY_REGION link property, to allow board codes to tell
  the device what its view of the world that it is doing DMA to is
- Replace cpu_physical_memory_write() with address_space_write()

 include/hw/dma/xlnx_csu_dma.h |  39 ++++
 hw/dma/xlnx_csu_dma.c         | 444 ++++++++++++++++++++++++++++++++++++++++++
 hw/dma/Kconfig                |   4 +
 hw/dma/meson.build            |   1 +
 4 files changed, 488 insertions(+)
 create mode 100644 include/hw/dma/xlnx_csu_dma.h
 create mode 100644 hw/dma/xlnx_csu_dma.c

diff --git a/include/hw/dma/xlnx_csu_dma.h b/include/hw/dma/xlnx_csu_dma.h
new file mode 100644
index 0000000..bd87ee7
--- /dev/null
+++ b/include/hw/dma/xlnx_csu_dma.h
@@ -0,0 +1,39 @@
+/*
+ * ZynqMP Platform CSU Stream DMA emulation
+ *
+ * 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 or
+ * (at your option) version 3 of the License.
+ *
+ * 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/>.
+ */
+
+#ifndef XLNX_CSU_DMA_H
+#define XLNX_CSU_DMA_H
+
+#define TYPE_XLNX_CSU_DMA "xlnx.csu_dma"
+
+#define XLNX_CSU_DMA_REGS_MAX ((0x28 / 4) + 1)
+
+typedef struct XlnxCSUDMA {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    MemoryRegion *dma_mr;
+    AddressSpace *dma_as;
+    qemu_irq irq;
+    StreamSink *tx;
+    uint32_t regs[XLNX_CSU_DMA_REGS_MAX];
+    RegisterInfo regs_info[XLNX_CSU_DMA_REGS_MAX];
+} XlnxCSUDMA;
+
+#define XLNX_CSU_DMA(obj) \
+     OBJECT_CHECK(XlnxCSUDMA, (obj), TYPE_XLNX_CSU_DMA)
+
+#endif
diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c
new file mode 100644
index 0000000..6f237ca
--- /dev/null
+++ b/hw/dma/xlnx_csu_dma.c
@@ -0,0 +1,444 @@
+/*
+ * ZynqMP Platform CSU Stream DMA emulation
+ *
+ * This implements only the basic DMA transfer function of the DST part,
+ * other advanced features are not implemented.
+ *
+ * This implementation is based on
+ * https://github.com/Xilinx/qemu/blob/master/hw/dma/csu_stream_dma.c
+ *
+ * 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 or
+ * (at your option) version 3 of the License.
+ *
+ * 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 "qemu/log.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "sysemu/dma.h"
+#include "hw/ptimer.h"
+#include "hw/stream.h"
+#include "hw/register.h"
+#include "hw/dma/xlnx_csu_dma.h"
+
+/*
+ * Ref: UG1087 (v1.7) February 8, 2019
+ * https://www.xilinx.com/html_docs/registers/ug1087/
+ * ug1087-zynq-ultrascale-registers.html
+ */
+REG32(ADDR, 0x0)
+    FIELD(ADDR, ADDR, 2, 30) /* wo */
+REG32(SIZE, 0x4)
+    FIELD(SIZE, SIZE, 2, 27) /* wo */
+REG32(STATUS, 0x8)
+    FIELD(STATUS, DONE_CNT, 13, 3) /* wtc */
+    FIELD(STATUS, BUSY, 0, 1) /* ro */
+REG32(CTRL, 0xc)
+    FIELD(CTRL, FIFO_LVL_HIT_THRESH, 25, 7) /* rw, reset: 0x40 */
+    FIELD(CTRL, APB_ERR_RESP, 24, 1) /* rw */
+    FIELD(CTRL, ENDIANNESS, 23, 1) /* rw */
+    FIELD(CTRL, AXI_BRST_TYPE, 22, 1) /* rw */
+    FIELD(CTRL, TIMEOUT_VAL, 10, 12) /* rw, reset: 0xFFE */
+    FIELD(CTRL, FIFO_THRESH, 2, 8) /* rw, reset: 0x80 */
+    FIELD(CTRL, PAUSE_STRM, 1, 1) /* rw */
+    FIELD(CTRL, PAUSE_MEM, 0, 1) /* rw */
+REG32(RES, 0x10)
+REG32(INT_STATUS, 0x14)
+    FIELD(INT_STATUS, FIFO_OVERFLOW, 7, 1) /* wtc */
+    FIELD(INT_STATUS, INVALID_APB, 6, 1) /* wtc */
+    FIELD(INT_STATUS, THRESH_HIT, 5, 1) /* wtc */
+    FIELD(INT_STATUS, TIMEOUT_MEM, 4, 1) /* wtc */
+    FIELD(INT_STATUS, TIMEOUT_STRM, 3, 1) /* wtc */
+    FIELD(INT_STATUS, AXI_BRESP_ERR, 2, 1) /* wtc */
+    FIELD(INT_STATUS, DONE, 1, 1) /* wtc */
+REG32(INT_ENABLE, 0x18)
+    FIELD(INT_ENABLE, FIFO_OVERFLOW, 7, 1) /* wtc */
+    FIELD(INT_ENABLE, INVALID_APB, 6, 1) /* wtc */
+    FIELD(INT_ENABLE, THRESH_HIT, 5, 1) /* wtc */
+    FIELD(INT_ENABLE, TIMEOUT_MEM, 4, 1) /* wtc */
+    FIELD(INT_ENABLE, TIMEOUT_STRM, 3, 1) /* wtc */
+    FIELD(INT_ENABLE, AXI_BRESP_ERR, 2, 1) /* wtc */
+    FIELD(INT_ENABLE, DONE, 1, 1) /* wtc */
+REG32(INT_DISABLE, 0x1c)
+    FIELD(INT_DISABLE, FIFO_OVERFLOW, 7, 1) /* wtc */
+    FIELD(INT_DISABLE, INVALID_APB, 6, 1) /* wtc */
+    FIELD(INT_DISABLE, THRESH_HIT, 5, 1) /* wtc */
+    FIELD(INT_DISABLE, TIMEOUT_MEM, 4, 1) /* wtc */
+    FIELD(INT_DISABLE, TIMEOUT_STRM, 3, 1) /* wtc */
+    FIELD(INT_DISABLE, AXI_BRESP_ERR, 2, 1) /* wtc */
+    FIELD(INT_DISABLE, DONE, 1, 1) /* wtc */
+REG32(INT_MASK, 0x20) /* reset: 0xFE */
+    FIELD(INT_MASK, FIFO_OVERFLOW, 7, 1) /* ro, reset: 0x1 */
+    FIELD(INT_MASK, INVALID_APB, 6, 1) /* ro, reset: 0x1 */
+    FIELD(INT_MASK, THRESH_HIT, 5, 1) /* ro, reset: 0x1 */
+    FIELD(INT_MASK, TIMEOUT_MEM, 4, 1) /* ro, reset: 0x1 */
+    FIELD(INT_MASK, TIMEOUT_STRM, 3, 1) /* ro, reset: 0x1 */
+    FIELD(INT_MASK, AXI_BRESP_ERR, 2, 1) /* ro, reset: 0x1 */
+    FIELD(INT_MASK, DONE, 1, 1) /* ro, reset: 0x1 */
+REG32(CTRL2, 0x24) /* reset: 0xFFF8 */
+    FIELD(CTRL2, ARCACHE, 24, 3) /* rw */
+    FIELD(CTRL2, TIMEOUT_EN, 22, 1) /* rw */
+    FIELD(CTRL2, TIMEOUT_PRE, 4, 12) /* rw, reset: 0xFFF */
+    FIELD(CTRL2, MAX_OUTS_CMDS, 0, 4) /* rw, reset: 0x8 */
+REG32(ADDR_MSB, 0x28)
+    FIELD(ADDR_MSB, ADDR_MSB, 0, 12) /* wo */
+
+#define CSU_DMA_INT_REGS_MASK 0xfe
+
+static uint64_t addr_pre_write(RegisterInfo *reg, uint64_t val)
+{
+    return val & R_ADDR_ADDR_MASK;
+}
+
+static uint64_t size_pre_write(RegisterInfo *reg, uint64_t val)
+{
+    return val & R_SIZE_SIZE_MASK;
+}
+
+static uint64_t status_pre_write(RegisterInfo *reg, uint64_t val)
+{
+    return val & (R_STATUS_DONE_CNT_MASK | R_STATUS_BUSY_MASK);
+}
+
+static uint64_t addr_msb_pre_write(RegisterInfo *reg, uint64_t val)
+{
+    return val & R_ADDR_MSB_ADDR_MSB_MASK;
+}
+
+static void csu_dma_done(XlnxCSUDMA *s)
+{
+    int cnt;
+
+    s->regs[R_STATUS] &= ~R_STATUS_BUSY_MASK;
+    s->regs[R_INT_STATUS] |= R_INT_STATUS_DONE_MASK;
+
+    cnt = ARRAY_FIELD_EX32(s->regs, STATUS, DONE_CNT) + 1;
+    ARRAY_FIELD_DP32(s->regs, STATUS, DONE_CNT, cnt);
+}
+
+static void csu_dma_update_irq(XlnxCSUDMA *s)
+{
+    qemu_set_irq(s->irq, !!(s->regs[R_INT_STATUS] & ~s->regs[R_INT_MASK]));
+}
+
+static uint64_t int_enable_pre_write(RegisterInfo *reg, uint64_t val)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
+    /*
+     * 1: Enable this interrupt field (The mask bit will be cleared to 0)
+     * 0: No effect
+     * Reads to this register will return 0
+     */
+    uint32_t ret = s->regs[R_INT_ENABLE] | (val & CSU_DMA_INT_REGS_MASK);
+
+    s->regs[R_INT_MASK] &= ~ret;
+
+    /* The field in int_disable should also be cleared */
+    s->regs[R_INT_DISABLE] &= ~ret;
+
+    return ret;
+}
+
+static void int_enable_post_write(RegisterInfo *reg, uint64_t val)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
+
+    csu_dma_update_irq(s);
+    return;
+}
+
+static void int_disable_post_write(RegisterInfo *reg, uint64_t val)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
+
+    csu_dma_update_irq(s);
+
+    /* Clear int_status when disable DMA interrupt */
+    s->regs[R_INT_STATUS] &= 0;
+    return;
+}
+
+static uint64_t int_disable_pre_write(RegisterInfo *reg, uint64_t val)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
+    /*
+     * 1: Disable this interrupt field (The mask bit will be set to 1)
+     * 0: No effect
+     * Reads to this register will return 0
+     */
+    uint32_t ret = s->regs[R_INT_DISABLE] | (val & CSU_DMA_INT_REGS_MASK);
+
+    s->regs[R_INT_MASK] |= ret;
+
+    /* The field in int_enable should also be cleared */
+    s->regs[R_INT_ENABLE] &= ~ret;
+    return ret;
+}
+
+static uint64_t int_status_pre_write(RegisterInfo *reg, uint64_t val)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
+
+    /* Write 1: clear status bit */
+    return s->regs[R_INT_STATUS] & ~(val & CSU_DMA_INT_REGS_MASK);
+}
+
+static RegisterAccessInfo xlnx_csu_dma_regs_info[] = {
+    {   .name = "CSU_DMA_ADDR",
+        .addr = A_ADDR,
+        .pre_write = addr_pre_write
+    }, {
+        .name = "CSU_DMA_SIZE",
+        .addr = A_SIZE,
+        .pre_write = size_pre_write
+    }, {
+        .name = "CSU_DMA_STATUS",
+        .addr = A_STATUS,
+        .pre_write = status_pre_write,
+        .ro = R_STATUS_BUSY_MASK
+    }, {
+        .name = "CSU_DMA_CTRL",
+        .addr = A_CTRL,
+        .reset = 0x803FFA00
+    }, {
+        .name = "CSU_DMA_RES",
+         .addr = A_RES,
+    }, {
+        .name = "CSU_DMA_INT_STATUS",
+        .addr = A_INT_STATUS,
+        .pre_write = int_status_pre_write
+    }, {
+        .name = "CSU_DMA_INT_ENABLE",
+        .addr = A_INT_ENABLE,
+        .pre_write = int_enable_pre_write,
+        .post_write = int_enable_post_write
+    }, {
+        .name = "CSU_DMA_INT_DISABLE",
+        .addr = A_INT_DISABLE,
+        .pre_write = int_disable_pre_write,
+        .post_write = int_disable_post_write
+    }, {
+        .name = "CSU_DMA_INT_MASK",
+        .addr = A_INT_MASK,
+        .ro = ~0,
+        .reset = CSU_DMA_INT_REGS_MASK
+    }, {
+        .name = "CSU_DMA_CTRL2",
+        .addr = A_CTRL2,
+        .reset = 0x081BFFF8
+    }, {
+        .name = "CSU_DMA_ADDR_MSB",
+        .addr = A_ADDR_MSB,
+        .pre_write = addr_msb_pre_write
+    }
+};
+
+static uint32_t csu_dma_advance(XlnxCSUDMA *s, uint32_t len, hwaddr dst)
+{
+    uint32_t size = s->regs[R_SIZE];
+
+    size -= len;
+    size &= R_SIZE_SIZE_MASK;
+    dst += len;
+
+    s->regs[R_SIZE] = size;
+    s->regs[R_ADDR] = (uint32_t) dst;
+    s->regs[R_ADDR_MSB] = dst >> 32;
+
+    return size;
+}
+
+static size_t xlnx_csu_dma_stream_push(StreamSink *obj, uint8_t *buf,
+                                       size_t len, bool eop)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(obj);
+    hwaddr dst = (hwaddr)s->regs[R_ADDR_MSB] << 32 | s->regs[R_ADDR];
+    uint32_t size = s->regs[R_SIZE];
+    uint32_t mlen = MIN(size, len) & (~3); /* Size is word aligned */
+
+    if (size == 0 || len <= 0) {
+        return 0;
+    }
+
+    if (address_space_write(s->dma_as, dst, MEMTXATTRS_UNSPECIFIED, buf, mlen)
+        != MEMTX_OK) {
+        return 0;
+    }
+
+    size = csu_dma_advance(s, mlen, dst);
+
+    if (size == 0) {
+        csu_dma_done(s);
+        csu_dma_update_irq(s);
+    }
+
+   return mlen;
+}
+
+static bool xlnx_csu_dma_stream_can_push(StreamSink *obj,
+                                         StreamCanPushNotifyFn notify,
+                                         void *notify_opaque)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(obj);
+
+    return s->regs[R_SIZE] ? true : false;
+}
+
+static uint64_t xlnx_csu_dma_read(void *opaque, hwaddr offset, unsigned size)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(opaque);
+    RegisterInfo *r = &s->regs_info[offset / 4];
+    uint64_t ret = 0;
+
+    if (!r->data) {
+        char *path = object_get_canonical_path(OBJECT(s));
+        qemu_log("%s: Decode error: read from %" HWADDR_PRIx "\n",
+                 path, offset);
+        g_free(path);
+        return 0;
+    }
+
+    ret = register_read(r, ~0, NULL, false);
+    return ret;
+}
+
+static void xlnx_csu_dma_write(void *opaque, hwaddr offset,
+                               uint64_t value, unsigned size)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(opaque);
+    uint32_t reg = offset / 4;
+    RegisterInfo *r = &s->regs_info[reg];
+
+    if (!r->data) {
+        char *path = object_get_canonical_path(OBJECT(s));
+        qemu_log("%s: Decode error: read from %" HWADDR_PRIx "\n",
+                 path, offset);
+        g_free(path);
+        return;
+    }
+
+    register_write(r, value, ~0, NULL, false);
+}
+
+static const MemoryRegionOps xlnx_csu_dma_ops = {
+    .read = xlnx_csu_dma_read,
+    .write = xlnx_csu_dma_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void xlnx_csu_dma_reset(DeviceState *dev)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(dev);
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
+        register_reset(&s->regs_info[i]);
+    }
+}
+
+static void xlnx_csu_dma_realize(DeviceState *dev, Error **errp)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(dev);
+    unsigned int i = 0;
+
+    memory_region_init_io(&s->iomem, OBJECT(dev), &xlnx_csu_dma_ops, s,
+                          TYPE_XLNX_CSU_DMA, XLNX_CSU_DMA_REGS_MAX * 4);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+
+    for (i = 0; i < ARRAY_SIZE(xlnx_csu_dma_regs_info); i++) {
+        RegisterInfo *r = &s->regs_info[xlnx_csu_dma_regs_info[i].addr / 4];
+        r->data = (uint8_t *)&s->regs[xlnx_csu_dma_regs_info[i].addr / 4];
+        r->data_size = sizeof(uint32_t);
+        r->access = (const RegisterAccessInfo *)&xlnx_csu_dma_regs_info[i];
+        r->opaque = s;
+    }
+
+    if (s->dma_mr) {
+        s->dma_as = g_malloc0(sizeof(AddressSpace));
+        address_space_init(s->dma_as, s->dma_mr, NULL);
+    } else {
+        s->dma_as = &address_space_memory;
+    }
+}
+
+static void xlnx_csu_dma_init(Object *obj)
+{
+    XlnxCSUDMA *s = XLNX_CSU_DMA(obj);
+
+    object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SINK,
+                             (Object **)&s->tx,
+                             qdev_prop_allow_set_link_before_realize,
+                             OBJ_PROP_LINK_STRONG);
+    object_property_add_link(obj, "xlnx-csu-dma-mr", TYPE_MEMORY_REGION,
+                             (Object **)&s->dma_mr,
+                             qdev_prop_allow_set_link_before_realize,
+                             OBJ_PROP_LINK_STRONG);
+}
+
+static const VMStateDescription vmstate_xlnx_csu_dma = {
+    .name = TYPE_XLNX_CSU_DMA,
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, XlnxCSUDMA, XLNX_CSU_DMA_REGS_MAX),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
+
+    dc->reset = xlnx_csu_dma_reset;
+    dc->realize = xlnx_csu_dma_realize;
+    dc->vmsd = &vmstate_xlnx_csu_dma;
+
+    ssc->push = ((StreamSinkClass *)data)->push;
+    ssc->can_push = ((StreamSinkClass *)data)->can_push;
+}
+
+static StreamSinkClass xlnx_csu_dma_stream_class = {
+    .push = xlnx_csu_dma_stream_push,
+    .can_push = xlnx_csu_dma_stream_can_push,
+};
+
+static const TypeInfo xlnx_csu_dma_info = {
+    .name          = TYPE_XLNX_CSU_DMA,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(XlnxCSUDMA),
+    .class_init    = xlnx_csu_dma_class_init,
+    .class_data    = &xlnx_csu_dma_stream_class,
+    .instance_init = xlnx_csu_dma_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_STREAM_SINK },
+        { }
+    }
+};
+
+static void xlnx_csu_dma_register_types(void)
+{
+    type_register_static(&xlnx_csu_dma_info);
+}
+
+type_init(xlnx_csu_dma_register_types)
diff --git a/hw/dma/Kconfig b/hw/dma/Kconfig
index 5d6be1a..98fbb1b 100644
--- a/hw/dma/Kconfig
+++ b/hw/dma/Kconfig
@@ -26,3 +26,7 @@ config STP2000
 
 config SIFIVE_PDMA
     bool
+
+config XLNX_CSU_DMA
+    bool
+    select REGISTER
diff --git a/hw/dma/meson.build b/hw/dma/meson.build
index 47b4a7c..5c78a4e 100644
--- a/hw/dma/meson.build
+++ b/hw/dma/meson.build
@@ -14,3 +14,4 @@ softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c'))
 softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_dma.c'))
 softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c'))
 softmmu_ss.add(when: 'CONFIG_SIFIVE_PDMA', if_true: files('sifive_pdma.c'))
+softmmu_ss.add(when: 'CONFIG_XLNX_CSU_DMA', if_true: files('xlnx_csu_dma.c'))
-- 
2.7.4



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

* [PATCH v3 2/5] hw/arm: xlnx-zynqmp: Clean up coding convention issues
  2021-02-10 10:10 [PATCH v3 0/5] hw/arm: zynqmp: Implement a CSU DMA model and connect it with GQSPI Bin Meng
  2021-02-10 10:10 ` [PATCH v3 1/5] hw/dma: xlnx_csu_dma: Implement a basic XLNX CSU DMA model Bin Meng
@ 2021-02-10 10:10 ` Bin Meng
  2021-02-10 11:54   ` Edgar E. Iglesias
  2021-02-10 10:10 ` [PATCH v3 3/5] hw/arm: xlnx-zynqmp: Add XLNX CSU DMA module Bin Meng
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Bin Meng @ 2021-02-10 10:10 UTC (permalink / raw)
  To: Alistair Francis, Edgar E . Iglesias, Peter Maydell
  Cc: Bin Meng, Francisco Iglesias, qemu-arm, qemu-devel, Xuzhou Cheng

From: Xuzhou Cheng <xuzhou.cheng@windriver.com>

There are some coding convention warnings in xlnx-zynqmp.c and
xlnx-zynqmp.h, as reported by:

  $ ./scripts/checkpatch.pl include/hw/arm/xlnx-zynqmp.h
  $ ./scripts/checkpatch.pl hw/arm/xlnx-zynqmp.c

Let's clean them up.

Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v3:
- new patch: xlnx-zynqmp: Clean up coding convention issues

 include/hw/arm/xlnx-zynqmp.h |  3 ++-
 hw/arm/xlnx-zynqmp.c         | 11 +++++++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
index 6f45387..be15cc8 100644
--- a/include/hw/arm/xlnx-zynqmp.h
+++ b/include/hw/arm/xlnx-zynqmp.h
@@ -60,7 +60,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP)
 
 #define XLNX_ZYNQMP_GIC_REGIONS 6
 
-/* ZynqMP maps the ARM GIC regions (GICC, GICD ...) at consecutive 64k offsets
+/*
+ * ZynqMP maps the ARM GIC regions (GICC, GICD ...) at consecutive 64k offsets
  * and under-decodes the 64k region. This mirrors the 4k regions to every 4k
  * aligned address in the 64k region. To implement each GIC region needs a
  * number of memory region aliases.
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 8818472..76b94a5 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -301,11 +301,13 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
 
     ram_size = memory_region_size(s->ddr_ram);
 
-    /* Create the DDR Memory Regions. User friendly checks should happen at
+    /*
+     * Create the DDR Memory Regions. User friendly checks should happen at
      * the board level
      */
     if (ram_size > XLNX_ZYNQMP_MAX_LOW_RAM_SIZE) {
-        /* The RAM size is above the maximum available for the low DDR.
+        /*
+         * The RAM size is above the maximum available for the low DDR.
          * Create the high DDR memory region as well.
          */
         assert(ram_size <= XLNX_ZYNQMP_MAX_RAM_SIZE);
@@ -351,7 +353,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
 
     qdev_realize(DEVICE(&s->apu_cluster), NULL, &error_fatal);
 
-    /* Realize APUs before realizing the GIC. KVM requires this.  */
+    /* Realize APUs before realizing the GIC. KVM requires this. */
     for (i = 0; i < num_apus; i++) {
         const char *name;
 
@@ -526,7 +528,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->sdhci[i]);
         Object *sdhci = OBJECT(&s->sdhci[i]);
 
-        /* Compatible with:
+        /*
+         * Compatible with:
          * - SD Host Controller Specification Version 3.00
          * - SDIO Specification Version 3.0
          * - eMMC Specification Version 4.51
-- 
2.7.4



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

* [PATCH v3 3/5] hw/arm: xlnx-zynqmp: Add XLNX CSU DMA module
  2021-02-10 10:10 [PATCH v3 0/5] hw/arm: zynqmp: Implement a CSU DMA model and connect it with GQSPI Bin Meng
  2021-02-10 10:10 ` [PATCH v3 1/5] hw/dma: xlnx_csu_dma: Implement a basic XLNX CSU DMA model Bin Meng
  2021-02-10 10:10 ` [PATCH v3 2/5] hw/arm: xlnx-zynqmp: Clean up coding convention issues Bin Meng
@ 2021-02-10 10:10 ` Bin Meng
  2021-02-10 11:38   ` Edgar E. Iglesias
  2021-02-10 10:10 ` [PATCH v3 4/5] hw/ssi: xilinx_spips: Clean up coding convention issues Bin Meng
  2021-02-10 10:10 ` [PATCH v3 5/5] hw/ssi: xilinx_spips: Remove DMA related code from zynqmp_qspips Bin Meng
  4 siblings, 1 reply; 11+ messages in thread
From: Bin Meng @ 2021-02-10 10:10 UTC (permalink / raw)
  To: Alistair Francis, Edgar E . Iglesias, Peter Maydell
  Cc: Bin Meng, Francisco Iglesias, qemu-arm, qemu-devel, Xuzhou Cheng

From: Xuzhou Cheng <xuzhou.cheng@windriver.com>

Insert XLNX CSU DMA module to ZynqMP SoC, and connent the stream
link of GQSPI to CSU DMA.

Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v3:
- new patch: xlnx-zynqmp: Add XLNX CSU DMA module

 include/hw/arm/xlnx-zynqmp.h |  2 ++
 hw/arm/xlnx-zynqmp.c         | 14 ++++++++++++++
 hw/arm/Kconfig               |  1 +
 3 files changed, 17 insertions(+)

diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
index be15cc8..d387c85 100644
--- a/include/hw/arm/xlnx-zynqmp.h
+++ b/include/hw/arm/xlnx-zynqmp.h
@@ -35,6 +35,7 @@
 #include "target/arm/cpu.h"
 #include "qom/object.h"
 #include "net/can_emu.h"
+#include "hw/dma/xlnx_csu_dma.h"
 
 #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
 OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP)
@@ -108,6 +109,7 @@ struct XlnxZynqMPState {
     XlnxZynqMPRTC rtc;
     XlnxZDMA gdma[XLNX_ZYNQMP_NUM_GDMA_CH];
     XlnxZDMA adma[XLNX_ZYNQMP_NUM_ADMA_CH];
+    XlnxCSUDMA csu_dma;
 
     char *boot_cpu;
     ARMCPU *boot_cpu_ptr;
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 76b94a5..ed34692 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -63,6 +63,9 @@
 #define RTC_ADDR            0xffa60000
 #define RTC_IRQ             26
 
+#define CSU_DMA_ADDR        0xff0f0800
+#define CSU_DMA_IRQ         15
+
 #define SDHCI_CAPABILITIES  0x280737ec6481 /* Datasheet: UG1085 (v1.7) */
 
 static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = {
@@ -284,6 +287,8 @@ static void xlnx_zynqmp_init(Object *obj)
     for (i = 0; i < XLNX_ZYNQMP_NUM_ADMA_CH; i++) {
         object_initialize_child(obj, "adma[*]", &s->adma[i], TYPE_XLNX_ZDMA);
     }
+
+    object_initialize_child(obj, "csu-dma", &s->csu_dma, TYPE_XLNX_CSU_DMA);
 }
 
 static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
@@ -643,6 +648,15 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
         sysbus_connect_irq(SYS_BUS_DEVICE(&s->adma[i]), 0,
                            gic_spi[adma_ch_intr[i]]);
     }
+
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->csu_dma), errp)) {
+        return;
+    }
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->csu_dma), 0, CSU_DMA_ADDR);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->csu_dma), 0, gic_spi[CSU_DMA_IRQ]);
+    object_property_set_link(OBJECT(&s->qspi), "stream-connected-dma",
+                             OBJECT(&s->csu_dma), errp);
 }
 
 static Property xlnx_zynqmp_props[] = {
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index be017b9..0c0384c 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -353,6 +353,7 @@ config XLNX_ZYNQMP_ARM
     select SSI_M25P80
     select XILINX_AXI
     select XILINX_SPIPS
+    select XLNX_CSU_DMA
     select XLNX_ZYNQMP
     select XLNX_ZDMA
 
-- 
2.7.4



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

* [PATCH v3 4/5] hw/ssi: xilinx_spips: Clean up coding convention issues
  2021-02-10 10:10 [PATCH v3 0/5] hw/arm: zynqmp: Implement a CSU DMA model and connect it with GQSPI Bin Meng
                   ` (2 preceding siblings ...)
  2021-02-10 10:10 ` [PATCH v3 3/5] hw/arm: xlnx-zynqmp: Add XLNX CSU DMA module Bin Meng
@ 2021-02-10 10:10 ` Bin Meng
  2021-02-10 11:39   ` Edgar E. Iglesias
  2021-02-10 10:10 ` [PATCH v3 5/5] hw/ssi: xilinx_spips: Remove DMA related code from zynqmp_qspips Bin Meng
  4 siblings, 1 reply; 11+ messages in thread
From: Bin Meng @ 2021-02-10 10:10 UTC (permalink / raw)
  To: Alistair Francis, Edgar E . Iglesias, Peter Maydell
  Cc: Bin Meng, Francisco Iglesias, qemu-arm, qemu-devel, Xuzhou Cheng

From: Xuzhou Cheng <xuzhou.cheng@windriver.com>

There are some coding convention warnings in xilinx_spips.c,
as reported by:

  $ ./scripts/checkpatch.pl hw/ssi/xilinx_spips.c

Let's clean them up.

Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---

(no changes since v1)

 hw/ssi/xilinx_spips.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index a897034..8a0cc22 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -176,7 +176,8 @@
     FIELD(GQSPI_FIFO_CTRL, GENERIC_FIFO_RESET, 0, 1)
 #define R_GQSPI_GFIFO_THRESH    (0x150 / 4)
 #define R_GQSPI_DATA_STS (0x15c / 4)
-/* We use the snapshot register to hold the core state for the currently
+/*
+ * We use the snapshot register to hold the core state for the currently
  * or most recently executed command. So the generic fifo format is defined
  * for the snapshot register
  */
@@ -424,7 +425,8 @@ static void xlnx_zynqmp_qspips_reset(DeviceState *d)
     xlnx_zynqmp_qspips_update_ixr(s);
 }
 
-/* N way (num) in place bit striper. Lay out row wise bits (MSB to LSB)
+/*
+ * N way (num) in place bit striper. Lay out row wise bits (MSB to LSB)
  * column wise (from element 0 to N-1). num is the length of x, and dir
  * reverses the direction of the transform. Best illustrated by example:
  * Each digit in the below array is a single bit (num == 3):
@@ -637,8 +639,10 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
                 tx_rx[i] = tx;
             }
         } else {
-            /* Extract a dummy byte and generate dummy cycles according to the
-             * link state */
+            /*
+             * Extract a dummy byte and generate dummy cycles according to the
+             * link state
+             */
             tx = fifo8_pop(&s->tx_fifo);
             dummy_cycles = 8 / s->link_state;
         }
@@ -721,8 +725,9 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
             }
             break;
         case (SNOOP_ADDR):
-            /* Address has been transmitted, transmit dummy cycles now if
-             * needed */
+            /*
+             * Address has been transmitted, transmit dummy cycles now if needed
+             */
             if (s->cmd_dummies < 0) {
                 s->snoop_state = SNOOP_NONE;
             } else {
@@ -876,7 +881,7 @@ static void xlnx_zynqmp_qspips_notify(void *opaque)
 }
 
 static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
-                                                        unsigned size)
+                                  unsigned size)
 {
     XilinxSPIPS *s = opaque;
     uint32_t mask = ~0;
@@ -970,7 +975,7 @@ static uint64_t xlnx_zynqmp_qspips_read(void *opaque,
 }
 
 static void xilinx_spips_write(void *opaque, hwaddr addr,
-                                        uint64_t value, unsigned size)
+                               uint64_t value, unsigned size)
 {
     int mask = ~0;
     XilinxSPIPS *s = opaque;
@@ -1072,7 +1077,7 @@ static void xilinx_qspips_write(void *opaque, hwaddr addr,
 }
 
 static void xlnx_zynqmp_qspips_write(void *opaque, hwaddr addr,
-                                        uint64_t value, unsigned size)
+                                     uint64_t value, unsigned size)
 {
     XlnxZynqMPQSPIPS *s = XLNX_ZYNQMP_QSPIPS(opaque);
     uint32_t reg = addr / 4;
-- 
2.7.4



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

* [PATCH v3 5/5] hw/ssi: xilinx_spips: Remove DMA related code from zynqmp_qspips
  2021-02-10 10:10 [PATCH v3 0/5] hw/arm: zynqmp: Implement a CSU DMA model and connect it with GQSPI Bin Meng
                   ` (3 preceding siblings ...)
  2021-02-10 10:10 ` [PATCH v3 4/5] hw/ssi: xilinx_spips: Clean up coding convention issues Bin Meng
@ 2021-02-10 10:10 ` Bin Meng
  2021-02-10 11:39   ` Edgar E. Iglesias
  4 siblings, 1 reply; 11+ messages in thread
From: Bin Meng @ 2021-02-10 10:10 UTC (permalink / raw)
  To: Alistair Francis, Edgar E . Iglesias, Peter Maydell
  Cc: Bin Meng, Francisco Iglesias, qemu-arm, qemu-devel, Xuzhou Cheng

From: Xuzhou Cheng <xuzhou.cheng@windriver.com>

Now that the XLNX CSU DMA model is implemented, the existing codes
in the ZynqMP QSPIS are useless and should be removed.

Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v3:
- new patch: xilinx_spips: Remove DMA related code from zynqmp_qspips

 hw/ssi/xilinx_spips.c | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 8a0cc22..1e9dba2 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -195,13 +195,6 @@
 #define R_GQSPI_MOD_ID        (0x1fc / 4)
 #define R_GQSPI_MOD_ID_RESET  (0x10a0000)
 
-#define R_QSPIDMA_DST_CTRL         (0x80c / 4)
-#define R_QSPIDMA_DST_CTRL_RESET   (0x803ffa00)
-#define R_QSPIDMA_DST_I_MASK       (0x820 / 4)
-#define R_QSPIDMA_DST_I_MASK_RESET (0xfe)
-#define R_QSPIDMA_DST_CTRL2        (0x824 / 4)
-#define R_QSPIDMA_DST_CTRL2_RESET  (0x081bfff8)
-
 /* size of TXRX FIFOs */
 #define RXFF_A          (128)
 #define TXFF_A          (128)
@@ -417,9 +410,6 @@ static void xlnx_zynqmp_qspips_reset(DeviceState *d)
     s->regs[R_GQSPI_GPIO] = 1;
     s->regs[R_GQSPI_LPBK_DLY_ADJ] = R_GQSPI_LPBK_DLY_ADJ_RESET;
     s->regs[R_GQSPI_MOD_ID] = R_GQSPI_MOD_ID_RESET;
-    s->regs[R_QSPIDMA_DST_CTRL] = R_QSPIDMA_DST_CTRL_RESET;
-    s->regs[R_QSPIDMA_DST_I_MASK] = R_QSPIDMA_DST_I_MASK_RESET;
-    s->regs[R_QSPIDMA_DST_CTRL2] = R_QSPIDMA_DST_CTRL2_RESET;
     s->man_start_com_g = false;
     s->gqspi_irqline = 0;
     xlnx_zynqmp_qspips_update_ixr(s);
-- 
2.7.4



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

* Re: [PATCH v3 3/5] hw/arm: xlnx-zynqmp: Add XLNX CSU DMA module
  2021-02-10 10:10 ` [PATCH v3 3/5] hw/arm: xlnx-zynqmp: Add XLNX CSU DMA module Bin Meng
@ 2021-02-10 11:38   ` Edgar E. Iglesias
  0 siblings, 0 replies; 11+ messages in thread
From: Edgar E. Iglesias @ 2021-02-10 11:38 UTC (permalink / raw)
  To: Bin Meng
  Cc: Peter Maydell, Xuzhou Cheng, Bin Meng, qemu-devel,
	Francisco Iglesias, qemu-arm, Alistair Francis

On Wed, Feb 10, 2021 at 06:10:11PM +0800, Bin Meng wrote:
> From: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> 
> Insert XLNX CSU DMA module to ZynqMP SoC, and connent the stream
> link of GQSPI to CSU DMA.
> 
> Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> 
> ---
> 
> Changes in v3:
> - new patch: xlnx-zynqmp: Add XLNX CSU DMA module
> 
>  include/hw/arm/xlnx-zynqmp.h |  2 ++
>  hw/arm/xlnx-zynqmp.c         | 14 ++++++++++++++
>  hw/arm/Kconfig               |  1 +
>  3 files changed, 17 insertions(+)
> 
> diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
> index be15cc8..d387c85 100644
> --- a/include/hw/arm/xlnx-zynqmp.h
> +++ b/include/hw/arm/xlnx-zynqmp.h
> @@ -35,6 +35,7 @@
>  #include "target/arm/cpu.h"
>  #include "qom/object.h"
>  #include "net/can_emu.h"
> +#include "hw/dma/xlnx_csu_dma.h"
>  
>  #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
>  OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP)
> @@ -108,6 +109,7 @@ struct XlnxZynqMPState {
>      XlnxZynqMPRTC rtc;
>      XlnxZDMA gdma[XLNX_ZYNQMP_NUM_GDMA_CH];
>      XlnxZDMA adma[XLNX_ZYNQMP_NUM_ADMA_CH];
> +    XlnxCSUDMA csu_dma;


This should be named in relation to QSPI, e.g qspi_dma.

Otherwise, this looks good to me.


>  
>      char *boot_cpu;
>      ARMCPU *boot_cpu_ptr;
> diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
> index 76b94a5..ed34692 100644
> --- a/hw/arm/xlnx-zynqmp.c
> +++ b/hw/arm/xlnx-zynqmp.c
> @@ -63,6 +63,9 @@
>  #define RTC_ADDR            0xffa60000
>  #define RTC_IRQ             26
>  
> +#define CSU_DMA_ADDR        0xff0f0800
> +#define CSU_DMA_IRQ         15
> +
>  #define SDHCI_CAPABILITIES  0x280737ec6481 /* Datasheet: UG1085 (v1.7) */
>  
>  static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = {
> @@ -284,6 +287,8 @@ static void xlnx_zynqmp_init(Object *obj)
>      for (i = 0; i < XLNX_ZYNQMP_NUM_ADMA_CH; i++) {
>          object_initialize_child(obj, "adma[*]", &s->adma[i], TYPE_XLNX_ZDMA);
>      }
> +
> +    object_initialize_child(obj, "csu-dma", &s->csu_dma, TYPE_XLNX_CSU_DMA);
>  }
>  
>  static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
> @@ -643,6 +648,15 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
>          sysbus_connect_irq(SYS_BUS_DEVICE(&s->adma[i]), 0,
>                             gic_spi[adma_ch_intr[i]]);
>      }
> +
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->csu_dma), errp)) {
> +        return;
> +    }
> +
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->csu_dma), 0, CSU_DMA_ADDR);
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->csu_dma), 0, gic_spi[CSU_DMA_IRQ]);
> +    object_property_set_link(OBJECT(&s->qspi), "stream-connected-dma",
> +                             OBJECT(&s->csu_dma), errp);
>  }
>  
>  static Property xlnx_zynqmp_props[] = {
> diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
> index be017b9..0c0384c 100644
> --- a/hw/arm/Kconfig
> +++ b/hw/arm/Kconfig
> @@ -353,6 +353,7 @@ config XLNX_ZYNQMP_ARM
>      select SSI_M25P80
>      select XILINX_AXI
>      select XILINX_SPIPS
> +    select XLNX_CSU_DMA
>      select XLNX_ZYNQMP
>      select XLNX_ZDMA
>  
> -- 
> 2.7.4
> 


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

* Re: [PATCH v3 5/5] hw/ssi: xilinx_spips: Remove DMA related code from zynqmp_qspips
  2021-02-10 10:10 ` [PATCH v3 5/5] hw/ssi: xilinx_spips: Remove DMA related code from zynqmp_qspips Bin Meng
@ 2021-02-10 11:39   ` Edgar E. Iglesias
  0 siblings, 0 replies; 11+ messages in thread
From: Edgar E. Iglesias @ 2021-02-10 11:39 UTC (permalink / raw)
  To: Bin Meng
  Cc: Peter Maydell, Xuzhou Cheng, Bin Meng, qemu-devel,
	Francisco Iglesias, qemu-arm, Alistair Francis

On Wed, Feb 10, 2021 at 06:10:13PM +0800, Bin Meng wrote:
> From: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> 
> Now that the XLNX CSU DMA model is implemented, the existing codes
> in the ZynqMP QSPIS are useless and should be removed.

We should also modify XLNX_ZYNQMP_SPIPS_R_MAX in the header file.

Otherwise, this looks good to me.


> 
> Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> 
> ---
> 
> Changes in v3:
> - new patch: xilinx_spips: Remove DMA related code from zynqmp_qspips
> 
>  hw/ssi/xilinx_spips.c | 10 ----------
>  1 file changed, 10 deletions(-)
> 
> diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
> index 8a0cc22..1e9dba2 100644
> --- a/hw/ssi/xilinx_spips.c
> +++ b/hw/ssi/xilinx_spips.c
> @@ -195,13 +195,6 @@
>  #define R_GQSPI_MOD_ID        (0x1fc / 4)
>  #define R_GQSPI_MOD_ID_RESET  (0x10a0000)
>  
> -#define R_QSPIDMA_DST_CTRL         (0x80c / 4)
> -#define R_QSPIDMA_DST_CTRL_RESET   (0x803ffa00)
> -#define R_QSPIDMA_DST_I_MASK       (0x820 / 4)
> -#define R_QSPIDMA_DST_I_MASK_RESET (0xfe)
> -#define R_QSPIDMA_DST_CTRL2        (0x824 / 4)
> -#define R_QSPIDMA_DST_CTRL2_RESET  (0x081bfff8)
> -
>  /* size of TXRX FIFOs */
>  #define RXFF_A          (128)
>  #define TXFF_A          (128)
> @@ -417,9 +410,6 @@ static void xlnx_zynqmp_qspips_reset(DeviceState *d)
>      s->regs[R_GQSPI_GPIO] = 1;
>      s->regs[R_GQSPI_LPBK_DLY_ADJ] = R_GQSPI_LPBK_DLY_ADJ_RESET;
>      s->regs[R_GQSPI_MOD_ID] = R_GQSPI_MOD_ID_RESET;
> -    s->regs[R_QSPIDMA_DST_CTRL] = R_QSPIDMA_DST_CTRL_RESET;
> -    s->regs[R_QSPIDMA_DST_I_MASK] = R_QSPIDMA_DST_I_MASK_RESET;
> -    s->regs[R_QSPIDMA_DST_CTRL2] = R_QSPIDMA_DST_CTRL2_RESET;
>      s->man_start_com_g = false;
>      s->gqspi_irqline = 0;
>      xlnx_zynqmp_qspips_update_ixr(s);
> -- 
> 2.7.4
> 


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

* Re: [PATCH v3 4/5] hw/ssi: xilinx_spips: Clean up coding convention issues
  2021-02-10 10:10 ` [PATCH v3 4/5] hw/ssi: xilinx_spips: Clean up coding convention issues Bin Meng
@ 2021-02-10 11:39   ` Edgar E. Iglesias
  0 siblings, 0 replies; 11+ messages in thread
From: Edgar E. Iglesias @ 2021-02-10 11:39 UTC (permalink / raw)
  To: Bin Meng
  Cc: Peter Maydell, Xuzhou Cheng, Bin Meng, qemu-devel,
	Francisco Iglesias, qemu-arm, Alistair Francis

On Wed, Feb 10, 2021 at 06:10:12PM +0800, Bin Meng wrote:
> From: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> 
> There are some coding convention warnings in xilinx_spips.c,
> as reported by:
> 
>   $ ./scripts/checkpatch.pl hw/ssi/xilinx_spips.c
> 
> Let's clean them up.
> 
> Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

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



> ---
> 
> (no changes since v1)
> 
>  hw/ssi/xilinx_spips.c | 23 ++++++++++++++---------
>  1 file changed, 14 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
> index a897034..8a0cc22 100644
> --- a/hw/ssi/xilinx_spips.c
> +++ b/hw/ssi/xilinx_spips.c
> @@ -176,7 +176,8 @@
>      FIELD(GQSPI_FIFO_CTRL, GENERIC_FIFO_RESET, 0, 1)
>  #define R_GQSPI_GFIFO_THRESH    (0x150 / 4)
>  #define R_GQSPI_DATA_STS (0x15c / 4)
> -/* We use the snapshot register to hold the core state for the currently
> +/*
> + * We use the snapshot register to hold the core state for the currently
>   * or most recently executed command. So the generic fifo format is defined
>   * for the snapshot register
>   */
> @@ -424,7 +425,8 @@ static void xlnx_zynqmp_qspips_reset(DeviceState *d)
>      xlnx_zynqmp_qspips_update_ixr(s);
>  }
>  
> -/* N way (num) in place bit striper. Lay out row wise bits (MSB to LSB)
> +/*
> + * N way (num) in place bit striper. Lay out row wise bits (MSB to LSB)
>   * column wise (from element 0 to N-1). num is the length of x, and dir
>   * reverses the direction of the transform. Best illustrated by example:
>   * Each digit in the below array is a single bit (num == 3):
> @@ -637,8 +639,10 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
>                  tx_rx[i] = tx;
>              }
>          } else {
> -            /* Extract a dummy byte and generate dummy cycles according to the
> -             * link state */
> +            /*
> +             * Extract a dummy byte and generate dummy cycles according to the
> +             * link state
> +             */
>              tx = fifo8_pop(&s->tx_fifo);
>              dummy_cycles = 8 / s->link_state;
>          }
> @@ -721,8 +725,9 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
>              }
>              break;
>          case (SNOOP_ADDR):
> -            /* Address has been transmitted, transmit dummy cycles now if
> -             * needed */
> +            /*
> +             * Address has been transmitted, transmit dummy cycles now if needed
> +             */
>              if (s->cmd_dummies < 0) {
>                  s->snoop_state = SNOOP_NONE;
>              } else {
> @@ -876,7 +881,7 @@ static void xlnx_zynqmp_qspips_notify(void *opaque)
>  }
>  
>  static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
> -                                                        unsigned size)
> +                                  unsigned size)
>  {
>      XilinxSPIPS *s = opaque;
>      uint32_t mask = ~0;
> @@ -970,7 +975,7 @@ static uint64_t xlnx_zynqmp_qspips_read(void *opaque,
>  }
>  
>  static void xilinx_spips_write(void *opaque, hwaddr addr,
> -                                        uint64_t value, unsigned size)
> +                               uint64_t value, unsigned size)
>  {
>      int mask = ~0;
>      XilinxSPIPS *s = opaque;
> @@ -1072,7 +1077,7 @@ static void xilinx_qspips_write(void *opaque, hwaddr addr,
>  }
>  
>  static void xlnx_zynqmp_qspips_write(void *opaque, hwaddr addr,
> -                                        uint64_t value, unsigned size)
> +                                     uint64_t value, unsigned size)
>  {
>      XlnxZynqMPQSPIPS *s = XLNX_ZYNQMP_QSPIPS(opaque);
>      uint32_t reg = addr / 4;
> -- 
> 2.7.4
> 


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

* Re: [PATCH v3 1/5] hw/dma: xlnx_csu_dma: Implement a basic XLNX CSU DMA model
  2021-02-10 10:10 ` [PATCH v3 1/5] hw/dma: xlnx_csu_dma: Implement a basic XLNX CSU DMA model Bin Meng
@ 2021-02-10 11:52   ` Edgar E. Iglesias
  0 siblings, 0 replies; 11+ messages in thread
From: Edgar E. Iglesias @ 2021-02-10 11:52 UTC (permalink / raw)
  To: Bin Meng
  Cc: Peter Maydell, Xuzhou Cheng, Bin Meng, qemu-devel,
	Francisco Iglesias, qemu-arm, Alistair Francis

On Wed, Feb 10, 2021 at 06:10:09PM +0800, Bin Meng wrote:
> From: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> 
> ZynqMP QSPI supports SPI transfer using DMA mode, but currently this
> is unimplemented. When QSPI is programmed to use DMA mode, QEMU will
> crash. This is observed when testing VxWorks 7.
> 
> This adds a basic CSU DMA model and the implementation is based on
> https://github.com/Xilinx/qemu/blob/master/hw/dma/csu_stream_dma.c
> 
> The model implements only the basic DMA transfer function of the DST
> part, verified along with ZynqMP GQSPI model. Other advanced features
> are not implemented.


As you mention, this basic DMA model is not complete.
I've pushed a branch based on your series but with the more complete
model from our tree (two patches to squash at the top). Please include that
in v2 and we can continue reviewing the complete model.

https://github.com/edgarigl/qemu/tree/zynqmp-qspi

Cheers,
Edgar


> 
> Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> 
> ---
> 
> Changes in v3:
> - Implement DMA as a separate CSU DMA model
> 
> Changes in v2:
> - Remove unconnected TYPE_STREAM_SINK link property
> - Add a TYPE_MEMORY_REGION link property, to allow board codes to tell
>   the device what its view of the world that it is doing DMA to is
> - Replace cpu_physical_memory_write() with address_space_write()
> 
>  include/hw/dma/xlnx_csu_dma.h |  39 ++++
>  hw/dma/xlnx_csu_dma.c         | 444 ++++++++++++++++++++++++++++++++++++++++++
>  hw/dma/Kconfig                |   4 +
>  hw/dma/meson.build            |   1 +
>  4 files changed, 488 insertions(+)
>  create mode 100644 include/hw/dma/xlnx_csu_dma.h
>  create mode 100644 hw/dma/xlnx_csu_dma.c
> 
> diff --git a/include/hw/dma/xlnx_csu_dma.h b/include/hw/dma/xlnx_csu_dma.h
> new file mode 100644
> index 0000000..bd87ee7
> --- /dev/null
> +++ b/include/hw/dma/xlnx_csu_dma.h
> @@ -0,0 +1,39 @@
> +/*
> + * ZynqMP Platform CSU Stream DMA emulation
> + *
> + * 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 or
> + * (at your option) version 3 of the License.
> + *
> + * 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/>.
> + */
> +
> +#ifndef XLNX_CSU_DMA_H
> +#define XLNX_CSU_DMA_H
> +
> +#define TYPE_XLNX_CSU_DMA "xlnx.csu_dma"
> +
> +#define XLNX_CSU_DMA_REGS_MAX ((0x28 / 4) + 1)
> +
> +typedef struct XlnxCSUDMA {
> +    SysBusDevice busdev;
> +    MemoryRegion iomem;
> +    MemoryRegion *dma_mr;
> +    AddressSpace *dma_as;
> +    qemu_irq irq;
> +    StreamSink *tx;
> +    uint32_t regs[XLNX_CSU_DMA_REGS_MAX];
> +    RegisterInfo regs_info[XLNX_CSU_DMA_REGS_MAX];
> +} XlnxCSUDMA;
> +
> +#define XLNX_CSU_DMA(obj) \
> +     OBJECT_CHECK(XlnxCSUDMA, (obj), TYPE_XLNX_CSU_DMA)
> +
> +#endif
> diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c
> new file mode 100644
> index 0000000..6f237ca
> --- /dev/null
> +++ b/hw/dma/xlnx_csu_dma.c
> @@ -0,0 +1,444 @@
> +/*
> + * ZynqMP Platform CSU Stream DMA emulation
> + *
> + * This implements only the basic DMA transfer function of the DST part,
> + * other advanced features are not implemented.
> + *
> + * This implementation is based on
> + * https://github.com/Xilinx/qemu/blob/master/hw/dma/csu_stream_dma.c
> + *
> + * 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 or
> + * (at your option) version 3 of the License.
> + *
> + * 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 "qemu/log.h"
> +#include "qapi/error.h"
> +#include "hw/hw.h"
> +#include "hw/irq.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/sysbus.h"
> +#include "migration/vmstate.h"
> +#include "sysemu/dma.h"
> +#include "hw/ptimer.h"
> +#include "hw/stream.h"
> +#include "hw/register.h"
> +#include "hw/dma/xlnx_csu_dma.h"
> +
> +/*
> + * Ref: UG1087 (v1.7) February 8, 2019
> + * https://www.xilinx.com/html_docs/registers/ug1087/
> + * ug1087-zynq-ultrascale-registers.html
> + */
> +REG32(ADDR, 0x0)
> +    FIELD(ADDR, ADDR, 2, 30) /* wo */
> +REG32(SIZE, 0x4)
> +    FIELD(SIZE, SIZE, 2, 27) /* wo */
> +REG32(STATUS, 0x8)
> +    FIELD(STATUS, DONE_CNT, 13, 3) /* wtc */
> +    FIELD(STATUS, BUSY, 0, 1) /* ro */
> +REG32(CTRL, 0xc)
> +    FIELD(CTRL, FIFO_LVL_HIT_THRESH, 25, 7) /* rw, reset: 0x40 */
> +    FIELD(CTRL, APB_ERR_RESP, 24, 1) /* rw */
> +    FIELD(CTRL, ENDIANNESS, 23, 1) /* rw */
> +    FIELD(CTRL, AXI_BRST_TYPE, 22, 1) /* rw */
> +    FIELD(CTRL, TIMEOUT_VAL, 10, 12) /* rw, reset: 0xFFE */
> +    FIELD(CTRL, FIFO_THRESH, 2, 8) /* rw, reset: 0x80 */
> +    FIELD(CTRL, PAUSE_STRM, 1, 1) /* rw */
> +    FIELD(CTRL, PAUSE_MEM, 0, 1) /* rw */
> +REG32(RES, 0x10)
> +REG32(INT_STATUS, 0x14)
> +    FIELD(INT_STATUS, FIFO_OVERFLOW, 7, 1) /* wtc */
> +    FIELD(INT_STATUS, INVALID_APB, 6, 1) /* wtc */
> +    FIELD(INT_STATUS, THRESH_HIT, 5, 1) /* wtc */
> +    FIELD(INT_STATUS, TIMEOUT_MEM, 4, 1) /* wtc */
> +    FIELD(INT_STATUS, TIMEOUT_STRM, 3, 1) /* wtc */
> +    FIELD(INT_STATUS, AXI_BRESP_ERR, 2, 1) /* wtc */
> +    FIELD(INT_STATUS, DONE, 1, 1) /* wtc */
> +REG32(INT_ENABLE, 0x18)
> +    FIELD(INT_ENABLE, FIFO_OVERFLOW, 7, 1) /* wtc */
> +    FIELD(INT_ENABLE, INVALID_APB, 6, 1) /* wtc */
> +    FIELD(INT_ENABLE, THRESH_HIT, 5, 1) /* wtc */
> +    FIELD(INT_ENABLE, TIMEOUT_MEM, 4, 1) /* wtc */
> +    FIELD(INT_ENABLE, TIMEOUT_STRM, 3, 1) /* wtc */
> +    FIELD(INT_ENABLE, AXI_BRESP_ERR, 2, 1) /* wtc */
> +    FIELD(INT_ENABLE, DONE, 1, 1) /* wtc */
> +REG32(INT_DISABLE, 0x1c)
> +    FIELD(INT_DISABLE, FIFO_OVERFLOW, 7, 1) /* wtc */
> +    FIELD(INT_DISABLE, INVALID_APB, 6, 1) /* wtc */
> +    FIELD(INT_DISABLE, THRESH_HIT, 5, 1) /* wtc */
> +    FIELD(INT_DISABLE, TIMEOUT_MEM, 4, 1) /* wtc */
> +    FIELD(INT_DISABLE, TIMEOUT_STRM, 3, 1) /* wtc */
> +    FIELD(INT_DISABLE, AXI_BRESP_ERR, 2, 1) /* wtc */
> +    FIELD(INT_DISABLE, DONE, 1, 1) /* wtc */
> +REG32(INT_MASK, 0x20) /* reset: 0xFE */
> +    FIELD(INT_MASK, FIFO_OVERFLOW, 7, 1) /* ro, reset: 0x1 */
> +    FIELD(INT_MASK, INVALID_APB, 6, 1) /* ro, reset: 0x1 */
> +    FIELD(INT_MASK, THRESH_HIT, 5, 1) /* ro, reset: 0x1 */
> +    FIELD(INT_MASK, TIMEOUT_MEM, 4, 1) /* ro, reset: 0x1 */
> +    FIELD(INT_MASK, TIMEOUT_STRM, 3, 1) /* ro, reset: 0x1 */
> +    FIELD(INT_MASK, AXI_BRESP_ERR, 2, 1) /* ro, reset: 0x1 */
> +    FIELD(INT_MASK, DONE, 1, 1) /* ro, reset: 0x1 */
> +REG32(CTRL2, 0x24) /* reset: 0xFFF8 */
> +    FIELD(CTRL2, ARCACHE, 24, 3) /* rw */
> +    FIELD(CTRL2, TIMEOUT_EN, 22, 1) /* rw */
> +    FIELD(CTRL2, TIMEOUT_PRE, 4, 12) /* rw, reset: 0xFFF */
> +    FIELD(CTRL2, MAX_OUTS_CMDS, 0, 4) /* rw, reset: 0x8 */
> +REG32(ADDR_MSB, 0x28)
> +    FIELD(ADDR_MSB, ADDR_MSB, 0, 12) /* wo */
> +
> +#define CSU_DMA_INT_REGS_MASK 0xfe
> +
> +static uint64_t addr_pre_write(RegisterInfo *reg, uint64_t val)
> +{
> +    return val & R_ADDR_ADDR_MASK;
> +}
> +
> +static uint64_t size_pre_write(RegisterInfo *reg, uint64_t val)
> +{
> +    return val & R_SIZE_SIZE_MASK;
> +}
> +
> +static uint64_t status_pre_write(RegisterInfo *reg, uint64_t val)
> +{
> +    return val & (R_STATUS_DONE_CNT_MASK | R_STATUS_BUSY_MASK);
> +}
> +
> +static uint64_t addr_msb_pre_write(RegisterInfo *reg, uint64_t val)
> +{
> +    return val & R_ADDR_MSB_ADDR_MSB_MASK;
> +}
> +
> +static void csu_dma_done(XlnxCSUDMA *s)
> +{
> +    int cnt;
> +
> +    s->regs[R_STATUS] &= ~R_STATUS_BUSY_MASK;
> +    s->regs[R_INT_STATUS] |= R_INT_STATUS_DONE_MASK;
> +
> +    cnt = ARRAY_FIELD_EX32(s->regs, STATUS, DONE_CNT) + 1;
> +    ARRAY_FIELD_DP32(s->regs, STATUS, DONE_CNT, cnt);
> +}
> +
> +static void csu_dma_update_irq(XlnxCSUDMA *s)
> +{
> +    qemu_set_irq(s->irq, !!(s->regs[R_INT_STATUS] & ~s->regs[R_INT_MASK]));
> +}
> +
> +static uint64_t int_enable_pre_write(RegisterInfo *reg, uint64_t val)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
> +    /*
> +     * 1: Enable this interrupt field (The mask bit will be cleared to 0)
> +     * 0: No effect
> +     * Reads to this register will return 0
> +     */
> +    uint32_t ret = s->regs[R_INT_ENABLE] | (val & CSU_DMA_INT_REGS_MASK);
> +
> +    s->regs[R_INT_MASK] &= ~ret;
> +
> +    /* The field in int_disable should also be cleared */
> +    s->regs[R_INT_DISABLE] &= ~ret;
> +
> +    return ret;
> +}
> +
> +static void int_enable_post_write(RegisterInfo *reg, uint64_t val)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
> +
> +    csu_dma_update_irq(s);
> +    return;
> +}
> +
> +static void int_disable_post_write(RegisterInfo *reg, uint64_t val)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
> +
> +    csu_dma_update_irq(s);
> +
> +    /* Clear int_status when disable DMA interrupt */
> +    s->regs[R_INT_STATUS] &= 0;
> +    return;
> +}
> +
> +static uint64_t int_disable_pre_write(RegisterInfo *reg, uint64_t val)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
> +    /*
> +     * 1: Disable this interrupt field (The mask bit will be set to 1)
> +     * 0: No effect
> +     * Reads to this register will return 0
> +     */
> +    uint32_t ret = s->regs[R_INT_DISABLE] | (val & CSU_DMA_INT_REGS_MASK);
> +
> +    s->regs[R_INT_MASK] |= ret;
> +
> +    /* The field in int_enable should also be cleared */
> +    s->regs[R_INT_ENABLE] &= ~ret;
> +    return ret;
> +}
> +
> +static uint64_t int_status_pre_write(RegisterInfo *reg, uint64_t val)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
> +
> +    /* Write 1: clear status bit */
> +    return s->regs[R_INT_STATUS] & ~(val & CSU_DMA_INT_REGS_MASK);
> +}
> +
> +static RegisterAccessInfo xlnx_csu_dma_regs_info[] = {
> +    {   .name = "CSU_DMA_ADDR",
> +        .addr = A_ADDR,
> +        .pre_write = addr_pre_write
> +    }, {
> +        .name = "CSU_DMA_SIZE",
> +        .addr = A_SIZE,
> +        .pre_write = size_pre_write
> +    }, {
> +        .name = "CSU_DMA_STATUS",
> +        .addr = A_STATUS,
> +        .pre_write = status_pre_write,
> +        .ro = R_STATUS_BUSY_MASK
> +    }, {
> +        .name = "CSU_DMA_CTRL",
> +        .addr = A_CTRL,
> +        .reset = 0x803FFA00
> +    }, {
> +        .name = "CSU_DMA_RES",
> +         .addr = A_RES,
> +    }, {
> +        .name = "CSU_DMA_INT_STATUS",
> +        .addr = A_INT_STATUS,
> +        .pre_write = int_status_pre_write
> +    }, {
> +        .name = "CSU_DMA_INT_ENABLE",
> +        .addr = A_INT_ENABLE,
> +        .pre_write = int_enable_pre_write,
> +        .post_write = int_enable_post_write
> +    }, {
> +        .name = "CSU_DMA_INT_DISABLE",
> +        .addr = A_INT_DISABLE,
> +        .pre_write = int_disable_pre_write,
> +        .post_write = int_disable_post_write
> +    }, {
> +        .name = "CSU_DMA_INT_MASK",
> +        .addr = A_INT_MASK,
> +        .ro = ~0,
> +        .reset = CSU_DMA_INT_REGS_MASK
> +    }, {
> +        .name = "CSU_DMA_CTRL2",
> +        .addr = A_CTRL2,
> +        .reset = 0x081BFFF8
> +    }, {
> +        .name = "CSU_DMA_ADDR_MSB",
> +        .addr = A_ADDR_MSB,
> +        .pre_write = addr_msb_pre_write
> +    }
> +};
> +
> +static uint32_t csu_dma_advance(XlnxCSUDMA *s, uint32_t len, hwaddr dst)
> +{
> +    uint32_t size = s->regs[R_SIZE];
> +
> +    size -= len;
> +    size &= R_SIZE_SIZE_MASK;
> +    dst += len;
> +
> +    s->regs[R_SIZE] = size;
> +    s->regs[R_ADDR] = (uint32_t) dst;
> +    s->regs[R_ADDR_MSB] = dst >> 32;
> +
> +    return size;
> +}
> +
> +static size_t xlnx_csu_dma_stream_push(StreamSink *obj, uint8_t *buf,
> +                                       size_t len, bool eop)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(obj);
> +    hwaddr dst = (hwaddr)s->regs[R_ADDR_MSB] << 32 | s->regs[R_ADDR];
> +    uint32_t size = s->regs[R_SIZE];
> +    uint32_t mlen = MIN(size, len) & (~3); /* Size is word aligned */
> +
> +    if (size == 0 || len <= 0) {
> +        return 0;
> +    }
> +
> +    if (address_space_write(s->dma_as, dst, MEMTXATTRS_UNSPECIFIED, buf, mlen)
> +        != MEMTX_OK) {
> +        return 0;
> +    }
> +
> +    size = csu_dma_advance(s, mlen, dst);
> +
> +    if (size == 0) {
> +        csu_dma_done(s);
> +        csu_dma_update_irq(s);
> +    }
> +
> +   return mlen;
> +}
> +
> +static bool xlnx_csu_dma_stream_can_push(StreamSink *obj,
> +                                         StreamCanPushNotifyFn notify,
> +                                         void *notify_opaque)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(obj);
> +
> +    return s->regs[R_SIZE] ? true : false;
> +}
> +
> +static uint64_t xlnx_csu_dma_read(void *opaque, hwaddr offset, unsigned size)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(opaque);
> +    RegisterInfo *r = &s->regs_info[offset / 4];
> +    uint64_t ret = 0;
> +
> +    if (!r->data) {
> +        char *path = object_get_canonical_path(OBJECT(s));
> +        qemu_log("%s: Decode error: read from %" HWADDR_PRIx "\n",
> +                 path, offset);
> +        g_free(path);
> +        return 0;
> +    }
> +
> +    ret = register_read(r, ~0, NULL, false);
> +    return ret;
> +}
> +
> +static void xlnx_csu_dma_write(void *opaque, hwaddr offset,
> +                               uint64_t value, unsigned size)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(opaque);
> +    uint32_t reg = offset / 4;
> +    RegisterInfo *r = &s->regs_info[reg];
> +
> +    if (!r->data) {
> +        char *path = object_get_canonical_path(OBJECT(s));
> +        qemu_log("%s: Decode error: read from %" HWADDR_PRIx "\n",
> +                 path, offset);
> +        g_free(path);
> +        return;
> +    }
> +
> +    register_write(r, value, ~0, NULL, false);
> +}
> +
> +static const MemoryRegionOps xlnx_csu_dma_ops = {
> +    .read = xlnx_csu_dma_read,
> +    .write = xlnx_csu_dma_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    }
> +};
> +
> +static void xlnx_csu_dma_reset(DeviceState *dev)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(dev);
> +    unsigned int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
> +        register_reset(&s->regs_info[i]);
> +    }
> +}
> +
> +static void xlnx_csu_dma_realize(DeviceState *dev, Error **errp)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(dev);
> +    unsigned int i = 0;
> +
> +    memory_region_init_io(&s->iomem, OBJECT(dev), &xlnx_csu_dma_ops, s,
> +                          TYPE_XLNX_CSU_DMA, XLNX_CSU_DMA_REGS_MAX * 4);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
> +    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
> +
> +    for (i = 0; i < ARRAY_SIZE(xlnx_csu_dma_regs_info); i++) {
> +        RegisterInfo *r = &s->regs_info[xlnx_csu_dma_regs_info[i].addr / 4];
> +        r->data = (uint8_t *)&s->regs[xlnx_csu_dma_regs_info[i].addr / 4];
> +        r->data_size = sizeof(uint32_t);
> +        r->access = (const RegisterAccessInfo *)&xlnx_csu_dma_regs_info[i];
> +        r->opaque = s;
> +    }
> +
> +    if (s->dma_mr) {
> +        s->dma_as = g_malloc0(sizeof(AddressSpace));
> +        address_space_init(s->dma_as, s->dma_mr, NULL);
> +    } else {
> +        s->dma_as = &address_space_memory;
> +    }
> +}
> +
> +static void xlnx_csu_dma_init(Object *obj)
> +{
> +    XlnxCSUDMA *s = XLNX_CSU_DMA(obj);
> +
> +    object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SINK,
> +                             (Object **)&s->tx,
> +                             qdev_prop_allow_set_link_before_realize,
> +                             OBJ_PROP_LINK_STRONG);
> +    object_property_add_link(obj, "xlnx-csu-dma-mr", TYPE_MEMORY_REGION,
> +                             (Object **)&s->dma_mr,
> +                             qdev_prop_allow_set_link_before_realize,
> +                             OBJ_PROP_LINK_STRONG);
> +}
> +
> +static const VMStateDescription vmstate_xlnx_csu_dma = {
> +    .name = TYPE_XLNX_CSU_DMA,
> +    .version_id = 0,
> +    .minimum_version_id = 0,
> +    .minimum_version_id_old = 0,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32_ARRAY(regs, XlnxCSUDMA, XLNX_CSU_DMA_REGS_MAX),
> +        VMSTATE_END_OF_LIST(),
> +    }
> +};
> +
> +static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
> +
> +    dc->reset = xlnx_csu_dma_reset;
> +    dc->realize = xlnx_csu_dma_realize;
> +    dc->vmsd = &vmstate_xlnx_csu_dma;
> +
> +    ssc->push = ((StreamSinkClass *)data)->push;
> +    ssc->can_push = ((StreamSinkClass *)data)->can_push;
> +}
> +
> +static StreamSinkClass xlnx_csu_dma_stream_class = {
> +    .push = xlnx_csu_dma_stream_push,
> +    .can_push = xlnx_csu_dma_stream_can_push,
> +};
> +
> +static const TypeInfo xlnx_csu_dma_info = {
> +    .name          = TYPE_XLNX_CSU_DMA,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(XlnxCSUDMA),
> +    .class_init    = xlnx_csu_dma_class_init,
> +    .class_data    = &xlnx_csu_dma_stream_class,
> +    .instance_init = xlnx_csu_dma_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { TYPE_STREAM_SINK },
> +        { }
> +    }
> +};
> +
> +static void xlnx_csu_dma_register_types(void)
> +{
> +    type_register_static(&xlnx_csu_dma_info);
> +}
> +
> +type_init(xlnx_csu_dma_register_types)
> diff --git a/hw/dma/Kconfig b/hw/dma/Kconfig
> index 5d6be1a..98fbb1b 100644
> --- a/hw/dma/Kconfig
> +++ b/hw/dma/Kconfig
> @@ -26,3 +26,7 @@ config STP2000
>  
>  config SIFIVE_PDMA
>      bool
> +
> +config XLNX_CSU_DMA
> +    bool
> +    select REGISTER
> diff --git a/hw/dma/meson.build b/hw/dma/meson.build
> index 47b4a7c..5c78a4e 100644
> --- a/hw/dma/meson.build
> +++ b/hw/dma/meson.build
> @@ -14,3 +14,4 @@ softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c'))
>  softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_dma.c'))
>  softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c'))
>  softmmu_ss.add(when: 'CONFIG_SIFIVE_PDMA', if_true: files('sifive_pdma.c'))
> +softmmu_ss.add(when: 'CONFIG_XLNX_CSU_DMA', if_true: files('xlnx_csu_dma.c'))
> -- 
> 2.7.4
> 


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

* Re: [PATCH v3 2/5] hw/arm: xlnx-zynqmp: Clean up coding convention issues
  2021-02-10 10:10 ` [PATCH v3 2/5] hw/arm: xlnx-zynqmp: Clean up coding convention issues Bin Meng
@ 2021-02-10 11:54   ` Edgar E. Iglesias
  0 siblings, 0 replies; 11+ messages in thread
From: Edgar E. Iglesias @ 2021-02-10 11:54 UTC (permalink / raw)
  To: Bin Meng
  Cc: Peter Maydell, Xuzhou Cheng, Bin Meng, qemu-devel,
	Francisco Iglesias, qemu-arm, Alistair Francis

On Wed, Feb 10, 2021 at 06:10:10PM +0800, Bin Meng wrote:
> From: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> 
> There are some coding convention warnings in xlnx-zynqmp.c and
> xlnx-zynqmp.h, as reported by:
> 
>   $ ./scripts/checkpatch.pl include/hw/arm/xlnx-zynqmp.h
>   $ ./scripts/checkpatch.pl hw/arm/xlnx-zynqmp.c
> 
> Let's clean them up.
> 
> Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>
> 
> ---
> 
> Changes in v3:
> - new patch: xlnx-zynqmp: Clean up coding convention issues
> 
>  include/hw/arm/xlnx-zynqmp.h |  3 ++-
>  hw/arm/xlnx-zynqmp.c         | 11 +++++++----
>  2 files changed, 9 insertions(+), 5 deletions(-)
> 
> diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
> index 6f45387..be15cc8 100644
> --- a/include/hw/arm/xlnx-zynqmp.h
> +++ b/include/hw/arm/xlnx-zynqmp.h
> @@ -60,7 +60,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP)
>  
>  #define XLNX_ZYNQMP_GIC_REGIONS 6
>  
> -/* ZynqMP maps the ARM GIC regions (GICC, GICD ...) at consecutive 64k offsets
> +/*
> + * ZynqMP maps the ARM GIC regions (GICC, GICD ...) at consecutive 64k offsets
>   * and under-decodes the 64k region. This mirrors the 4k regions to every 4k
>   * aligned address in the 64k region. To implement each GIC region needs a
>   * number of memory region aliases.
> diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
> index 8818472..76b94a5 100644
> --- a/hw/arm/xlnx-zynqmp.c
> +++ b/hw/arm/xlnx-zynqmp.c
> @@ -301,11 +301,13 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
>  
>      ram_size = memory_region_size(s->ddr_ram);
>  
> -    /* Create the DDR Memory Regions. User friendly checks should happen at
> +    /*
> +     * Create the DDR Memory Regions. User friendly checks should happen at
>       * the board level
>       */
>      if (ram_size > XLNX_ZYNQMP_MAX_LOW_RAM_SIZE) {
> -        /* The RAM size is above the maximum available for the low DDR.
> +        /*
> +         * The RAM size is above the maximum available for the low DDR.
>           * Create the high DDR memory region as well.
>           */
>          assert(ram_size <= XLNX_ZYNQMP_MAX_RAM_SIZE);
> @@ -351,7 +353,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
>  
>      qdev_realize(DEVICE(&s->apu_cluster), NULL, &error_fatal);
>  
> -    /* Realize APUs before realizing the GIC. KVM requires this.  */
> +    /* Realize APUs before realizing the GIC. KVM requires this. */

This doesn't look like a checkpatch fix...




>      for (i = 0; i < num_apus; i++) {
>          const char *name;
>  
> @@ -526,7 +528,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
>          SysBusDevice *sbd = SYS_BUS_DEVICE(&s->sdhci[i]);
>          Object *sdhci = OBJECT(&s->sdhci[i]);
>  
> -        /* Compatible with:
> +        /*
> +         * Compatible with:
>           * - SD Host Controller Specification Version 3.00
>           * - SDIO Specification Version 3.0
>           * - eMMC Specification Version 4.51
> -- 
> 2.7.4
> 


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

end of thread, other threads:[~2021-02-10 11:56 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-10 10:10 [PATCH v3 0/5] hw/arm: zynqmp: Implement a CSU DMA model and connect it with GQSPI Bin Meng
2021-02-10 10:10 ` [PATCH v3 1/5] hw/dma: xlnx_csu_dma: Implement a basic XLNX CSU DMA model Bin Meng
2021-02-10 11:52   ` Edgar E. Iglesias
2021-02-10 10:10 ` [PATCH v3 2/5] hw/arm: xlnx-zynqmp: Clean up coding convention issues Bin Meng
2021-02-10 11:54   ` Edgar E. Iglesias
2021-02-10 10:10 ` [PATCH v3 3/5] hw/arm: xlnx-zynqmp: Add XLNX CSU DMA module Bin Meng
2021-02-10 11:38   ` Edgar E. Iglesias
2021-02-10 10:10 ` [PATCH v3 4/5] hw/ssi: xilinx_spips: Clean up coding convention issues Bin Meng
2021-02-10 11:39   ` Edgar E. Iglesias
2021-02-10 10:10 ` [PATCH v3 5/5] hw/ssi: xilinx_spips: Remove DMA related code from zynqmp_qspips Bin Meng
2021-02-10 11:39   ` Edgar E. Iglesias

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.