[PATCH 10/19] dma: imx-sdma: Add multi fifo support
S.J. Wang
shengjiu.wang at nxp.com
Thu Mar 17 11:18:20 CET 2022
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
More information about the Alsa-devel
mailing list