Ejemplo n.º 1
0
static struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
		struct dma_chan *chan, struct scatterlist *sgl,
		unsigned int sg_len, enum dma_transfer_direction direction,
		unsigned long flags, void *context)
{
	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
	struct fsl_edma_desc *fsl_desc;
	struct scatterlist *sg;
	u32 src_addr, dst_addr, last_sg, nbytes;
	u16 soff, doff, iter;
	int i;

	if (!is_slave_direction(fsl_chan->fsc.dir))
		return NULL;

	fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
	if (!fsl_desc)
		return NULL;
	fsl_desc->iscyclic = false;

	nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
	for_each_sg(sgl, sg, sg_len, i) {
		/* get next sg's physical address */
		last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;

		if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
			src_addr = sg_dma_address(sg);
			dst_addr = fsl_chan->fsc.dev_addr;
			soff = fsl_chan->fsc.addr_width;
			doff = 0;
		} else {
			src_addr = fsl_chan->fsc.dev_addr;
			dst_addr = sg_dma_address(sg);
			soff = 0;
			doff = fsl_chan->fsc.addr_width;
		}

		iter = sg_dma_len(sg) / nbytes;
		if (i < sg_len - 1) {
			last_sg = fsl_desc->tcd[(i + 1)].ptcd;
			fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd,
					src_addr, dst_addr, fsl_chan->fsc.attr,
					soff, nbytes, 0, iter, iter, doff, last_sg,
					false, false, true);
		} else {
			last_sg = 0;
			fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd,
					src_addr, dst_addr, fsl_chan->fsc.attr,
					soff, nbytes, 0, iter, iter, doff, last_sg,
					true, true, false);
		}
	}
Ejemplo n.º 2
0
static int edma_engine_config(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct mvf_pcm_runtime_data *iprtd = runtime->private_data;
	u32 size = frames_to_bytes(runtime, runtime->period_size);
	struct imx_pcm_dma_params *dma_params;
	u32 sg_addr;
	int i;

	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);

	iprtd->dma_buf_phys = runtime->dma_addr;
	iprtd->dma_buf_next = iprtd->dma_buf_phys;
	iprtd->dma_buf_end = iprtd->dma_buf_phys + runtime->periods * size;

	sg_addr = iprtd->tcd_buf_phys;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		iprtd->src_addr = iprtd->dma_buf_next;
		iprtd->dst_addr = dma_params->dma_addr;
		iprtd->soffset = 2;
		iprtd->doffset = 0;
	} else {
		iprtd->src_addr = dma_params->dma_addr;
		iprtd->dst_addr = iprtd->dma_buf_next;
		iprtd->soffset = 0;
		iprtd->doffset = 2;
	}

	mcf_edma_set_tcd_params(iprtd->tcd_chan,
		iprtd->src_addr, iprtd->dst_addr,
		MCF_EDMA_TCD_ATTR_SSIZE_16BIT | MCF_EDMA_TCD_ATTR_DSIZE_16BIT,
		iprtd->soffset, 4, 0, size / 4, size / 4, iprtd->doffset,
		sg_addr, 1, 0, 1);

	for (i = 0; i < TCD_NUMBER; i++) {
		iprtd->dma_buf_next += size;
		if (iprtd->dma_buf_next >= iprtd->dma_buf_end)
			iprtd->dma_buf_next = iprtd->dma_buf_phys;

		sg_addr = iprtd->tcd_buf_phys +
			((i + 1) % TCD_NUMBER) * sizeof(struct edma_tcd);

		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
			iprtd->src_addr = iprtd->dma_buf_next;
		else
			iprtd->dst_addr = iprtd->dma_buf_next;

		fill_tcd_params(&iprtd->tcd[i],
			iprtd->src_addr, iprtd->dst_addr,
			MCF_EDMA_TCD_ATTR_SSIZE_16BIT |
				MCF_EDMA_TCD_ATTR_DSIZE_16BIT,
			iprtd->soffset, 4, 0, size / 4, size / 4,
			iprtd->doffset, sg_addr, 1, 0, 1);
	}

	return 0;
}
Ejemplo n.º 3
0
static struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
		size_t period_len, enum dma_transfer_direction direction,
		unsigned long flags)
{
	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
	struct fsl_edma_desc *fsl_desc;
	dma_addr_t dma_buf_next;
	int sg_len, i;
	u32 src_addr, dst_addr, last_sg, nbytes;
	u16 soff, doff, iter;

	if (!is_slave_direction(fsl_chan->fsc.dir))
		return NULL;

	sg_len = buf_len / period_len;
	fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
	if (!fsl_desc)
		return NULL;
	fsl_desc->iscyclic = true;

	dma_buf_next = dma_addr;
	nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
	iter = period_len / nbytes;

	for (i = 0; i < sg_len; i++) {
		if (dma_buf_next >= dma_addr + buf_len)
			dma_buf_next = dma_addr;

		/* get next sg's physical address */
		last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;

		if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
			src_addr = dma_buf_next;
			dst_addr = fsl_chan->fsc.dev_addr;
			soff = fsl_chan->fsc.addr_width;
			doff = 0;
		} else {
			src_addr = fsl_chan->fsc.dev_addr;
			dst_addr = dma_buf_next;
			soff = 0;
			doff = fsl_chan->fsc.addr_width;
		}

		fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd, src_addr,
				dst_addr, fsl_chan->fsc.attr, soff, nbytes, 0,
				iter, iter, doff, last_sg, true, false, true);
		dma_buf_next += period_len;
	}

	return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
}