dmaengine: imx-sdma: move dma parameters from imx_dma_data to slave_config
authorRobin Gong <yibin.gong@nxp.com>
Wed, 24 Mar 2021 16:50:10 +0000 (00:50 +0800)
committerShengjiu Wang <shengjiu.wang@nxp.com>
Wed, 21 Apr 2021 08:00:09 +0000 (16:00 +0800)
use 'peripheral_config' to pass our special sdma parameters from
dma_request_slave_channel() to dmaengine_slave_config(), thus could make
upper driver much cleaner, besides could make binding docs much cleaner
too and easier to upstreaming.

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
(cherry picked from commit 6f52f8e232017df86fa50270c206f99b21a37ac2)

drivers/dma/imx-sdma.c
include/linux/platform_data/dma-imx.h

index 298fb5b..92d2373 100644 (file)
@@ -377,8 +377,9 @@ struct sdma_channel {
        struct sdma_desc                *desc;
        struct sdma_engine              *sdma;
        unsigned int                    channel;
-       enum dma_transfer_direction             direction;
+       enum dma_transfer_direction     direction;
        struct dma_slave_config         slave_config;
+       struct sdma_audio_config        *audio_config;
        enum sdma_peripheral_type       peripheral_type;
        unsigned int                    event_id0;
        unsigned int                    event_id1;
@@ -395,11 +396,6 @@ struct sdma_channel {
        struct imx_dma_data             data;
        struct work_struct              terminate_worker;
        bool                            is_ram_script;
-       bool                            src_dualfifo;
-       bool                            dst_dualfifo;
-       unsigned int                    fifo_num;
-       bool                            sw_done;
-       u32                             sw_done_sel;
 };
 
 #define IMX_DMA_SG_LOOP                BIT(0)
@@ -829,12 +825,13 @@ static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event)
        writel_relaxed(val, sdma->regs + chnenbl);
 
        /* Set SDMA_DONEx_CONFIG is sw_done enabled */
-       if (sdmac->sw_done) {
-               u32 offset = SDMA_DONE0_CONFIG + sdmac->sw_done_sel / 4;
+       if (sdmac->audio_config && sdmac->audio_config->sw_done_sel & BIT(31)) {
+               u32 sw_done_sel = sdmac->audio_config->sw_done_sel & 0xff;
+               u32 offset = SDMA_DONE0_CONFIG + sw_done_sel / 4;
                u32 done_sel = SDMA_DONE0_CONFIG_DONE_SEL +
-                               ((sdmac->sw_done_sel % 4) << 3);
+                               ((sw_done_sel % 4) << 3);
                u32 sw_done_dis = SDMA_DONE0_CONFIG_DONE_DIS +
-                               ((sdmac->sw_done_sel % 4) << 3);
+                               ((sw_done_sel % 4) << 3);
 
                val = readl_relaxed(sdma->regs + offset);
                __set_bit(done_sel, &val);
@@ -1306,30 +1303,35 @@ static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
 
        sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_CONT;
 
-       if (sdmac->src_dualfifo)
+       if (sdmac->audio_config->src_fifo_num > 1)
                sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SD;
-       if (sdmac->dst_dualfifo)
+       if (sdmac->audio_config->dst_fifo_num > 1)
                sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_DD;
 }
 
 static void sdma_set_watermarklevel_for_sais(struct sdma_channel *sdmac)
 {
+       u8 fifo_num = sdmac->audio_config->src_fifo_num |
+                     sdmac->audio_config->dst_fifo_num;
+
        sdmac->watermark_level &= ~(0xFF << SDMA_WATERMARK_LEVEL_FIFOS_OFF |
                                    SDMA_WATERMARK_LEVEL_SW_DONE |
                                    0xf << SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF);
 
-       if (sdmac->sw_done)
+       if (sdmac->audio_config->sw_done_sel & BIT(31))
                sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SW_DONE |
-                       sdmac->sw_done_sel <<
-                       SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF;
+                               (sdmac->audio_config->sw_done_sel & 0xff) <<
+                               SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF;
 
        /* For fifo_num
         * bit 12-15 is the fifo number;
         * bit 16-19 is the fifo offset,
+        * bit 28-31 is the channels per fifo.
         * so here only need to shift left fifo_num 12 bit for watermake_level
         */
-       sdmac->watermark_level |= sdmac->fifo_num<<
-                               SDMA_WATERMARK_LEVEL_FIFOS_OFF;
+       if (fifo_num)
+               sdmac->watermark_level |= fifo_num <<
+                                       SDMA_WATERMARK_LEVEL_FIFOS_OFF;
 }
 
 static int sdma_config_channel(struct dma_chan *chan)
@@ -1603,13 +1605,6 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
        sdmac->peripheral_type = data->peripheral_type;
        sdmac->event_id0 = data->dma_request;
        sdmac->event_id1 = data->dma_request2;
-       sdmac->src_dualfifo = data->src_dualfifo;
-       sdmac->dst_dualfifo = data->dst_dualfifo;
-       /* Get software done selector if sw_done enabled */
-       if (data->done_sel & BIT(31)) {
-               sdmac->sw_done = true;
-               sdmac->sw_done_sel = (data->done_sel >> 8) & 0xff;
-       }
 
        pm_runtime_get_sync(sdmac->sdma->dev);
 
@@ -1638,6 +1633,9 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
 
        sdma_set_channel_priority(sdmac, 0);
 
+       kfree(sdmac->audio_config);
+       sdmac->audio_config = NULL;
+
        pm_runtime_put_sync(sdma->dev);
 }
 
@@ -1918,7 +1916,6 @@ 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->fifo_num =  dmaengine_cfg->src_fifo_num;
        } else if (direction == DMA_DEV_TO_DEV) {
                sdmac->per_address2 = dmaengine_cfg->src_addr;
                sdmac->per_address = dmaengine_cfg->dst_addr;
@@ -1936,7 +1933,6 @@ 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->fifo_num =  dmaengine_cfg->dst_fifo_num;
        }
        sdmac->direction = direction;
        return sdma_config_channel(chan);
@@ -1946,9 +1942,23 @@ static int sdma_config(struct dma_chan *chan,
                       struct dma_slave_config *dmaengine_cfg)
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
+       void *tmp;
 
        memcpy(&sdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg));
 
+       /* Allocate special sdma_audio_config if it's used */
+       if (dmaengine_cfg->peripheral_config) {
+               tmp = krealloc(sdmac->audio_config,
+                              dmaengine_cfg->peripheral_size, GFP_NOWAIT);
+               if (!tmp)
+                       return -ENOMEM;
+
+               sdmac->audio_config = (struct sdma_audio_config *)tmp;
+
+               memcpy(tmp, dmaengine_cfg->peripheral_config,
+                       dmaengine_cfg->peripheral_size);
+       }
+
        /* Set ENBLn earlier to make sure dma request triggered after that */
        if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events)
                return -EINVAL;
@@ -2267,9 +2277,6 @@ static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
 
        data.dma_request = dma_spec->args[0];
        data.peripheral_type = dma_spec->args[1];
-       /* Get sw_done setting if sw_done enabled */
-       if (dma_spec->args[2] & BIT(31))
-               data.done_sel = dma_spec->args[2];
        data.priority = dma_spec->args[2] & 0xff;
        /*
         * init dma_request2 to zero, which is not used by the dts.
index f10d767..2a88d5a 100644 (file)
@@ -51,14 +51,44 @@ enum imx_dma_prio {
        DMA_PRIO_LOW = 2
 };
 
+/**
+ * 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;
+};
+
 struct imx_dma_data {
        int dma_request; /* DMA request line */
        int dma_request2; /* secondary DMA request line */
        enum sdma_peripheral_type peripheral_type;
        int priority;
-       bool src_dualfifo;
-       bool dst_dualfifo;
-       int done_sel;
 };
 
 static inline int imx_dma_is_ipu(struct dma_chan *chan)