cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fsl_asrc_dma.c (12924B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Freescale ASRC ALSA SoC Platform (DMA) driver
      4//
      5// Copyright (C) 2014 Freescale Semiconductor, Inc.
      6//
      7// Author: Nicolin Chen <nicoleotsuka@gmail.com>
      8
      9#include <linux/dma-mapping.h>
     10#include <linux/module.h>
     11#include <linux/dma/imx-dma.h>
     12#include <sound/dmaengine_pcm.h>
     13#include <sound/pcm_params.h>
     14
     15#include "fsl_asrc_common.h"
     16
     17#define FSL_ASRC_DMABUF_SIZE	(256 * 1024)
     18
     19static struct snd_pcm_hardware snd_imx_hardware = {
     20	.info = SNDRV_PCM_INFO_INTERLEAVED |
     21		SNDRV_PCM_INFO_BLOCK_TRANSFER |
     22		SNDRV_PCM_INFO_MMAP |
     23		SNDRV_PCM_INFO_MMAP_VALID,
     24	.buffer_bytes_max = FSL_ASRC_DMABUF_SIZE,
     25	.period_bytes_min = 128,
     26	.period_bytes_max = 65535, /* Limited by SDMA engine */
     27	.periods_min = 2,
     28	.periods_max = 255,
     29	.fifo_size = 0,
     30};
     31
     32static bool filter(struct dma_chan *chan, void *param)
     33{
     34	if (!imx_dma_is_general_purpose(chan))
     35		return false;
     36
     37	chan->private = param;
     38
     39	return true;
     40}
     41
     42static void fsl_asrc_dma_complete(void *arg)
     43{
     44	struct snd_pcm_substream *substream = arg;
     45	struct snd_pcm_runtime *runtime = substream->runtime;
     46	struct fsl_asrc_pair *pair = runtime->private_data;
     47
     48	pair->pos += snd_pcm_lib_period_bytes(substream);
     49	if (pair->pos >= snd_pcm_lib_buffer_bytes(substream))
     50		pair->pos = 0;
     51
     52	snd_pcm_period_elapsed(substream);
     53}
     54
     55static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream,
     56					   struct snd_soc_component *component)
     57{
     58	u8 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? OUT : IN;
     59	struct snd_pcm_runtime *runtime = substream->runtime;
     60	struct fsl_asrc_pair *pair = runtime->private_data;
     61	struct device *dev = component->dev;
     62	unsigned long flags = DMA_CTRL_ACK;
     63
     64	/* Prepare and submit Front-End DMA channel */
     65	if (!substream->runtime->no_period_wakeup)
     66		flags |= DMA_PREP_INTERRUPT;
     67
     68	pair->pos = 0;
     69	pair->desc[!dir] = dmaengine_prep_dma_cyclic(
     70			pair->dma_chan[!dir], runtime->dma_addr,
     71			snd_pcm_lib_buffer_bytes(substream),
     72			snd_pcm_lib_period_bytes(substream),
     73			dir == OUT ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, flags);
     74	if (!pair->desc[!dir]) {
     75		dev_err(dev, "failed to prepare slave DMA for Front-End\n");
     76		return -ENOMEM;
     77	}
     78
     79	pair->desc[!dir]->callback = fsl_asrc_dma_complete;
     80	pair->desc[!dir]->callback_param = substream;
     81
     82	dmaengine_submit(pair->desc[!dir]);
     83
     84	/* Prepare and submit Back-End DMA channel */
     85	pair->desc[dir] = dmaengine_prep_dma_cyclic(
     86			pair->dma_chan[dir], 0xffff, 64, 64, DMA_DEV_TO_DEV, 0);
     87	if (!pair->desc[dir]) {
     88		dev_err(dev, "failed to prepare slave DMA for Back-End\n");
     89		return -ENOMEM;
     90	}
     91
     92	dmaengine_submit(pair->desc[dir]);
     93
     94	return 0;
     95}
     96
     97static int fsl_asrc_dma_trigger(struct snd_soc_component *component,
     98				struct snd_pcm_substream *substream, int cmd)
     99{
    100	struct snd_pcm_runtime *runtime = substream->runtime;
    101	struct fsl_asrc_pair *pair = runtime->private_data;
    102	int ret;
    103
    104	switch (cmd) {
    105	case SNDRV_PCM_TRIGGER_START:
    106	case SNDRV_PCM_TRIGGER_RESUME:
    107	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    108		ret = fsl_asrc_dma_prepare_and_submit(substream, component);
    109		if (ret)
    110			return ret;
    111		dma_async_issue_pending(pair->dma_chan[IN]);
    112		dma_async_issue_pending(pair->dma_chan[OUT]);
    113		break;
    114	case SNDRV_PCM_TRIGGER_STOP:
    115	case SNDRV_PCM_TRIGGER_SUSPEND:
    116	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    117		dmaengine_terminate_all(pair->dma_chan[OUT]);
    118		dmaengine_terminate_all(pair->dma_chan[IN]);
    119		break;
    120	default:
    121		return -EINVAL;
    122	}
    123
    124	return 0;
    125}
    126
    127static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
    128				  struct snd_pcm_substream *substream,
    129				  struct snd_pcm_hw_params *params)
    130{
    131	enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
    132	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    133	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
    134	struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL;
    135	struct snd_dmaengine_dai_dma_data *dma_params_be = NULL;
    136	struct snd_pcm_runtime *runtime = substream->runtime;
    137	struct fsl_asrc_pair *pair = runtime->private_data;
    138	struct dma_chan *tmp_chan = NULL, *be_chan = NULL;
    139	struct snd_soc_component *component_be = NULL;
    140	struct fsl_asrc *asrc = pair->asrc;
    141	struct dma_slave_config config_fe, config_be;
    142	enum asrc_pair_index index = pair->index;
    143	struct device *dev = component->dev;
    144	struct device_node *of_dma_node;
    145	int stream = substream->stream;
    146	struct imx_dma_data *tmp_data;
    147	struct snd_soc_dpcm *dpcm;
    148	struct device *dev_be;
    149	u8 dir = tx ? OUT : IN;
    150	dma_cap_mask_t mask;
    151	int ret, width;
    152
    153	/* Fetch the Back-End dma_data from DPCM */
    154	for_each_dpcm_be(rtd, stream, dpcm) {
    155		struct snd_soc_pcm_runtime *be = dpcm->be;
    156		struct snd_pcm_substream *substream_be;
    157		struct snd_soc_dai *dai = asoc_rtd_to_cpu(be, 0);
    158
    159		if (dpcm->fe != rtd)
    160			continue;
    161
    162		substream_be = snd_soc_dpcm_get_substream(be, stream);
    163		dma_params_be = snd_soc_dai_get_dma_data(dai, substream_be);
    164		dev_be = dai->dev;
    165		break;
    166	}
    167
    168	if (!dma_params_be) {
    169		dev_err(dev, "failed to get the substream of Back-End\n");
    170		return -EINVAL;
    171	}
    172
    173	/* Override dma_data of the Front-End and config its dmaengine */
    174	dma_params_fe = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
    175	dma_params_fe->addr = asrc->paddr + asrc->get_fifo_addr(!dir, index);
    176	dma_params_fe->maxburst = dma_params_be->maxburst;
    177
    178	pair->dma_chan[!dir] = asrc->get_dma_channel(pair, !dir);
    179	if (!pair->dma_chan[!dir]) {
    180		dev_err(dev, "failed to request DMA channel\n");
    181		return -EINVAL;
    182	}
    183
    184	memset(&config_fe, 0, sizeof(config_fe));
    185	ret = snd_dmaengine_pcm_prepare_slave_config(substream, params, &config_fe);
    186	if (ret) {
    187		dev_err(dev, "failed to prepare DMA config for Front-End\n");
    188		return ret;
    189	}
    190
    191	ret = dmaengine_slave_config(pair->dma_chan[!dir], &config_fe);
    192	if (ret) {
    193		dev_err(dev, "failed to config DMA channel for Front-End\n");
    194		return ret;
    195	}
    196
    197	/* Request and config DMA channel for Back-End */
    198	dma_cap_zero(mask);
    199	dma_cap_set(DMA_SLAVE, mask);
    200	dma_cap_set(DMA_CYCLIC, mask);
    201
    202	/*
    203	 * The Back-End device might have already requested a DMA channel,
    204	 * so try to reuse it first, and then request a new one upon NULL.
    205	 */
    206	component_be = snd_soc_lookup_component_nolocked(dev_be, SND_DMAENGINE_PCM_DRV_NAME);
    207	if (component_be) {
    208		be_chan = soc_component_to_pcm(component_be)->chan[substream->stream];
    209		tmp_chan = be_chan;
    210	}
    211	if (!tmp_chan)
    212		tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx");
    213
    214	/*
    215	 * An EDMA DEV_TO_DEV channel is fixed and bound with DMA event of each
    216	 * peripheral, unlike SDMA channel that is allocated dynamically. So no
    217	 * need to configure dma_request and dma_request2, but get dma_chan of
    218	 * Back-End device directly via dma_request_slave_channel.
    219	 */
    220	if (!asrc->use_edma) {
    221		/* Get DMA request of Back-End */
    222		tmp_data = tmp_chan->private;
    223		pair->dma_data.dma_request = tmp_data->dma_request;
    224		if (!be_chan)
    225			dma_release_channel(tmp_chan);
    226
    227		/* Get DMA request of Front-End */
    228		tmp_chan = asrc->get_dma_channel(pair, dir);
    229		tmp_data = tmp_chan->private;
    230		pair->dma_data.dma_request2 = tmp_data->dma_request;
    231		pair->dma_data.peripheral_type = tmp_data->peripheral_type;
    232		pair->dma_data.priority = tmp_data->priority;
    233		dma_release_channel(tmp_chan);
    234
    235		of_dma_node = pair->dma_chan[!dir]->device->dev->of_node;
    236		pair->dma_chan[dir] =
    237			__dma_request_channel(&mask, filter, &pair->dma_data,
    238					      of_dma_node);
    239		pair->req_dma_chan = true;
    240	} else {
    241		pair->dma_chan[dir] = tmp_chan;
    242		/* Do not flag to release if we are reusing the Back-End one */
    243		pair->req_dma_chan = !be_chan;
    244	}
    245
    246	if (!pair->dma_chan[dir]) {
    247		dev_err(dev, "failed to request DMA channel for Back-End\n");
    248		return -EINVAL;
    249	}
    250
    251	width = snd_pcm_format_physical_width(asrc->asrc_format);
    252	if (width < 8 || width > 64)
    253		return -EINVAL;
    254	else if (width == 8)
    255		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
    256	else if (width == 16)
    257		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
    258	else if (width == 24)
    259		buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES;
    260	else if (width <= 32)
    261		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
    262	else
    263		buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES;
    264
    265	config_be.direction = DMA_DEV_TO_DEV;
    266	config_be.src_addr_width = buswidth;
    267	config_be.src_maxburst = dma_params_be->maxburst;
    268	config_be.dst_addr_width = buswidth;
    269	config_be.dst_maxburst = dma_params_be->maxburst;
    270
    271	if (tx) {
    272		config_be.src_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index);
    273		config_be.dst_addr = dma_params_be->addr;
    274	} else {
    275		config_be.dst_addr = asrc->paddr + asrc->get_fifo_addr(IN, index);
    276		config_be.src_addr = dma_params_be->addr;
    277	}
    278
    279	ret = dmaengine_slave_config(pair->dma_chan[dir], &config_be);
    280	if (ret) {
    281		dev_err(dev, "failed to config DMA channel for Back-End\n");
    282		if (pair->req_dma_chan)
    283			dma_release_channel(pair->dma_chan[dir]);
    284		return ret;
    285	}
    286
    287	return 0;
    288}
    289
    290static int fsl_asrc_dma_hw_free(struct snd_soc_component *component,
    291				struct snd_pcm_substream *substream)
    292{
    293	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
    294	struct snd_pcm_runtime *runtime = substream->runtime;
    295	struct fsl_asrc_pair *pair = runtime->private_data;
    296	u8 dir = tx ? OUT : IN;
    297
    298	if (pair->dma_chan[!dir])
    299		dma_release_channel(pair->dma_chan[!dir]);
    300
    301	/* release dev_to_dev chan if we aren't reusing the Back-End one */
    302	if (pair->dma_chan[dir] && pair->req_dma_chan)
    303		dma_release_channel(pair->dma_chan[dir]);
    304
    305	pair->dma_chan[!dir] = NULL;
    306	pair->dma_chan[dir] = NULL;
    307
    308	return 0;
    309}
    310
    311static int fsl_asrc_dma_startup(struct snd_soc_component *component,
    312				struct snd_pcm_substream *substream)
    313{
    314	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
    315	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    316	struct snd_pcm_runtime *runtime = substream->runtime;
    317	struct snd_dmaengine_dai_dma_data *dma_data;
    318	struct device *dev = component->dev;
    319	struct fsl_asrc *asrc = dev_get_drvdata(dev);
    320	struct fsl_asrc_pair *pair;
    321	struct dma_chan *tmp_chan = NULL;
    322	u8 dir = tx ? OUT : IN;
    323	bool release_pair = true;
    324	int ret = 0;
    325
    326	ret = snd_pcm_hw_constraint_integer(substream->runtime,
    327					    SNDRV_PCM_HW_PARAM_PERIODS);
    328	if (ret < 0) {
    329		dev_err(dev, "failed to set pcm hw params periods\n");
    330		return ret;
    331	}
    332
    333	pair = kzalloc(sizeof(*pair) + asrc->pair_priv_size, GFP_KERNEL);
    334	if (!pair)
    335		return -ENOMEM;
    336
    337	pair->asrc = asrc;
    338	pair->private = (void *)pair + sizeof(struct fsl_asrc_pair);
    339
    340	runtime->private_data = pair;
    341
    342	/* Request a dummy pair, which will be released later.
    343	 * Request pair function needs channel num as input, for this
    344	 * dummy pair, we just request "1" channel temporarily.
    345	 */
    346	ret = asrc->request_pair(1, pair);
    347	if (ret < 0) {
    348		dev_err(dev, "failed to request asrc pair\n");
    349		goto req_pair_err;
    350	}
    351
    352	/* Request a dummy dma channel, which will be released later. */
    353	tmp_chan = asrc->get_dma_channel(pair, dir);
    354	if (!tmp_chan) {
    355		dev_err(dev, "failed to get dma channel\n");
    356		ret = -EINVAL;
    357		goto dma_chan_err;
    358	}
    359
    360	dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
    361
    362	/* Refine the snd_imx_hardware according to caps of DMA. */
    363	ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream,
    364							dma_data,
    365							&snd_imx_hardware,
    366							tmp_chan);
    367	if (ret < 0) {
    368		dev_err(dev, "failed to refine runtime hwparams\n");
    369		goto out;
    370	}
    371
    372	release_pair = false;
    373	snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
    374
    375out:
    376	dma_release_channel(tmp_chan);
    377
    378dma_chan_err:
    379	asrc->release_pair(pair);
    380
    381req_pair_err:
    382	if (release_pair)
    383		kfree(pair);
    384
    385	return ret;
    386}
    387
    388static int fsl_asrc_dma_shutdown(struct snd_soc_component *component,
    389				 struct snd_pcm_substream *substream)
    390{
    391	struct snd_pcm_runtime *runtime = substream->runtime;
    392	struct fsl_asrc_pair *pair = runtime->private_data;
    393	struct fsl_asrc *asrc;
    394
    395	if (!pair)
    396		return 0;
    397
    398	asrc = pair->asrc;
    399
    400	if (asrc->pair[pair->index] == pair)
    401		asrc->pair[pair->index] = NULL;
    402
    403	kfree(pair);
    404
    405	return 0;
    406}
    407
    408static snd_pcm_uframes_t
    409fsl_asrc_dma_pcm_pointer(struct snd_soc_component *component,
    410			 struct snd_pcm_substream *substream)
    411{
    412	struct snd_pcm_runtime *runtime = substream->runtime;
    413	struct fsl_asrc_pair *pair = runtime->private_data;
    414
    415	return bytes_to_frames(substream->runtime, pair->pos);
    416}
    417
    418static int fsl_asrc_dma_pcm_new(struct snd_soc_component *component,
    419				struct snd_soc_pcm_runtime *rtd)
    420{
    421	struct snd_card *card = rtd->card->snd_card;
    422	struct snd_pcm *pcm = rtd->pcm;
    423	int ret;
    424
    425	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
    426	if (ret) {
    427		dev_err(card->dev, "failed to set DMA mask\n");
    428		return ret;
    429	}
    430
    431	return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
    432					    card->dev, FSL_ASRC_DMABUF_SIZE);
    433}
    434
    435struct snd_soc_component_driver fsl_asrc_component = {
    436	.name		= DRV_NAME,
    437	.hw_params	= fsl_asrc_dma_hw_params,
    438	.hw_free	= fsl_asrc_dma_hw_free,
    439	.trigger	= fsl_asrc_dma_trigger,
    440	.open		= fsl_asrc_dma_startup,
    441	.close		= fsl_asrc_dma_shutdown,
    442	.pointer	= fsl_asrc_dma_pcm_pointer,
    443	.pcm_construct	= fsl_asrc_dma_pcm_new,
    444};
    445EXPORT_SYMBOL_GPL(fsl_asrc_component);