aboutsummaryrefslogtreecommitdiff
path: root/drivers/dma/sh
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/sh')
-rw-r--r--drivers/dma/sh/rcar-dmac.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index bb93038c48b9..711da01a200b 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -325,6 +325,8 @@ static void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan)
rcar_dmac_chan_write(chan, RCAR_DMARS, chan->mid_rid);
if (desc->hwdescs.use) {
+ struct rcar_dmac_xfer_chunk *chunk;
+
dev_dbg(chan->chan.device->dev,
"chan%u: queue desc %p: %u@%pad\n",
chan->index, desc, desc->nchunks, &desc->hwdescs.dma);
@@ -341,6 +343,18 @@ static void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan)
RCAR_DMACHCRB_DRST);
/*
+ * Errata: When descriptor memory is accessed through an IOMMU
+ * the DMADAR register isn't initialized automatically from the
+ * first descriptor at beginning of transfer by the DMAC like it
+ * should. Initialize it manually with the destination address
+ * of the first chunk.
+ */
+ chunk = list_first_entry(&desc->chunks,
+ struct rcar_dmac_xfer_chunk, node);
+ rcar_dmac_chan_write(chan, RCAR_DMADAR,
+ chunk->dst_addr & 0xffffffff);
+
+ /*
* Program the descriptor stage interrupt to occur after the end
* of the first stage.
*/