OSDN Git Service

dmaengine: sun4i: Add support for cyclic requests with dedicated DMA
authorStefan Mavrodiev <stefan@olimex.com>
Fri, 10 Jan 2020 14:11:39 +0000 (16:11 +0200)
committerVinod Koul <vkoul@kernel.org>
Tue, 21 Jan 2020 08:34:29 +0000 (14:04 +0530)
Currently the cyclic transfers can be used only with normal DMAs. They
can be used by pcm_dmaengine module, which is required for implementing
sound with sun4i-hdmi encoder. This is so because the controller can
accept audio only from a dedicated DMA.

This patch enables them, following the existing style for the
scatter/gather type transfers.

Signed-off-by: Stefan Mavrodiev <stefan@olimex.com>
Acked-by: Maxime Ripard <mripard@kernel.org>
Link: https://lore.kernel.org/r/20200110141140.28527-2-stefan@olimex.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/sun4i-dma.c

index 4e1575e..bbc2bda 100644 (file)
@@ -669,43 +669,41 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
        dma_addr_t src, dest;
        u32 endpoints;
        int nr_periods, offset, plength, i;
+       u8 ram_type, io_mode, linear_mode;
 
        if (!is_slave_direction(dir)) {
                dev_err(chan2dev(chan), "Invalid DMA direction\n");
                return NULL;
        }
 
-       if (vchan->is_dedicated) {
-               /*
-                * As we are using this just for audio data, we need to use
-                * normal DMA. There is nothing stopping us from supporting
-                * dedicated DMA here as well, so if a client comes up and
-                * requires it, it will be simple to implement it.
-                */
-               dev_err(chan2dev(chan),
-                       "Cyclic transfers are only supported on Normal DMA\n");
-               return NULL;
-       }
-
        contract = generate_dma_contract();
        if (!contract)
                return NULL;
 
        contract->is_cyclic = 1;
 
-       /* Figure out the endpoints and the address we need */
+       if (vchan->is_dedicated) {
+               io_mode = SUN4I_DDMA_ADDR_MODE_IO;
+               linear_mode = SUN4I_DDMA_ADDR_MODE_LINEAR;
+               ram_type = SUN4I_DDMA_DRQ_TYPE_SDRAM;
+       } else {
+               io_mode = SUN4I_NDMA_ADDR_MODE_IO;
+               linear_mode = SUN4I_NDMA_ADDR_MODE_LINEAR;
+               ram_type = SUN4I_NDMA_DRQ_TYPE_SDRAM;
+       }
+
        if (dir == DMA_MEM_TO_DEV) {
                src = buf;
                dest = sconfig->dst_addr;
-               endpoints = SUN4I_DMA_CFG_SRC_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM) |
-                           SUN4I_DMA_CFG_DST_DRQ_TYPE(vchan->endpoint) |
-                           SUN4I_DMA_CFG_DST_ADDR_MODE(SUN4I_NDMA_ADDR_MODE_IO);
+               endpoints = SUN4I_DMA_CFG_DST_DRQ_TYPE(vchan->endpoint) |
+                           SUN4I_DMA_CFG_DST_ADDR_MODE(io_mode) |
+                           SUN4I_DMA_CFG_SRC_DRQ_TYPE(ram_type);
        } else {
                src = sconfig->src_addr;
                dest = buf;
-               endpoints = SUN4I_DMA_CFG_SRC_DRQ_TYPE(vchan->endpoint) |
-                           SUN4I_DMA_CFG_SRC_ADDR_MODE(SUN4I_NDMA_ADDR_MODE_IO) |
-                           SUN4I_DMA_CFG_DST_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM);
+               endpoints = SUN4I_DMA_CFG_DST_DRQ_TYPE(ram_type) |
+                           SUN4I_DMA_CFG_SRC_DRQ_TYPE(vchan->endpoint) |
+                           SUN4I_DMA_CFG_SRC_ADDR_MODE(io_mode);
        }
 
        /*
@@ -747,8 +745,13 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
                        dest = buf + offset;
 
                /* Make the promise */
-               promise = generate_ndma_promise(chan, src, dest,
-                                               plength, sconfig, dir);
+               if (vchan->is_dedicated)
+                       promise = generate_ddma_promise(chan, src, dest,
+                                                       plength, sconfig);
+               else
+                       promise = generate_ndma_promise(chan, src, dest,
+                                                       plength, sconfig, dir);
+
                if (!promise) {
                        /* TODO: should we free everything? */
                        return NULL;