aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/dma/sifive_pdma.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/hw/dma/sifive_pdma.c b/hw/dma/sifive_pdma.c
index b8ec762..85fe34f 100644
--- a/hw/dma/sifive_pdma.c
+++ b/hw/dma/sifive_pdma.c
@@ -232,7 +232,7 @@ static void sifive_pdma_write(void *opaque, hwaddr offset,
{
SiFivePDMAState *s = opaque;
int ch = SIFIVE_PDMA_CHAN_NO(offset);
- bool claimed;
+ bool claimed, run;
if (ch >= SIFIVE_PDMA_CHANS) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
@@ -244,6 +244,7 @@ static void sifive_pdma_write(void *opaque, hwaddr offset,
switch (offset) {
case DMA_CONTROL:
claimed = !!(s->chan[ch].control & CONTROL_CLAIM);
+ run = !!(s->chan[ch].control & CONTROL_RUN);
if (!claimed && (value & CONTROL_CLAIM)) {
/* reset Next* registers */
@@ -254,13 +255,19 @@ static void sifive_pdma_write(void *opaque, hwaddr offset,
s->chan[ch].next_src = 0;
}
+ /* claim bit can only be cleared when run is low */
+ if (run && !(value & CONTROL_CLAIM)) {
+ value |= CONTROL_CLAIM;
+ }
+
s->chan[ch].control = value;
/*
* If channel was not claimed before run bit is set,
+ * or if the channel is disclaimed when run was low,
* DMA won't run.
*/
- if (!claimed) {
+ if (!claimed || (!run && !(value & CONTROL_CLAIM))) {
s->chan[ch].control &= ~CONTROL_RUN;
return;
}