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

sprd-pcm-dma.c (12871B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (C) 2019 Spreadtrum Communications Inc.
      3
      4#include <linux/dma-mapping.h>
      5#include <linux/dmaengine.h>
      6#include <linux/dma/sprd-dma.h>
      7#include <linux/kernel.h>
      8#include <linux/module.h>
      9#include <linux/of_reserved_mem.h>
     10#include <linux/platform_device.h>
     11#include <sound/pcm.h>
     12#include <sound/pcm_params.h>
     13#include <sound/soc.h>
     14
     15#include "sprd-pcm-dma.h"
     16
     17#define SPRD_PCM_DMA_LINKLIST_SIZE	64
     18#define SPRD_PCM_DMA_BRUST_LEN		640
     19
     20struct sprd_pcm_dma_data {
     21	struct dma_chan *chan;
     22	struct dma_async_tx_descriptor *desc;
     23	dma_cookie_t cookie;
     24	dma_addr_t phys;
     25	void *virt;
     26	int pre_pointer;
     27};
     28
     29struct sprd_pcm_dma_private {
     30	struct snd_pcm_substream *substream;
     31	struct sprd_pcm_dma_params *params;
     32	struct sprd_pcm_dma_data data[SPRD_PCM_CHANNEL_MAX];
     33	int hw_chan;
     34	int dma_addr_offset;
     35};
     36
     37static const struct snd_pcm_hardware sprd_pcm_hardware = {
     38	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
     39		SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE |
     40		SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
     41	.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
     42	.period_bytes_min = 1,
     43	.period_bytes_max = 64 * 1024,
     44	.periods_min = 1,
     45	.periods_max = PAGE_SIZE / SPRD_PCM_DMA_LINKLIST_SIZE,
     46	.buffer_bytes_max = 64 * 1024,
     47};
     48
     49static int sprd_pcm_open(struct snd_soc_component *component,
     50			 struct snd_pcm_substream *substream)
     51{
     52	struct snd_pcm_runtime *runtime = substream->runtime;
     53	struct device *dev = component->dev;
     54	struct sprd_pcm_dma_private *dma_private;
     55	int hw_chan = SPRD_PCM_CHANNEL_MAX;
     56	int size, ret, i;
     57
     58	snd_soc_set_runtime_hwparams(substream, &sprd_pcm_hardware);
     59
     60	ret = snd_pcm_hw_constraint_step(runtime, 0,
     61					 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
     62					 SPRD_PCM_DMA_BRUST_LEN);
     63	if (ret < 0)
     64		return ret;
     65
     66	ret = snd_pcm_hw_constraint_step(runtime, 0,
     67					 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
     68					 SPRD_PCM_DMA_BRUST_LEN);
     69	if (ret < 0)
     70		return ret;
     71
     72	ret = snd_pcm_hw_constraint_integer(runtime,
     73					    SNDRV_PCM_HW_PARAM_PERIODS);
     74	if (ret < 0)
     75		return ret;
     76
     77	dma_private = devm_kzalloc(dev, sizeof(*dma_private), GFP_KERNEL);
     78	if (!dma_private)
     79		return -ENOMEM;
     80
     81	size = runtime->hw.periods_max * SPRD_PCM_DMA_LINKLIST_SIZE;
     82
     83	for (i = 0; i < hw_chan; i++) {
     84		struct sprd_pcm_dma_data *data = &dma_private->data[i];
     85
     86		data->virt = dmam_alloc_coherent(dev, size, &data->phys,
     87						 GFP_KERNEL);
     88		if (!data->virt) {
     89			ret = -ENOMEM;
     90			goto error;
     91		}
     92	}
     93
     94	dma_private->hw_chan = hw_chan;
     95	runtime->private_data = dma_private;
     96	dma_private->substream = substream;
     97
     98	return 0;
     99
    100error:
    101	for (i = 0; i < hw_chan; i++) {
    102		struct sprd_pcm_dma_data *data = &dma_private->data[i];
    103
    104		if (data->virt)
    105			dmam_free_coherent(dev, size, data->virt, data->phys);
    106	}
    107
    108	devm_kfree(dev, dma_private);
    109	return ret;
    110}
    111
    112static int sprd_pcm_close(struct snd_soc_component *component,
    113			  struct snd_pcm_substream *substream)
    114{
    115	struct snd_pcm_runtime *runtime = substream->runtime;
    116	struct sprd_pcm_dma_private *dma_private = runtime->private_data;
    117	struct device *dev = component->dev;
    118	int size = runtime->hw.periods_max * SPRD_PCM_DMA_LINKLIST_SIZE;
    119	int i;
    120
    121	for (i = 0; i < dma_private->hw_chan; i++) {
    122		struct sprd_pcm_dma_data *data = &dma_private->data[i];
    123
    124		dmam_free_coherent(dev, size, data->virt, data->phys);
    125	}
    126
    127	devm_kfree(dev, dma_private);
    128
    129	return 0;
    130}
    131
    132static void sprd_pcm_dma_complete(void *data)
    133{
    134	struct sprd_pcm_dma_private *dma_private = data;
    135	struct snd_pcm_substream *substream = dma_private->substream;
    136
    137	snd_pcm_period_elapsed(substream);
    138}
    139
    140static void sprd_pcm_release_dma_channel(struct snd_pcm_substream *substream)
    141{
    142	struct snd_pcm_runtime *runtime = substream->runtime;
    143	struct sprd_pcm_dma_private *dma_private = runtime->private_data;
    144	int i;
    145
    146	for (i = 0; i < SPRD_PCM_CHANNEL_MAX; i++) {
    147		struct sprd_pcm_dma_data *data = &dma_private->data[i];
    148
    149		if (data->chan) {
    150			dma_release_channel(data->chan);
    151			data->chan = NULL;
    152		}
    153	}
    154}
    155
    156static int sprd_pcm_request_dma_channel(struct snd_soc_component *component,
    157					struct snd_pcm_substream *substream,
    158					int channels)
    159{
    160	struct snd_pcm_runtime *runtime = substream->runtime;
    161	struct sprd_pcm_dma_private *dma_private = runtime->private_data;
    162	struct device *dev = component->dev;
    163	struct sprd_pcm_dma_params *dma_params = dma_private->params;
    164	int i;
    165
    166	if (channels > SPRD_PCM_CHANNEL_MAX) {
    167		dev_err(dev, "invalid dma channel number:%d\n", channels);
    168		return -EINVAL;
    169	}
    170
    171	for (i = 0; i < channels; i++) {
    172		struct sprd_pcm_dma_data *data = &dma_private->data[i];
    173
    174		data->chan = dma_request_slave_channel(dev,
    175						       dma_params->chan_name[i]);
    176		if (!data->chan) {
    177			dev_err(dev, "failed to request dma channel:%s\n",
    178				dma_params->chan_name[i]);
    179			sprd_pcm_release_dma_channel(substream);
    180			return -ENODEV;
    181		}
    182	}
    183
    184	return 0;
    185}
    186
    187static int sprd_pcm_hw_params(struct snd_soc_component *component,
    188			      struct snd_pcm_substream *substream,
    189			      struct snd_pcm_hw_params *params)
    190{
    191	struct snd_pcm_runtime *runtime = substream->runtime;
    192	struct sprd_pcm_dma_private *dma_private = runtime->private_data;
    193	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    194	struct sprd_pcm_dma_params *dma_params;
    195	size_t totsize = params_buffer_bytes(params);
    196	size_t period = params_period_bytes(params);
    197	int channels = params_channels(params);
    198	int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
    199	struct scatterlist *sg;
    200	unsigned long flags;
    201	int ret, i, j, sg_num;
    202
    203	dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
    204	if (!dma_params) {
    205		dev_warn(component->dev, "no dma parameters setting\n");
    206		dma_private->params = NULL;
    207		return 0;
    208	}
    209
    210	if (!dma_private->params) {
    211		dma_private->params = dma_params;
    212		ret = sprd_pcm_request_dma_channel(component,
    213						   substream, channels);
    214		if (ret)
    215			return ret;
    216	}
    217
    218	sg_num = totsize / period;
    219	dma_private->dma_addr_offset = totsize / channels;
    220
    221	sg = devm_kcalloc(component->dev, sg_num, sizeof(*sg), GFP_KERNEL);
    222	if (!sg) {
    223		ret = -ENOMEM;
    224		goto sg_err;
    225	}
    226
    227	for (i = 0; i < channels; i++) {
    228		struct sprd_pcm_dma_data *data = &dma_private->data[i];
    229		struct dma_chan *chan = data->chan;
    230		struct dma_slave_config config = { };
    231		struct sprd_dma_linklist link = { };
    232		enum dma_transfer_direction dir;
    233		struct scatterlist *sgt = sg;
    234
    235		config.src_maxburst = dma_params->fragment_len[i];
    236		config.src_addr_width = dma_params->datawidth[i];
    237		config.dst_addr_width = dma_params->datawidth[i];
    238		if (is_playback) {
    239			config.src_addr = runtime->dma_addr +
    240				i * dma_private->dma_addr_offset;
    241			config.dst_addr = dma_params->dev_phys[i];
    242			dir = DMA_MEM_TO_DEV;
    243		} else {
    244			config.src_addr = dma_params->dev_phys[i];
    245			config.dst_addr = runtime->dma_addr +
    246				i * dma_private->dma_addr_offset;
    247			dir = DMA_DEV_TO_MEM;
    248		}
    249
    250		sg_init_table(sgt, sg_num);
    251		for (j = 0; j < sg_num; j++, sgt++) {
    252			u32 sg_len = period / channels;
    253
    254			sg_dma_len(sgt) = sg_len;
    255			sg_dma_address(sgt) = runtime->dma_addr +
    256				i * dma_private->dma_addr_offset + sg_len * j;
    257		}
    258
    259		/*
    260		 * Configure the link-list address for the DMA engine link-list
    261		 * mode.
    262		 */
    263		link.virt_addr = (unsigned long)data->virt;
    264		link.phy_addr = data->phys;
    265
    266		ret = dmaengine_slave_config(chan, &config);
    267		if (ret) {
    268			dev_err(component->dev,
    269				"failed to set slave configuration: %d\n", ret);
    270			goto config_err;
    271		}
    272
    273		/*
    274		 * We configure the DMA request mode, interrupt mode, channel
    275		 * mode and channel trigger mode by the flags.
    276		 */
    277		flags = SPRD_DMA_FLAGS(SPRD_DMA_CHN_MODE_NONE, SPRD_DMA_NO_TRG,
    278				       SPRD_DMA_FRAG_REQ, SPRD_DMA_TRANS_INT);
    279		data->desc = chan->device->device_prep_slave_sg(chan, sg,
    280								sg_num, dir,
    281								flags, &link);
    282		if (!data->desc) {
    283			dev_err(component->dev, "failed to prepare slave sg\n");
    284			ret = -ENOMEM;
    285			goto config_err;
    286		}
    287
    288		if (!runtime->no_period_wakeup) {
    289			data->desc->callback = sprd_pcm_dma_complete;
    290			data->desc->callback_param = dma_private;
    291		}
    292	}
    293
    294	devm_kfree(component->dev, sg);
    295
    296	return 0;
    297
    298config_err:
    299	devm_kfree(component->dev, sg);
    300sg_err:
    301	sprd_pcm_release_dma_channel(substream);
    302	return ret;
    303}
    304
    305static int sprd_pcm_hw_free(struct snd_soc_component *component,
    306			    struct snd_pcm_substream *substream)
    307{
    308	sprd_pcm_release_dma_channel(substream);
    309
    310	return 0;
    311}
    312
    313static int sprd_pcm_trigger(struct snd_soc_component *component,
    314			    struct snd_pcm_substream *substream, int cmd)
    315{
    316	struct sprd_pcm_dma_private *dma_private =
    317		substream->runtime->private_data;
    318	int ret = 0, i;
    319
    320	switch (cmd) {
    321	case SNDRV_PCM_TRIGGER_START:
    322		for (i = 0; i < dma_private->hw_chan; i++) {
    323			struct sprd_pcm_dma_data *data = &dma_private->data[i];
    324
    325			if (!data->desc)
    326				continue;
    327
    328			data->cookie = dmaengine_submit(data->desc);
    329			ret = dma_submit_error(data->cookie);
    330			if (ret) {
    331				dev_err(component->dev,
    332					"failed to submit dma request: %d\n",
    333					ret);
    334				return ret;
    335			}
    336
    337			dma_async_issue_pending(data->chan);
    338		}
    339
    340		break;
    341	case SNDRV_PCM_TRIGGER_RESUME:
    342	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    343		for (i = 0; i < dma_private->hw_chan; i++) {
    344			struct sprd_pcm_dma_data *data = &dma_private->data[i];
    345
    346			if (data->chan)
    347				dmaengine_resume(data->chan);
    348		}
    349
    350		break;
    351	case SNDRV_PCM_TRIGGER_STOP:
    352		for (i = 0; i < dma_private->hw_chan; i++) {
    353			struct sprd_pcm_dma_data *data = &dma_private->data[i];
    354
    355			if (data->chan)
    356				dmaengine_terminate_async(data->chan);
    357		}
    358
    359		break;
    360	case SNDRV_PCM_TRIGGER_SUSPEND:
    361	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    362		for (i = 0; i < dma_private->hw_chan; i++) {
    363			struct sprd_pcm_dma_data *data = &dma_private->data[i];
    364
    365			if (data->chan)
    366				dmaengine_pause(data->chan);
    367		}
    368
    369		break;
    370	default:
    371		ret = -EINVAL;
    372	}
    373
    374	return ret;
    375}
    376
    377static snd_pcm_uframes_t sprd_pcm_pointer(struct snd_soc_component *component,
    378					  struct snd_pcm_substream *substream)
    379{
    380	struct snd_pcm_runtime *runtime = substream->runtime;
    381	struct sprd_pcm_dma_private *dma_private = runtime->private_data;
    382	int pointer[SPRD_PCM_CHANNEL_MAX];
    383	int bytes_of_pointer = 0, sel_max = 0, i;
    384	snd_pcm_uframes_t x;
    385	struct dma_tx_state state;
    386	enum dma_status status;
    387
    388	for (i = 0; i < dma_private->hw_chan; i++) {
    389		struct sprd_pcm_dma_data *data = &dma_private->data[i];
    390
    391		if (!data->chan)
    392			continue;
    393
    394		status = dmaengine_tx_status(data->chan, data->cookie, &state);
    395		if (status == DMA_ERROR) {
    396			dev_err(component->dev,
    397				"failed to get dma channel %d status\n", i);
    398			return 0;
    399		}
    400
    401		/*
    402		 * We just get current transfer address from the DMA engine, so
    403		 * we need convert to current pointer.
    404		 */
    405		pointer[i] = state.residue - runtime->dma_addr -
    406			i * dma_private->dma_addr_offset;
    407
    408		if (i == 0) {
    409			bytes_of_pointer = pointer[i];
    410			sel_max = pointer[i] < data->pre_pointer ? 1 : 0;
    411		} else {
    412			sel_max ^= pointer[i] < data->pre_pointer ? 1 : 0;
    413
    414			if (sel_max)
    415				bytes_of_pointer =
    416					max(pointer[i], pointer[i - 1]) << 1;
    417			else
    418				bytes_of_pointer =
    419					min(pointer[i], pointer[i - 1]) << 1;
    420		}
    421
    422		data->pre_pointer = pointer[i];
    423	}
    424
    425	x = bytes_to_frames(runtime, bytes_of_pointer);
    426	if (x == runtime->buffer_size)
    427		x = 0;
    428
    429	return x;
    430}
    431
    432static int sprd_pcm_new(struct snd_soc_component *component,
    433			struct snd_soc_pcm_runtime *rtd)
    434{
    435	struct snd_card *card = rtd->card->snd_card;
    436	struct snd_pcm *pcm = rtd->pcm;
    437	int ret;
    438
    439	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
    440	if (ret)
    441		return ret;
    442
    443	return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
    444					    card->dev,
    445					    sprd_pcm_hardware.buffer_bytes_max);
    446}
    447
    448static const struct snd_soc_component_driver sprd_soc_component = {
    449	.name		= DRV_NAME,
    450	.open		= sprd_pcm_open,
    451	.close		= sprd_pcm_close,
    452	.hw_params	= sprd_pcm_hw_params,
    453	.hw_free	= sprd_pcm_hw_free,
    454	.trigger	= sprd_pcm_trigger,
    455	.pointer	= sprd_pcm_pointer,
    456	.pcm_construct	= sprd_pcm_new,
    457	.compress_ops	= &sprd_platform_compress_ops,
    458};
    459
    460static int sprd_soc_platform_probe(struct platform_device *pdev)
    461{
    462	struct device_node *np = pdev->dev.of_node;
    463	int ret;
    464
    465	ret = of_reserved_mem_device_init_by_idx(&pdev->dev, np, 0);
    466	if (ret)
    467		dev_warn(&pdev->dev,
    468			 "no reserved DMA memory for audio platform device\n");
    469
    470	ret = devm_snd_soc_register_component(&pdev->dev, &sprd_soc_component,
    471					      NULL, 0);
    472	if (ret)
    473		dev_err(&pdev->dev, "could not register platform:%d\n", ret);
    474
    475	return ret;
    476}
    477
    478static const struct of_device_id sprd_pcm_of_match[] = {
    479	{ .compatible = "sprd,pcm-platform", },
    480	{ },
    481};
    482MODULE_DEVICE_TABLE(of, sprd_pcm_of_match);
    483
    484static struct platform_driver sprd_pcm_driver = {
    485	.driver = {
    486		.name = "sprd-pcm-audio",
    487		.of_match_table = sprd_pcm_of_match,
    488	},
    489
    490	.probe = sprd_soc_platform_probe,
    491};
    492
    493module_platform_driver(sprd_pcm_driver);
    494
    495MODULE_DESCRIPTION("Spreadtrum ASoC PCM DMA");
    496MODULE_LICENSE("GPL v2");
    497MODULE_ALIAS("platform:sprd-audio");