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:
Родитель
86e673f7c9
Коммит
955b17665d
|
@ -117,6 +117,7 @@
|
|||
#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
|
||||
/*
|
||||
|
@ -136,6 +137,9 @@
|
|||
/* 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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче