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: 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>
This commit is contained in:
parent
86e673f7c9
commit
955b17665d
@ -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 @@
|
|||||||
/* 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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
|
|
||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
/* 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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
/* 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,
|
|||||||
/* 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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
/* 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,
|
|||||||
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,
|
||||||
|
Loading…
Reference in New Issue
Block a user