dmaengine: fsl-edma: read/write multiple registers in cyclic transactions
authorLarisa Grigore <larisa.grigore@oss.nxp.com>
Thu, 19 Dec 2024 10:24:14 +0000 (12:24 +0200)
committerVinod Koul <vkoul@kernel.org>
Tue, 24 Dec 2024 09:44:13 +0000 (15:14 +0530)
Add support for reading multiple registers in DEV_TO_MEM transactions and
for writing multiple registers in MEM_TO_DEV transactions.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
Co-developed-by: Alexandru-Catalin Ionita <alexandru-catalin.ionita@nxp.com>
Signed-off-by: Alexandru-Catalin Ionita <alexandru-catalin.ionita@nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
Link: https://lore.kernel.org/r/20241219102415.1208328-6-larisa.grigore@oss.nxp.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/fsl-edma-common.c

index b7f15ab96855dea94538da29a8c6d013c0697507..443b2430466cbcf32c9bd8d487abd27fa19718b6 100644 (file)
@@ -480,8 +480,8 @@ void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan,
                       bool disable_req, bool enable_sg)
 {
        struct dma_slave_config *cfg = &fsl_chan->cfg;
+       u32 burst = 0;
        u16 csr = 0;
-       u32 burst;
 
        /*
         * eDMA hardware SGs require the TCDs to be stored in little
@@ -496,16 +496,30 @@ void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan,
 
        fsl_edma_set_tcd_to_le(fsl_chan, tcd, soff, soff);
 
-       if (fsl_chan->is_multi_fifo) {
-               /* set mloff to support multiple fifo */
-               burst = cfg->direction == DMA_DEV_TO_MEM ?
-                               cfg->src_maxburst : cfg->dst_maxburst;
-               nbytes |= EDMA_V3_TCD_NBYTES_MLOFF(-(burst * 4));
-               /* enable DMLOE/SMLOE */
-               if (cfg->direction == DMA_MEM_TO_DEV) {
+       /* If we expect to have either multi_fifo or a port window size,
+        * we will use minor loop offset, meaning bits 29-10 will be used for
+        * address offset, while bits 9-0 will be used to tell DMA how much
+        * data to read from addr.
+        * If we don't have either of those, will use a major loop reading from addr
+        * nbytes (29bits).
+        */
+       if (cfg->direction == DMA_MEM_TO_DEV) {
+               if (fsl_chan->is_multi_fifo)
+                       burst = cfg->dst_maxburst * 4;
+               if (cfg->dst_port_window_size)
+                       burst = cfg->dst_port_window_size * cfg->dst_addr_width;
+               if (burst) {
+                       nbytes |= EDMA_V3_TCD_NBYTES_MLOFF(-burst);
                        nbytes |= EDMA_V3_TCD_NBYTES_DMLOE;
                        nbytes &= ~EDMA_V3_TCD_NBYTES_SMLOE;
-               } else {
+               }
+       } else {
+               if (fsl_chan->is_multi_fifo)
+                       burst = cfg->src_maxburst * 4;
+               if (cfg->src_port_window_size)
+                       burst = cfg->src_port_window_size * cfg->src_addr_width;
+               if (burst) {
+                       nbytes |= EDMA_V3_TCD_NBYTES_MLOFF(-burst);
                        nbytes |= EDMA_V3_TCD_NBYTES_SMLOE;
                        nbytes &= ~EDMA_V3_TCD_NBYTES_DMLOE;
                }
@@ -623,11 +637,15 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
                        dst_addr = fsl_chan->dma_dev_addr;
                        soff = fsl_chan->cfg.dst_addr_width;
                        doff = fsl_chan->is_multi_fifo ? 4 : 0;
+                       if (fsl_chan->cfg.dst_port_window_size)
+                               doff = fsl_chan->cfg.dst_addr_width;
                } else if (direction == DMA_DEV_TO_MEM) {
                        src_addr = fsl_chan->dma_dev_addr;
                        dst_addr = dma_buf_next;
                        soff = fsl_chan->is_multi_fifo ? 4 : 0;
                        doff = fsl_chan->cfg.src_addr_width;
+                       if (fsl_chan->cfg.src_port_window_size)
+                               soff = fsl_chan->cfg.src_addr_width;
                } else {
                        /* DMA_DEV_TO_DEV */
                        src_addr = fsl_chan->cfg.src_addr;