diff options
author | Frank Chang <frank.chang@sifive.com> | 2021-09-12 21:05:45 +0800 |
---|---|---|
committer | Alistair Francis <alistair.francis@wdc.com> | 2021-09-21 07:56:49 +1000 |
commit | de7c7988d25d3e0abfad11261b21a21d40ce255f (patch) | |
tree | 37196ab749e9f7cdd883e9bd6cdb628462261bb9 | |
parent | 954886ea6dd496ad259f8c576a8767e1d7059a28 (diff) | |
download | qemu-de7c7988d25d3e0abfad11261b21a21d40ce255f.zip qemu-de7c7988d25d3e0abfad11261b21a21d40ce255f.tar.gz qemu-de7c7988d25d3e0abfad11261b21a21d40ce255f.tar.bz2 |
hw/dma: sifive_pdma: reset Next* registers when Control.claim is set
Setting Control.claim clears all of the chanel's Next registers.
This is effective only when Control.claim is set from 0 to 1.
Signed-off-by: Frank Chang <frank.chang@sifive.com>
Tested-by: Max Hsu <max.hsu@sifive.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Message-id: 20210912130553.179501-2-frank.chang@sifive.com
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
-rw-r--r-- | hw/dma/sifive_pdma.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/hw/dma/sifive_pdma.c b/hw/dma/sifive_pdma.c index 9b2ac20..d92e27d 100644 --- a/hw/dma/sifive_pdma.c +++ b/hw/dma/sifive_pdma.c @@ -54,6 +54,13 @@ #define DMA_EXEC_DST 0x110 #define DMA_EXEC_SRC 0x118 +/* + * FU540/FU740 docs are incorrect with NextConfig.wsize/rsize reset values. + * The reset values tested on Unleashed/Unmatched boards are 6 instead of 0. + */ +#define CONFIG_WRSZ_DEFAULT 6 +#define CONFIG_RDSZ_DEFAULT 6 + enum dma_chan_state { DMA_CHAN_STATE_IDLE, DMA_CHAN_STATE_STARTED, @@ -221,6 +228,7 @@ static void sifive_pdma_write(void *opaque, hwaddr offset, { SiFivePDMAState *s = opaque; int ch = SIFIVE_PDMA_CHAN_NO(offset); + bool claimed; if (ch >= SIFIVE_PDMA_CHANS) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n", @@ -231,6 +239,17 @@ static void sifive_pdma_write(void *opaque, hwaddr offset, offset &= 0xfff; switch (offset) { case DMA_CONTROL: + claimed = !!s->chan[ch].control & CONTROL_CLAIM; + + if (!claimed && (value & CONTROL_CLAIM)) { + /* reset Next* registers */ + s->chan[ch].next_config = (CONFIG_RDSZ_DEFAULT << CONFIG_RDSZ_SHIFT) | + (CONFIG_WRSZ_DEFAULT << CONFIG_WRSZ_SHIFT); + s->chan[ch].next_bytes = 0; + s->chan[ch].next_dst = 0; + s->chan[ch].next_src = 0; + } + s->chan[ch].control = value; if (value & CONTROL_RUN) { |