Commit 955b1766 authored by Amelie Delaunay's avatar Amelie Delaunay Committed by Vinod Koul

dmaengine: stm32-dma: direct mode support through device tree

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: default avatarAmelie Delaunay <amelie.delaunay@st.com>
Link: https://lore.kernel.org/r/20200422102904.1448-3-amelie.delaunay@st.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 86e673f7
...@@ -117,6 +117,7 @@ ...@@ -117,6 +117,7 @@
#define STM32_DMA_FIFO_THRESHOLD_HALFFULL 0x01 #define STM32_DMA_FIFO_THRESHOLD_HALFFULL 0x01
#define STM32_DMA_FIFO_THRESHOLD_3QUARTERSFULL 0x02 #define STM32_DMA_FIFO_THRESHOLD_3QUARTERSFULL 0x02
#define STM32_DMA_FIFO_THRESHOLD_FULL 0x03 #define STM32_DMA_FIFO_THRESHOLD_FULL 0x03
#define STM32_DMA_FIFO_THRESHOLD_NONE 0x04
#define STM32_DMA_MAX_DATA_ITEMS 0xffff #define STM32_DMA_MAX_DATA_ITEMS 0xffff
/* /*
...@@ -136,6 +137,9 @@ ...@@ -136,6 +137,9 @@
/* DMA Features */ /* DMA Features */
#define STM32_DMA_THRESHOLD_FTR_MASK GENMASK(1, 0) #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_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 { enum stm32_dma_width {
STM32_DMA_BYTE, STM32_DMA_BYTE,
...@@ -281,6 +285,9 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, ...@@ -281,6 +285,9 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold,
{ {
u32 remaining; u32 remaining;
if (threshold == STM32_DMA_FIFO_THRESHOLD_NONE)
return false;
if (width != DMA_SLAVE_BUSWIDTH_UNDEFINED) { if (width != DMA_SLAVE_BUSWIDTH_UNDEFINED) {
if (burst != 0) { if (burst != 0) {
/* /*
...@@ -302,6 +309,10 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, ...@@ -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) 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. * Buffer or period length has to be aligned on FIFO depth.
* Otherwise bytes may be stuck within FIFO at buffer or period * 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) ...@@ -657,6 +668,12 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid)
dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); 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) { if (status) {
stm32_dma_irq_clear(chan, status); stm32_dma_irq_clear(chan, status);
dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", 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, ...@@ -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_bus_width, dst_bus_width;
int src_burst_size, dst_burst_size; int src_burst_size, dst_burst_size;
u32 src_maxburst, dst_maxburst, src_best_burst, dst_best_burst; 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; src_addr_width = chan->dma_sconfig.src_addr_width;
dst_addr_width = chan->dma_sconfig.dst_addr_width; dst_addr_width = chan->dma_sconfig.dst_addr_width;
src_maxburst = chan->dma_sconfig.src_maxburst; src_maxburst = chan->dma_sconfig.src_maxburst;
dst_maxburst = chan->dma_sconfig.dst_maxburst; dst_maxburst = chan->dma_sconfig.dst_maxburst;
threshold = chan->threshold; fifoth = chan->threshold;
switch (direction) { switch (direction) {
case DMA_MEM_TO_DEV: case DMA_MEM_TO_DEV:
...@@ -710,7 +727,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, ...@@ -710,7 +727,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
/* Set device burst size */ /* Set device burst size */
dst_best_burst = stm32_dma_get_best_burst(buf_len, dst_best_burst = stm32_dma_get_best_burst(buf_len,
dst_maxburst, dst_maxburst,
threshold, fifoth,
dst_addr_width); dst_addr_width);
dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst); 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, ...@@ -718,7 +735,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
return dst_burst_size; return dst_burst_size;
/* Set memory data 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; chan->mem_width = src_addr_width;
src_bus_width = stm32_dma_get_width(chan, src_addr_width); src_bus_width = stm32_dma_get_width(chan, src_addr_width);
if (src_bus_width < 0) if (src_bus_width < 0)
...@@ -728,7 +745,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, ...@@ -728,7 +745,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
src_maxburst = STM32_DMA_MAX_BURST; src_maxburst = STM32_DMA_MAX_BURST;
src_best_burst = stm32_dma_get_best_burst(buf_len, src_best_burst = stm32_dma_get_best_burst(buf_len,
src_maxburst, src_maxburst,
threshold, fifoth,
src_addr_width); src_addr_width);
src_burst_size = stm32_dma_get_burst(chan, src_best_burst); src_burst_size = stm32_dma_get_burst(chan, src_best_burst);
if (src_burst_size < 0) if (src_burst_size < 0)
...@@ -742,7 +759,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, ...@@ -742,7 +759,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
/* Set FIFO threshold */ /* Set FIFO threshold */
chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; 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 */ /* Set peripheral address */
chan->chan_reg.dma_spar = chan->dma_sconfig.dst_addr; 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, ...@@ -758,7 +776,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
/* Set device burst size */ /* Set device burst size */
src_best_burst = stm32_dma_get_best_burst(buf_len, src_best_burst = stm32_dma_get_best_burst(buf_len,
src_maxburst, src_maxburst,
threshold, fifoth,
src_addr_width); src_addr_width);
chan->mem_burst = src_best_burst; chan->mem_burst = src_best_burst;
src_burst_size = stm32_dma_get_burst(chan, 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, ...@@ -766,7 +784,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
return src_burst_size; return src_burst_size;
/* Set memory data 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; chan->mem_width = dst_addr_width;
dst_bus_width = stm32_dma_get_width(chan, dst_addr_width); dst_bus_width = stm32_dma_get_width(chan, dst_addr_width);
if (dst_bus_width < 0) if (dst_bus_width < 0)
...@@ -776,7 +794,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, ...@@ -776,7 +794,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
dst_maxburst = STM32_DMA_MAX_BURST; dst_maxburst = STM32_DMA_MAX_BURST;
dst_best_burst = stm32_dma_get_best_burst(buf_len, dst_best_burst = stm32_dma_get_best_burst(buf_len,
dst_maxburst, dst_maxburst,
threshold, fifoth,
dst_addr_width); dst_addr_width);
chan->mem_burst = dst_best_burst; chan->mem_burst = dst_best_burst;
dst_burst_size = stm32_dma_get_burst(chan, 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, ...@@ -791,7 +809,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
/* Set FIFO threshold */ /* Set FIFO threshold */
chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; 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 */ /* Set peripheral address */
chan->chan_reg.dma_spar = chan->dma_sconfig.src_addr; 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, ...@@ -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->chan_reg.dma_scr |= STM32_DMA_SCR_TEIE | STM32_DMA_SCR_TCIE;
chan->threshold = STM32_DMA_THRESHOLD_FTR_GET(cfg->features); 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, static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment