* [PATCH 0/2] hw/ssi: xilinx_spips: Implement basic QSPI DMA support @ 2021-02-06 14:38 Bin Meng 2021-02-06 14:38 ` [PATCH 1/2] hw/ssi: xilinx_spips: Clean up coding convention issues Bin Meng 2021-02-06 14:38 ` [PATCH 2/2] hw/ssi: xilinx_spips: Implement basic QSPI DMA support Bin Meng 0 siblings, 2 replies; 7+ messages in thread From: Bin Meng @ 2021-02-06 14:38 UTC (permalink / raw) To: Alistair Francis, Edgar E . Iglesias, Peter Maydell, qemu-arm, qemu-devel Cc: Bin Meng 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. Add a basic implementation of QSPI DMA functionality. Xuzhou Cheng (2): hw/ssi: xilinx_spips: Clean up coding convention issues hw/ssi: xilinx_spips: Implement basic QSPI DMA support hw/ssi/xilinx_spips.c | 211 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 183 insertions(+), 28 deletions(-) -- 2.7.4 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/2] hw/ssi: xilinx_spips: Clean up coding convention issues 2021-02-06 14:38 [PATCH 0/2] hw/ssi: xilinx_spips: Implement basic QSPI DMA support Bin Meng @ 2021-02-06 14:38 ` Bin Meng 2021-02-06 15:18 ` Peter Maydell 2021-02-06 17:01 ` Philippe Mathieu-Daudé 2021-02-06 14:38 ` [PATCH 2/2] hw/ssi: xilinx_spips: Implement basic QSPI DMA support Bin Meng 1 sibling, 2 replies; 7+ messages in thread From: Bin Meng @ 2021-02-06 14:38 UTC (permalink / raw) To: Alistair Francis, Edgar E . Iglesias, Peter Maydell, qemu-arm, qemu-devel Cc: Xuzhou Cheng, Bin Meng 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> --- 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] 7+ messages in thread
* Re: [PATCH 1/2] hw/ssi: xilinx_spips: Clean up coding convention issues 2021-02-06 14:38 ` [PATCH 1/2] hw/ssi: xilinx_spips: Clean up coding convention issues Bin Meng @ 2021-02-06 15:18 ` Peter Maydell 2021-02-06 17:01 ` Philippe Mathieu-Daudé 1 sibling, 0 replies; 7+ messages in thread From: Peter Maydell @ 2021-02-06 15:18 UTC (permalink / raw) To: Bin Meng Cc: Xuzhou Cheng, Bin Meng, QEMU Developers, qemu-arm, Alistair Francis, Edgar E . Iglesias On Sat, 6 Feb 2021 at 14:38, Bin Meng <bmeng.cn@gmail.com> 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: Peter Maydell <peter.maydell@linaro.org> thanks -- PMM ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] hw/ssi: xilinx_spips: Clean up coding convention issues 2021-02-06 14:38 ` [PATCH 1/2] hw/ssi: xilinx_spips: Clean up coding convention issues Bin Meng 2021-02-06 15:18 ` Peter Maydell @ 2021-02-06 17:01 ` Philippe Mathieu-Daudé 1 sibling, 0 replies; 7+ messages in thread From: Philippe Mathieu-Daudé @ 2021-02-06 17:01 UTC (permalink / raw) To: Bin Meng, Alistair Francis, Edgar E . Iglesias, Peter Maydell, qemu-arm, qemu-devel Cc: Xuzhou Cheng, Bin Meng On 2/6/21 3:38 PM, 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> > --- > > hw/ssi/xilinx_spips.c | 23 ++++++++++++++--------- > 1 file changed, 14 insertions(+), 9 deletions(-) Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/2] hw/ssi: xilinx_spips: Implement basic QSPI DMA support 2021-02-06 14:38 [PATCH 0/2] hw/ssi: xilinx_spips: Implement basic QSPI DMA support Bin Meng 2021-02-06 14:38 ` [PATCH 1/2] hw/ssi: xilinx_spips: Clean up coding convention issues Bin Meng @ 2021-02-06 14:38 ` Bin Meng 2021-02-06 15:28 ` Peter Maydell 1 sibling, 1 reply; 7+ messages in thread From: Bin Meng @ 2021-02-06 14:38 UTC (permalink / raw) To: Alistair Francis, Edgar E . Iglesias, Peter Maydell, qemu-arm, qemu-devel Cc: Xuzhou Cheng, Bin Meng 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. Add a basic implementation of QSPI DMA functionality. Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com> Signed-off-by: Bin Meng <bin.meng@windriver.com> --- hw/ssi/xilinx_spips.c | 188 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 169 insertions(+), 19 deletions(-) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 8a0cc22..57ab9a3 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -195,12 +195,72 @@ #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) +#define GQSPI_CNFG_MODE_EN_IO (0) +#define GQSPI_CNFG_MODE_EN_DMA (2) + +/* + * Ref: UG1087 (v1.7) February 8, 2019 + * https://www.xilinx.com/html_docs/registers/ug1087/ug1087-zynq-ultrascale-registers.html + */ +REG32(GQSPI_DMA_ADDR, 0x800) + FIELD(GQSPI_DMA_ADDR, ADDR, 2, 30) +REG32(GQSPI_DMA_SIZE, 0x804) + FIELD(GQSPI_DMA_SIZE, SIZE, 2, 27) +REG32(GQSPI_DMA_STS, 0x808) + FIELD(GQSPI_DMA_STS, DONE_CNT, 13, 3) + FIELD(GQSPI_DMA_STS, BUSY, 0, 1) +REG32(GQSPI_DMA_CTRL, 0x80c) + FIELD(GQSPI_DMA_CTRL, FIFO_LVL_HIT_THRESH, 25, 7) + FIELD(GQSPI_DMA_CTRL, APB_ERR_RESP, 24, 1) + FIELD(GQSPI_DMA_CTRL, ENDIANNESS, 23, 1) + FIELD(GQSPI_DMA_CTRL, AXI_BRST_TYPE, 22, 1) + FIELD(GQSPI_DMA_CTRL, TIMEOUT_VAL, 10, 12) + FIELD(GQSPI_DMA_CTRL, FIFO_THRESH, 2, 8) + FIELD(GQSPI_DMA_CTRL, PAUSE_STRM, 1, 1) + FIELD(GQSPI_DMA_CTRL, PAUSE_MEM, 0, 1) +REG32(GQSPI_DMA_I_STS, 0x814) + FIELD(GQSPI_DMA_I_STS, FIFO_OVERFLOW, 7, 1) + FIELD(GQSPI_DMA_I_STS, INVALID_APB, 6, 1) + FIELD(GQSPI_DMA_I_STS, THRESH_HIT, 5, 1) + FIELD(GQSPI_DMA_I_STS, TIMEOUT_MEM, 4, 1) + FIELD(GQSPI_DMA_I_STS, TIMEOUT_STRM, 3, 1) + FIELD(GQSPI_DMA_I_STS, AXI_BRESP_ERR, 2, 1) + FIELD(GQSPI_DMA_I_STS, DONE, 1, 1) +REG32(GQSPI_DMA_I_EN, 0x818) + FIELD(GQSPI_DMA_I_EN, FIFO_OVERFLOW, 7, 1) + FIELD(GQSPI_DMA_I_EN, INVALID_APB, 6, 1) + FIELD(GQSPI_DMA_I_EN, THRESH_HIT, 5, 1) + FIELD(GQSPI_DMA_I_EN, TIMEOUT_MEM, 4, 1) + FIELD(GQSPI_DMA_I_EN, TIMEOUT_STRM, 3, 1) + FIELD(GQSPI_DMA_I_EN, AXI_BRESP_ERR, 2, 1) + FIELD(GQSPI_DMA_I_EN, DONE, 1, 1) +REG32(GQSPI_DMA_I_DIS, 0x81c) + FIELD(GQSPI_DMA_I_DIS, FIFO_OVERFLOW, 7, 1) + FIELD(GQSPI_DMA_I_DIS, INVALID_APB, 6, 1) + FIELD(GQSPI_DMA_I_DIS, THRESH_HIT, 5, 1) + FIELD(GQSPI_DMA_I_DIS, TIMEOUT_MEM, 4, 1) + FIELD(GQSPI_DMA_I_DIS, TIMEOUT_STRM, 3, 1) + FIELD(GQSPI_DMA_I_DIS, AXI_BRESP_ERR, 2, 1) + FIELD(GQSPI_DMA_I_DIS, DONE, 1, 1) +REG32(GQSPI_DMA_I_MASK, 0x820) + FIELD(GQSPI_DMA_I_MASK, FIFO_OVERFLOW, 7, 1) + FIELD(GQSPI_DMA_I_MASK, INVALID_APB, 6, 1) + FIELD(GQSPI_DMA_I_MASK, THRESH_HIT, 5, 1) + FIELD(GQSPI_DMA_I_MASK, TIMEOUT_MEM, 4, 1) + FIELD(GQSPI_DMA_I_MASK, TIMEOUT_STRM, 3, 1) + FIELD(GQSPI_DMA_I_MASK, AXI_BRESP_ERR, 2, 1) + FIELD(GQSPI_DMA_I_MASK, DONE, 1, 1) +REG32(GQSPI_DMA_CTRL2, 0x824) + FIELD(GQSPI_DMA_CTRL2, ARCACHE, 24, 3) + FIELD(GQSPI_DMA_CTRL2, TIMEOUT_EN, 22, 1) + FIELD(GQSPI_DMA_CTRL2, TIMEOUT_PRE, 4, 12) + FIELD(GQSPI_DMA_CTRL2, MAX_OUTS_CMDS, 0, 4) +REG32(GQSPI_DMA_ADDR_MSB, 0x828) + FIELD(GQSPI_DMA_ADDR_MSB, ADDR_MSB, 0, 12) + +#define R_GQSPI_DMA_CTRL_RESET (0x803ffa00) +#define R_GQSPI_DMA_INT_MASK (0xfe) +#define R_GQSPI_DMA_CTRL2_RESET (0x081bfff8) /* size of TXRX FIFOs */ #define RXFF_A (128) @@ -341,6 +401,7 @@ static void xilinx_spips_update_ixr(XilinxSPIPS *s) static void xlnx_zynqmp_qspips_update_ixr(XlnxZynqMPQSPIPS *s) { uint32_t gqspi_int; + uint32_t mode; int new_irqline; s->regs[R_GQSPI_ISR] &= ~IXR_SELF_CLEAR; @@ -359,13 +420,20 @@ static void xlnx_zynqmp_qspips_update_ixr(XlnxZynqMPQSPIPS *s) IXR_TX_FIFO_NOT_FULL : 0); /* GQSPI Interrupt Trigger Status */ - gqspi_int = (~s->regs[R_GQSPI_IMR]) & s->regs[R_GQSPI_ISR] & GQSPI_IXR_MASK; - new_irqline = !!(gqspi_int & IXR_ALL); - - /* drive external interrupt pin */ - if (new_irqline != s->gqspi_irqline) { - s->gqspi_irqline = new_irqline; - qemu_set_irq(XILINX_SPIPS(s)->irq, s->gqspi_irqline); + mode = ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, MODE_EN); + if (mode == GQSPI_CNFG_MODE_EN_IO) { + gqspi_int = (~s->regs[R_GQSPI_IMR]) & s->regs[R_GQSPI_ISR] \ + & GQSPI_IXR_MASK; + new_irqline = !!(gqspi_int & IXR_ALL); + + /* drive external interrupt pin */ + if (new_irqline != s->gqspi_irqline) { + s->gqspi_irqline = new_irqline; + qemu_set_irq(XILINX_SPIPS(s)->irq, s->gqspi_irqline); + } + } else if (mode == GQSPI_CNFG_MODE_EN_DMA) { + new_irqline = s->regs[R_GQSPI_DMA_I_STS] & ~s->regs[R_GQSPI_DMA_I_MASK]; + qemu_set_irq(XILINX_SPIPS(s)->irq, !!new_irqline); } } @@ -417,9 +485,9 @@ 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->regs[R_GQSPI_DMA_CTRL] = R_GQSPI_DMA_CTRL_RESET; + s->regs[R_GQSPI_DMA_I_MASK] = R_GQSPI_DMA_INT_MASK; + s->regs[R_GQSPI_DMA_CTRL2] = R_GQSPI_DMA_CTRL2_RESET; s->man_start_com_g = false; s->gqspi_irqline = 0; xlnx_zynqmp_qspips_update_ixr(s); @@ -843,6 +911,62 @@ static const void *pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num) return ret; } +static void xlnx_zynqmp_gspips_dma_done(XlnxZynqMPQSPIPS *s) +{ + int cnt; + + s->regs[R_GQSPI_DMA_STS] &= ~R_GQSPI_DMA_STS_BUSY_MASK; + s->regs[R_GQSPI_DMA_I_STS] |= R_GQSPI_DMA_I_STS_DONE_MASK; + + cnt = ARRAY_FIELD_EX32(s->regs, GQSPI_DMA_STS, DONE_CNT) + 1; + ARRAY_FIELD_DP32(s->regs, GQSPI_DMA_STS, DONE_CNT, cnt); + +} + +static uint32_t xlnx_zynqmp_gspips_dma_advance(XlnxZynqMPQSPIPS *s, + uint32_t len, hwaddr dst) +{ + uint32_t size = s->regs[R_GQSPI_DMA_SIZE]; + + size -= len; + size &= R_GQSPI_DMA_SIZE_SIZE_MASK; + dst += len; + + s->regs[R_GQSPI_DMA_SIZE] = size; + s->regs[R_GQSPI_DMA_ADDR] = (uint32_t) dst; + s->regs[R_GQSPI_DMA_ADDR_MSB] = dst >> 32; + + return size; +} + +static size_t xlnx_zynqmp_gspips_dma_push(XlnxZynqMPQSPIPS *s, + uint8_t *buf, size_t len, bool eop) +{ + hwaddr dst = (hwaddr)s->regs[R_GQSPI_DMA_ADDR_MSB] << 32 + | s->regs[R_GQSPI_DMA_ADDR]; + uint32_t size = s->regs[R_GQSPI_DMA_SIZE]; + uint32_t mlen = MIN(size, len) & (~3); /* Size is word aligned */ + + if (size == 0 || len <= 0) { + return 0; + } + + cpu_physical_memory_write(dst, buf, mlen); + size = xlnx_zynqmp_gspips_dma_advance(s, mlen, dst); + + if (size == 0) { + xlnx_zynqmp_gspips_dma_done(s); + xlnx_zynqmp_qspips_update_ixr(s); + } + + return mlen; +} + +static bool xlnx_zynqmp_gspips_dma_can_push(XlnxZynqMPQSPIPS *s) +{ + return s->regs[R_GQSPI_DMA_SIZE] ? true : false; +} + static void xlnx_zynqmp_qspips_notify(void *opaque) { XlnxZynqMPQSPIPS *rq = XLNX_ZYNQMP_QSPIPS(opaque); @@ -850,7 +974,8 @@ static void xlnx_zynqmp_qspips_notify(void *opaque) Fifo8 *recv_fifo; if (ARRAY_FIELD_EX32(rq->regs, GQSPI_SELECT, GENERIC_QSPI_EN)) { - if (!(ARRAY_FIELD_EX32(rq->regs, GQSPI_CNFG, MODE_EN) == 2)) { + if (ARRAY_FIELD_EX32(rq->regs, GQSPI_CNFG, MODE_EN) + != GQSPI_CNFG_MODE_EN_DMA) { return; } recv_fifo = &rq->rx_fifo_g; @@ -861,7 +986,7 @@ static void xlnx_zynqmp_qspips_notify(void *opaque) recv_fifo = &s->rx_fifo; } while (recv_fifo->num >= 4 - && stream_can_push(rq->dma, xlnx_zynqmp_qspips_notify, rq)) + && xlnx_zynqmp_gspips_dma_can_push(rq)) { size_t ret; uint32_t num; @@ -874,7 +999,7 @@ static void xlnx_zynqmp_qspips_notify(void *opaque) memcpy(rq->dma_buf, rxd, num); - ret = stream_push(rq->dma, rq->dma_buf, num, false); + ret = xlnx_zynqmp_gspips_dma_push(rq, rq->dma_buf, num, false); assert(ret == num); xlnx_zynqmp_qspips_check_flush(rq); } @@ -1127,6 +1252,31 @@ static void xlnx_zynqmp_qspips_write(void *opaque, hwaddr addr, case R_GQSPI_GF_SNAPSHOT: case R_GQSPI_MOD_ID: break; + case R_GQSPI_DMA_ADDR: + s->regs[R_GQSPI_DMA_ADDR] = value & R_GQSPI_DMA_ADDR_ADDR_MASK; + break; + case R_GQSPI_DMA_SIZE: + s->regs[R_GQSPI_DMA_SIZE] = value & R_GQSPI_DMA_SIZE_SIZE_MASK; + break; + case R_GQSPI_DMA_STS: + s->regs[R_GQSPI_DMA_STS] &= ~(value & + R_GQSPI_DMA_STS_DONE_CNT_MASK); + break; + case R_GQSPI_DMA_I_EN: + s->regs[R_GQSPI_DMA_I_EN] = value & R_GQSPI_DMA_INT_MASK; + s->regs[R_GQSPI_DMA_I_MASK] &= ~s->regs[R_GQSPI_DMA_I_EN]; + s->regs[R_GQSPI_DMA_I_DIS] &= ~s->regs[R_GQSPI_DMA_I_EN]; + break; + case R_GQSPI_DMA_I_DIS: + s->regs[R_GQSPI_DMA_I_DIS] |= value & R_GQSPI_DMA_INT_MASK; + s->regs[R_GQSPI_DMA_I_MASK] |= s->regs[R_GQSPI_DMA_I_DIS]; + s->regs[R_GQSPI_DMA_I_EN] &= ~s->regs[R_GQSPI_DMA_I_DIS]; + s->regs[R_GQSPI_DMA_STS] &= 0; + break; + case R_GQSPI_DMA_ADDR_MSB: + s->regs[R_GQSPI_DMA_ADDR_MSB] = value & + R_GQSPI_DMA_ADDR_MSB_ADDR_MSB_MASK; + break; default: s->regs[reg] = value; break; -- 2.7.4 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] hw/ssi: xilinx_spips: Implement basic QSPI DMA support 2021-02-06 14:38 ` [PATCH 2/2] hw/ssi: xilinx_spips: Implement basic QSPI DMA support Bin Meng @ 2021-02-06 15:28 ` Peter Maydell 2021-02-07 15:46 ` Bin Meng 0 siblings, 1 reply; 7+ messages in thread From: Peter Maydell @ 2021-02-06 15:28 UTC (permalink / raw) To: Bin Meng Cc: Xuzhou Cheng, Bin Meng, QEMU Developers, qemu-arm, Alistair Francis, Edgar E . Iglesias On Sat, 6 Feb 2021 at 14:38, Bin Meng <bmeng.cn@gmail.com> 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. > > Add a basic implementation of QSPI DMA functionality. > > Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com> > Signed-off-by: Bin Meng <bin.meng@windriver.com> > +static size_t xlnx_zynqmp_gspips_dma_push(XlnxZynqMPQSPIPS *s, > + uint8_t *buf, size_t len, bool eop) > +{ > + hwaddr dst = (hwaddr)s->regs[R_GQSPI_DMA_ADDR_MSB] << 32 > + | s->regs[R_GQSPI_DMA_ADDR]; > + uint32_t size = s->regs[R_GQSPI_DMA_SIZE]; > + uint32_t mlen = MIN(size, len) & (~3); /* Size is word aligned */ > + > + if (size == 0 || len <= 0) { > + return 0; > + } > + > + cpu_physical_memory_write(dst, buf, mlen); > + size = xlnx_zynqmp_gspips_dma_advance(s, mlen, dst); > + > + if (size == 0) { > + xlnx_zynqmp_gspips_dma_done(s); > + xlnx_zynqmp_qspips_update_ixr(s); > + } > + > + return mlen; > +} > @@ -861,7 +986,7 @@ static void xlnx_zynqmp_qspips_notify(void *opaque) > recv_fifo = &s->rx_fifo; > } > while (recv_fifo->num >= 4 > - && stream_can_push(rq->dma, xlnx_zynqmp_qspips_notify, rq)) > + && xlnx_zynqmp_gspips_dma_can_push(rq)) > { > size_t ret; > uint32_t num; > @@ -874,7 +999,7 @@ static void xlnx_zynqmp_qspips_notify(void *opaque) > > memcpy(rq->dma_buf, rxd, num); > > - ret = stream_push(rq->dma, rq->dma_buf, num, false); > + ret = xlnx_zynqmp_gspips_dma_push(rq, rq->dma_buf, num, false); > assert(ret == num); > xlnx_zynqmp_qspips_check_flush(rq); > } This seems to be removing the existing handling of DMA to the TYPE_STREAM_SINK via the stream_* functions -- that doesn't look right. I don't know any of the details of this device, but if it has two different modes of DMA then we need to support both of them, surely ? If the device really should be doing its own DMA memory accesses, please don't use cpu_physical_memory_write() for this. The device should take a TYPE_MEMORY_REGION link property, and the board code should set this to tell the device what its view of the world that it is doing DMA to is. Then the device in its realize method calls address_space_init() to create an AddressSpace for this MemoryRegion, and does memory accesses using functions like address_space_read()/address_space_write()/ address_space_ld*()/etc. (Examples in hw/dma, eg pl080.c.) Note that the address_space* functions have a return value indicating whether the access failed, which you should handle. (The pl080 code doesn't do that, but that's because it's older code.) thanks -- PMM ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] hw/ssi: xilinx_spips: Implement basic QSPI DMA support 2021-02-06 15:28 ` Peter Maydell @ 2021-02-07 15:46 ` Bin Meng 0 siblings, 0 replies; 7+ messages in thread From: Bin Meng @ 2021-02-07 15:46 UTC (permalink / raw) To: Peter Maydell Cc: Xuzhou Cheng, Bin Meng, QEMU Developers, qemu-arm, Alistair Francis, Edgar E . Iglesias Hi Peter, On Sat, Feb 6, 2021 at 11:28 PM Peter Maydell <peter.maydell@linaro.org> wrote: > > On Sat, 6 Feb 2021 at 14:38, Bin Meng <bmeng.cn@gmail.com> 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. > > > > Add a basic implementation of QSPI DMA functionality. > > > > Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com> > > Signed-off-by: Bin Meng <bin.meng@windriver.com> > > > +static size_t xlnx_zynqmp_gspips_dma_push(XlnxZynqMPQSPIPS *s, > > + uint8_t *buf, size_t len, bool eop) > > +{ > > + hwaddr dst = (hwaddr)s->regs[R_GQSPI_DMA_ADDR_MSB] << 32 > > + | s->regs[R_GQSPI_DMA_ADDR]; > > + uint32_t size = s->regs[R_GQSPI_DMA_SIZE]; > > + uint32_t mlen = MIN(size, len) & (~3); /* Size is word aligned */ > > + > > + if (size == 0 || len <= 0) { > > + return 0; > > + } > > + > > + cpu_physical_memory_write(dst, buf, mlen); > > + size = xlnx_zynqmp_gspips_dma_advance(s, mlen, dst); > > + > > + if (size == 0) { > > + xlnx_zynqmp_gspips_dma_done(s); > > + xlnx_zynqmp_qspips_update_ixr(s); > > + } > > + > > + return mlen; > > +} > > > @@ -861,7 +986,7 @@ static void xlnx_zynqmp_qspips_notify(void *opaque) > > recv_fifo = &s->rx_fifo; > > } > > while (recv_fifo->num >= 4 > > - && stream_can_push(rq->dma, xlnx_zynqmp_qspips_notify, rq)) > > + && xlnx_zynqmp_gspips_dma_can_push(rq)) > > { > > size_t ret; > > uint32_t num; > > @@ -874,7 +999,7 @@ static void xlnx_zynqmp_qspips_notify(void *opaque) > > > > memcpy(rq->dma_buf, rxd, num); > > > > - ret = stream_push(rq->dma, rq->dma_buf, num, false); > > + ret = xlnx_zynqmp_gspips_dma_push(rq, rq->dma_buf, num, false); > > assert(ret == num); > > xlnx_zynqmp_qspips_check_flush(rq); > > } > > This seems to be removing the existing handling of DMA to the > TYPE_STREAM_SINK via the stream_* functions -- that doesn't look > right. I don't know any of the details of this device, but if it > has two different modes of DMA then we need to support both of them, > surely ? This DMA engine is a built-in engine dedicated for QSPI so I think there is no need to use the stream_* functions. > If the device really should be doing its own DMA memory > accesses, please don't use cpu_physical_memory_write() for > this. The device should take a TYPE_MEMORY_REGION link property, > and the board code should set this to tell the device what > its view of the world that it is doing DMA to is. Then the > device in its realize method calls address_space_init() to create > an AddressSpace for this MemoryRegion, and does memory accesses > using functions like address_space_read()/address_space_write()/ > address_space_ld*()/etc. (Examples in hw/dma, eg pl080.c.) > Note that the address_space* functions have a return value > indicating whether the access failed, which you should handle. > (The pl080 code doesn't do that, but that's because it's older code.) Sure will switch to use DMA AddressSpace in v2. Regards, Bin ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2021-02-07 15:48 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2021-02-06 14:38 [PATCH 0/2] hw/ssi: xilinx_spips: Implement basic QSPI DMA support Bin Meng 2021-02-06 14:38 ` [PATCH 1/2] hw/ssi: xilinx_spips: Clean up coding convention issues Bin Meng 2021-02-06 15:18 ` Peter Maydell 2021-02-06 17:01 ` Philippe Mathieu-Daudé 2021-02-06 14:38 ` [PATCH 2/2] hw/ssi: xilinx_spips: Implement basic QSPI DMA support Bin Meng 2021-02-06 15:28 ` Peter Maydell 2021-02-07 15:46 ` Bin Meng
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).