RE: [PATCH 10/19] dma: imx-sdma: Add multi fifo support
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
participants (1)
-
S.J. Wang