RE: [PATCH 10/19] dma: imx-sdma: Add multi fifo support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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








[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux