Hi Sascha > --- > drivers/dma/imx-sdma.c | 54 +++++++++++++++++++++++++++ > include/linux/platform_data/dma-imx.h | 7 ++++ > 2 files changed, 61 insertions(+) > > diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index > 1038f6bc7f846..21e1cec2ffde9 100644 > --- a/drivers/dma/imx-sdma.c > +++ b/drivers/dma/imx-sdma.c > @@ -14,6 +14,7 @@ > #include <linux/iopoll.h> > #include <linux/module.h> > #include <linux/types.h> > +#include <linux/bitfield.h> > #include <linux/bitops.h> > #include <linux/mm.h> > #include <linux/interrupt.h> > @@ -73,6 +74,7 @@ > #define SDMA_CHNENBL0_IMX35 0x200 > #define SDMA_CHNENBL0_IMX31 0x080 > #define SDMA_CHNPRI_0 0x100 > +#define SDMA_DONE0_CONFIG 0x1000 > > /* > * Buffer descriptor status values. > @@ -180,6 +182,12 @@ > BIT(DMA_MEM_TO_DEV) | \ > BIT(DMA_DEV_TO_DEV)) > > +#define SDMA_WATERMARK_LEVEL_N_FIFOS GENMASK(15, 12) > +#define SDMA_WATERMARK_LEVEL_SW_DONE BIT(23) > + > +#define SDMA_DONE0_CONFIG_DONE_SEL BIT(7) > +#define SDMA_DONE0_CONFIG_DONE_DIS BIT(6) > + > /** > * struct sdma_script_start_addrs - SDMA script start pointers > * > @@ -441,6 +449,11 @@ struct sdma_channel { > struct work_struct terminate_worker; > struct list_head terminated; > bool is_ram_script; > + unsigned int n_fifos; > + unsigned int n_fifos_src; > + unsigned int n_fifos_dst; > + bool sw_done; > + u32 sw_done_sel; > }; > > #define IMX_DMA_SG_LOOP BIT(0) > @@ -773,6 +786,14 @@ static void sdma_event_enable(struct > sdma_channel *sdmac, unsigned int event) > val = readl_relaxed(sdma->regs + chnenbl); > __set_bit(channel, &val); > writel_relaxed(val, sdma->regs + chnenbl); > + > + /* Set SDMA_DONEx_CONFIG is sw_done enabled */ > + if (sdmac->sw_done) { > + val = readl_relaxed(sdma->regs + SDMA_DONE0_CONFIG); > + val |= SDMA_DONE0_CONFIG_DONE_SEL; > + val &= ~SDMA_DONE0_CONFIG_DONE_DIS; > + writel_relaxed(val, sdma->regs + SDMA_DONE0_CONFIG); > + } > } > > static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int > event) @@ -1022,6 +1043,10 @@ static int sdma_get_pc(struct > sdma_channel *sdmac, > case IMX_DMATYPE_IPU_MEMORY: > emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr; > break; > + case IMX_DMATYPE_MULTI_SAI: > + per_2_emi = sdma->script_addrs->sai_2_mcu_addr; > + emi_2_per = sdma->script_addrs->mcu_2_sai_addr; > + break; > default: > dev_err(sdma->dev, "Unsupported transfer type %d\n", > peripheral_type); @@ -1198,6 +1223,15 @@ static void > sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac) > sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_CONT; } > > +static void sdma_set_watermarklevel_for_sais(struct sdma_channel > +*sdmac) { > + if (sdmac->sw_done) > + sdmac->watermark_level |= > SDMA_WATERMARK_LEVEL_SW_DONE; > + > + sdmac->watermark_level |= > + FIELD_PREP(SDMA_WATERMARK_LEVEL_N_FIFOS, > +sdmac->n_fifos); } > + > static int sdma_config_channel(struct dma_chan *chan) { > struct sdma_channel *sdmac = to_sdma_chan(chan); @@ -1234,6 > +1268,10 @@ static int sdma_config_channel(struct dma_chan *chan) > sdmac->peripheral_type == IMX_DMATYPE_ASRC) > sdma_set_watermarklevel_for_p2p(sdmac); > } else { > + if (sdmac->peripheral_type == > + IMX_DMATYPE_MULTI_SAI) > + sdma_set_watermarklevel_for_sais(sdmac); > + > __set_bit(sdmac->event_id0, sdmac->event_mask); > } > > @@ -1669,6 +1707,7 @@ static int sdma_config_write(struct dma_chan > *chan, > sdmac->watermark_level = dmaengine_cfg->src_maxburst * > dmaengine_cfg->src_addr_width; > sdmac->word_size = dmaengine_cfg->src_addr_width; > + sdmac->n_fifos = sdmac->n_fifos_src; > } else if (direction == DMA_DEV_TO_DEV) { > sdmac->per_address2 = dmaengine_cfg->src_addr; > sdmac->per_address = dmaengine_cfg->dst_addr; @@ -1682,6 > +1721,7 @@ static int sdma_config_write(struct dma_chan *chan, > sdmac->watermark_level = dmaengine_cfg->dst_maxburst * > dmaengine_cfg->dst_addr_width; > sdmac->word_size = dmaengine_cfg->dst_addr_width; > + sdmac->n_fifos = sdmac->n_fifos_dst; > } > sdmac->direction = direction; > return sdma_config_channel(chan); @@ -1691,9 +1731,23 @@ static int > sdma_config(struct dma_chan *chan, > struct dma_slave_config *dmaengine_cfg) { > struct sdma_channel *sdmac = to_sdma_chan(chan); > + struct sdma_engine *sdma = sdmac->sdma; > > memcpy(&sdmac->slave_config, dmaengine_cfg, > sizeof(*dmaengine_cfg)); > > + if (dmaengine_cfg->peripheral_config) { > + struct sdma_peripheral_config *sdmacfg = dmaengine_cfg- > >peripheral_config; > + if (dmaengine_cfg->peripheral_size != sizeof(struct > sdma_peripheral_config)) { > + dev_err(sdma->dev, "Invalid peripheral size %zu, > expected %zu\n", > + dmaengine_cfg->peripheral_size, > + sizeof(struct sdma_peripheral_config)); > + return -EINVAL; > + } > + sdmac->n_fifos_src = sdmacfg->n_fifos_src; > + sdmac->n_fifos_dst = sdmacfg->n_fifos_dst; > + sdmac->sw_done = sdmacfg->sw_done; > + } > + > /* Set ENBLn earlier to make sure dma request triggered after that */ > if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events) > return -EINVAL; > diff --git a/include/linux/platform_data/dma-imx.h > b/include/linux/platform_data/dma-imx.h > index 281adbb26e6bd..4a43a048e1b4d 100644 > --- a/include/linux/platform_data/dma-imx.h > +++ b/include/linux/platform_data/dma-imx.h > @@ -39,6 +39,7 @@ enum sdma_peripheral_type { > IMX_DMATYPE_SSI_DUAL, /* SSI Dual FIFO */ > IMX_DMATYPE_ASRC_SP, /* Shared ASRC */ > IMX_DMATYPE_SAI, /* SAI */ > + IMX_DMATYPE_MULTI_SAI, /* MULTI FIFOs For Audio */ > }; > > enum imx_dma_prio { > @@ -65,4 +66,10 @@ static inline int imx_dma_is_general_purpose(struct > dma_chan *chan) > !strcmp(chan->device->dev->driver->name, "imx-dma"); } > > +struct sdma_peripheral_config { > + int n_fifos_src; > + int n_fifos_dst; > + bool sw_done; > +}; > + Seems there is issue with my gmail, I resend the comments again. This is our internal definition for this sdma_peripheral_config. Could you please adopt this? /** * struct sdma_audio_config - special sdma config for audio case * @src_fifo_num: source fifo number for mcu_2_sai/sai_2_mcu script * For example, if there are 4 fifos, sdma will fetch * fifos one by one and roll back to the first fifo after * the 4th fifo fetch. * @dst_fifo_num: similar as src_fifo_num, but dest fifo instead. * @src_fifo_off: source fifo offset, 0 means all fifos are continuous, 1 * means 1 word offset between fifos. All offset between * fifos should be same. * @dst_fifo_off: dst fifo offset, similar as @src_fifo_off. * @words_per_fifo: numbers of words per fifo fetch/fill, 0 means * one channel per fifo, 1 means 2 channels per fifo.. * If 'src_fifo_num = 4' and 'chans_per_fifo = 1', it * means the first two words(channels) fetch from fifo1 * and then jump to fifo2 for next two words, and so on * after the last fifo4 fetched, roll back to fifo1. * @sw_done_sel: software done selector, PDM need enable software done feature * in mcu_2_sai/sai_2_mcu script. * Bit31: sw_done eanbled or not * Bit16~Bit0: selector * For example: 0x80000000 means sw_done enabled for done0 * sector which is for PDM on i.mx8mm. */ struct sdma_audio_config { u8 src_fifo_num; u8 dst_fifo_num; u8 src_fifo_off; u8 dst_fifo_off; u8 words_per_fifo; u32 sw_done_sel; }; Best regards Wang shengjiu