{
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",
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 */
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;
}