dmaengine: fsl-edma-v3: dynamic change burst length
authorRobin Gong <yibin.gong@nxp.com>
Fri, 22 May 2020 14:00:28 +0000 (22:00 +0800)
committerRobin Gong <yibin.gong@nxp.com>
Wed, 21 Apr 2021 17:27:35 +0000 (01:27 +0800)
Dynamic change burst length in case transfer length is not multiple of
burst length to  meet the edmav3 hardware limitation.

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
(cherry picked from commit 4b92c1194ba9f1c6f6d9a6f13a09639323787ce9)

drivers/dma/fsl-edma-v3.c

index c38256c..a14bee2 100644 (file)
@@ -590,6 +590,26 @@ static struct dma_async_tx_descriptor *fsl_edma3_prep_dma_cyclic(
 
        dma_buf_next = dma_addr;
        nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
+
+       /*
+        * Choose the suitable burst length if period_len is not multiple of
+        * burst length so that the whole transfer length is multiple of minor
+        * loop(burst length).
+        */
+       if (period_len % nbytes) {
+               u32 width = fsl_chan->fsc.addr_width;
+
+               for (i = fsl_chan->fsc.burst; i > 1; i--) {
+                       if (!(period_len % (i * width))) {
+                               nbytes = i * width;
+                               break;
+                       }
+               }
+               /* if no chance to get suitable burst size, use it as 1 */
+               if (i == 1)
+                       nbytes = width;
+       }
+
        iter = period_len / nbytes;
 
        for (i = 0; i < sg_len; i++) {
@@ -676,6 +696,26 @@ static struct dma_async_tx_descriptor *fsl_edma3_prep_slave_sg(
                        doff = 0;
                }
 
+               /*
+                * Choose the suitable burst length if sg_dma_len is not
+                * multiple of burst length so that the whole transfer length is
+                * multiple of minor loop(burst length).
+                */
+               if (sg_dma_len(sg) % nbytes) {
+                       u32 width = fsl_chan->fsc.addr_width;
+                       int j;
+
+                       for (j = fsl_chan->fsc.burst; j > 1; j--) {
+                               if (!(sg_dma_len(sg) % (j * width))) {
+                                       nbytes = j * width;
+                                       break;
+                               }
+                       }
+                       /* Set burst size as 1 if there's no suitable one */
+                       if (j == 1)
+                               nbytes = width;
+               }
+
                iter = sg_dma_len(sg) / nbytes;
                if (i < sg_len - 1) {
                        last_sg = fsl_desc->tcd[(i + 1)].ptcd;