aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/dma/sh/rcar-dmac.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 54810ffd95e2..e2a5398f89b5 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -1282,6 +1282,9 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
1282 enum dma_status status; 1282 enum dma_status status;
1283 unsigned int residue = 0; 1283 unsigned int residue = 0;
1284 unsigned int dptr = 0; 1284 unsigned int dptr = 0;
1285 unsigned int chcrb;
1286 unsigned int tcrb;
1287 unsigned int i;
1285 1288
1286 if (!desc) 1289 if (!desc)
1287 return 0; 1290 return 0;
@@ -1330,14 +1333,31 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
1330 } 1333 }
1331 1334
1332 /* 1335 /*
1336 * We need to read two registers.
1337 * Make sure the control register does not skip to next chunk
1338 * while reading the counter.
1339 * Trying it 3 times should be enough: Initial read, retry, retry
1340 * for the paranoid.
1341 */
1342 for (i = 0; i < 3; i++) {
1343 chcrb = rcar_dmac_chan_read(chan, RCAR_DMACHCRB) &
1344 RCAR_DMACHCRB_DPTR_MASK;
1345 tcrb = rcar_dmac_chan_read(chan, RCAR_DMATCRB);
1346 /* Still the same? */
1347 if (chcrb == (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) &
1348 RCAR_DMACHCRB_DPTR_MASK))
1349 break;
1350 }
1351 WARN_ONCE(i >= 3, "residue might be not continuous!");
1352
1353 /*
1333 * In descriptor mode the descriptor running pointer is not maintained 1354 * In descriptor mode the descriptor running pointer is not maintained
1334 * by the interrupt handler, find the running descriptor from the 1355 * by the interrupt handler, find the running descriptor from the
1335 * descriptor pointer field in the CHCRB register. In non-descriptor 1356 * descriptor pointer field in the CHCRB register. In non-descriptor
1336 * mode just use the running descriptor pointer. 1357 * mode just use the running descriptor pointer.
1337 */ 1358 */
1338 if (desc->hwdescs.use) { 1359 if (desc->hwdescs.use) {
1339 dptr = (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) & 1360 dptr = chcrb >> RCAR_DMACHCRB_DPTR_SHIFT;
1340 RCAR_DMACHCRB_DPTR_MASK) >> RCAR_DMACHCRB_DPTR_SHIFT;
1341 if (dptr == 0) 1361 if (dptr == 0)
1342 dptr = desc->nchunks; 1362 dptr = desc->nchunks;
1343 dptr--; 1363 dptr--;
@@ -1355,7 +1375,7 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
1355 } 1375 }
1356 1376
1357 /* Add the residue for the current chunk. */ 1377 /* Add the residue for the current chunk. */
1358 residue += rcar_dmac_chan_read(chan, RCAR_DMATCRB) << desc->xfer_shift; 1378 residue += tcrb << desc->xfer_shift;
1359 1379
1360 return residue; 1380 return residue;
1361} 1381}