dmaengine: stm32-dma: direct mode support through device tree
authorAmelie Delaunay <amelie.delaunay@st.com>
Wed, 22 Apr 2020 10:29:04 +0000 (12:29 +0200)
committerVinod Koul <vkoul@kernel.org>
Mon, 27 Apr 2020 16:10:12 +0000 (21:40 +0530)
Direct mode or FIFO mode is computed by stm32-dma driver. Add a way for
the user to force direct mode, by setting bit 2 in the bitfield value
specifying DMA features in the device tree.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
Link: https://lore.kernel.org/r/20200422102904.1448-3-amelie.delaunay@st.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/stm32-dma.c

index 0ddbaa4..96ad1b3 100644 (file)
 #define STM32_DMA_FIFO_THRESHOLD_HALFFULL              0x01
 #define STM32_DMA_FIFO_THRESHOLD_3QUARTERSFULL         0x02
 #define STM32_DMA_FIFO_THRESHOLD_FULL                  0x03
+#define STM32_DMA_FIFO_THRESHOLD_NONE                  0x04
 
 #define STM32_DMA_MAX_DATA_ITEMS       0xffff
 /*
 /* DMA Features */
 #define STM32_DMA_THRESHOLD_FTR_MASK   GENMASK(1, 0)
 #define STM32_DMA_THRESHOLD_FTR_GET(n) ((n) & STM32_DMA_THRESHOLD_FTR_MASK)
+#define STM32_DMA_DIRECT_MODE_MASK     BIT(2)
+#define STM32_DMA_DIRECT_MODE_GET(n)   (((n) & STM32_DMA_DIRECT_MODE_MASK) \
+                                        >> 2)
 
 enum stm32_dma_width {
        STM32_DMA_BYTE,
@@ -281,6 +285,9 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold,
 {
        u32 remaining;
 
+       if (threshold == STM32_DMA_FIFO_THRESHOLD_NONE)
+               return false;
+
        if (width != DMA_SLAVE_BUSWIDTH_UNDEFINED) {
                if (burst != 0) {
                        /*
@@ -302,6 +309,10 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold,
 
 static bool stm32_dma_is_burst_possible(u32 buf_len, u32 threshold)
 {
+       /* If FIFO direct mode, burst is not possible */
+       if (threshold == STM32_DMA_FIFO_THRESHOLD_NONE)
+               return false;
+
        /*
         * Buffer or period length has to be aligned on FIFO depth.
         * Otherwise bytes may be stuck within FIFO at buffer or period
@@ -657,6 +668,12 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid)
                                dev_dbg(chan2dev(chan), "FIFO over/underrun\n");
                }
        }
+       if (status & STM32_DMA_DMEI) {
+               stm32_dma_irq_clear(chan, STM32_DMA_DMEI);
+               status &= ~STM32_DMA_DMEI;
+               if (sfcr & STM32_DMA_SCR_DMEIE)
+                       dev_dbg(chan2dev(chan), "Direct mode overrun\n");
+       }
        if (status) {
                stm32_dma_irq_clear(chan, status);
                dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status);
@@ -692,13 +709,13 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
        int src_bus_width, dst_bus_width;
        int src_burst_size, dst_burst_size;
        u32 src_maxburst, dst_maxburst, src_best_burst, dst_best_burst;
-       u32 dma_scr, threshold;
+       u32 dma_scr, fifoth;
 
        src_addr_width = chan->dma_sconfig.src_addr_width;
        dst_addr_width = chan->dma_sconfig.dst_addr_width;
        src_maxburst = chan->dma_sconfig.src_maxburst;
        dst_maxburst = chan->dma_sconfig.dst_maxburst;
-       threshold = chan->threshold;
+       fifoth = chan->threshold;
 
        switch (direction) {
        case DMA_MEM_TO_DEV:
@@ -710,7 +727,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
                /* Set device burst size */
                dst_best_burst = stm32_dma_get_best_burst(buf_len,
                                                          dst_maxburst,
-                                                         threshold,
+                                                         fifoth,
                                                          dst_addr_width);
 
                dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst);
@@ -718,7 +735,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
                        return dst_burst_size;
 
                /* Set memory data size */
-               src_addr_width = stm32_dma_get_max_width(buf_len, threshold);
+               src_addr_width = stm32_dma_get_max_width(buf_len, fifoth);
                chan->mem_width = src_addr_width;
                src_bus_width = stm32_dma_get_width(chan, src_addr_width);
                if (src_bus_width < 0)
@@ -728,7 +745,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
                src_maxburst = STM32_DMA_MAX_BURST;
                src_best_burst = stm32_dma_get_best_burst(buf_len,
                                                          src_maxburst,
-                                                         threshold,
+                                                         fifoth,
                                                          src_addr_width);
                src_burst_size = stm32_dma_get_burst(chan, src_best_burst);
                if (src_burst_size < 0)
@@ -742,7 +759,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
 
                /* Set FIFO threshold */
                chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK;
-               chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(threshold);
+               if (fifoth != STM32_DMA_FIFO_THRESHOLD_NONE)
+                       chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(fifoth);
 
                /* Set peripheral address */
                chan->chan_reg.dma_spar = chan->dma_sconfig.dst_addr;
@@ -758,7 +776,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
                /* Set device burst size */
                src_best_burst = stm32_dma_get_best_burst(buf_len,
                                                          src_maxburst,
-                                                         threshold,
+                                                         fifoth,
                                                          src_addr_width);
                chan->mem_burst = src_best_burst;
                src_burst_size = stm32_dma_get_burst(chan, src_best_burst);
@@ -766,7 +784,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
                        return src_burst_size;
 
                /* Set memory data size */
-               dst_addr_width = stm32_dma_get_max_width(buf_len, threshold);
+               dst_addr_width = stm32_dma_get_max_width(buf_len, fifoth);
                chan->mem_width = dst_addr_width;
                dst_bus_width = stm32_dma_get_width(chan, dst_addr_width);
                if (dst_bus_width < 0)
@@ -776,7 +794,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
                dst_maxburst = STM32_DMA_MAX_BURST;
                dst_best_burst = stm32_dma_get_best_burst(buf_len,
                                                          dst_maxburst,
-                                                         threshold,
+                                                         fifoth,
                                                          dst_addr_width);
                chan->mem_burst = dst_best_burst;
                dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst);
@@ -791,7 +809,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
 
                /* Set FIFO threshold */
                chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK;
-               chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(threshold);
+               if (fifoth != STM32_DMA_FIFO_THRESHOLD_NONE)
+                       chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(fifoth);
 
                /* Set peripheral address */
                chan->chan_reg.dma_spar = chan->dma_sconfig.src_addr;
@@ -1216,6 +1235,8 @@ static void stm32_dma_set_config(struct stm32_dma_chan *chan,
        chan->chan_reg.dma_scr |= STM32_DMA_SCR_TEIE | STM32_DMA_SCR_TCIE;
 
        chan->threshold = STM32_DMA_THRESHOLD_FTR_GET(cfg->features);
+       if (STM32_DMA_DIRECT_MODE_GET(cfg->features))
+               chan->threshold = STM32_DMA_FIFO_THRESHOLD_NONE;
 }
 
 static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec,