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;
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)
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);
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)
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);
sdma_set_channel_priority(sdmac, 0);
+ kfree(sdmac->audio_config);
+ sdmac->audio_config = NULL;
+
pm_runtime_put_sync(sdma->dev);
}
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;
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);
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;
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.
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)