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

mmp-pcm.c (6668B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * linux/sound/soc/pxa/mmp-pcm.c
      4 *
      5 * Copyright (C) 2011 Marvell International Ltd.
      6 */
      7#include <linux/module.h>
      8#include <linux/init.h>
      9#include <linux/platform_device.h>
     10#include <linux/slab.h>
     11#include <linux/dma-mapping.h>
     12#include <linux/dmaengine.h>
     13#include <linux/platform_data/dma-mmp_tdma.h>
     14#include <linux/platform_data/mmp_audio.h>
     15
     16#include <sound/pxa2xx-lib.h>
     17#include <sound/core.h>
     18#include <sound/pcm.h>
     19#include <sound/pcm_params.h>
     20#include <sound/soc.h>
     21#include <sound/dmaengine_pcm.h>
     22
     23#define DRV_NAME "mmp-pcm"
     24
     25struct mmp_dma_data {
     26	int ssp_id;
     27	struct resource *dma_res;
     28};
     29
     30#define MMP_PCM_INFO (SNDRV_PCM_INFO_MMAP |	\
     31		SNDRV_PCM_INFO_MMAP_VALID |	\
     32		SNDRV_PCM_INFO_INTERLEAVED |	\
     33		SNDRV_PCM_INFO_PAUSE |		\
     34		SNDRV_PCM_INFO_RESUME |		\
     35		SNDRV_PCM_INFO_NO_PERIOD_WAKEUP)
     36
     37static struct snd_pcm_hardware mmp_pcm_hardware[] = {
     38	{
     39		.info			= MMP_PCM_INFO,
     40		.period_bytes_min	= 1024,
     41		.period_bytes_max	= 2048,
     42		.periods_min		= 2,
     43		.periods_max		= 32,
     44		.buffer_bytes_max	= 4096,
     45		.fifo_size		= 32,
     46	},
     47	{
     48		.info			= MMP_PCM_INFO,
     49		.period_bytes_min	= 1024,
     50		.period_bytes_max	= 2048,
     51		.periods_min		= 2,
     52		.periods_max		= 32,
     53		.buffer_bytes_max	= 4096,
     54		.fifo_size		= 32,
     55	},
     56};
     57
     58static int mmp_pcm_hw_params(struct snd_soc_component *component,
     59			     struct snd_pcm_substream *substream,
     60			     struct snd_pcm_hw_params *params)
     61{
     62	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
     63	struct dma_slave_config slave_config;
     64	int ret;
     65
     66	ret =
     67	    snd_dmaengine_pcm_prepare_slave_config(substream, params,
     68						   &slave_config);
     69	if (ret)
     70		return ret;
     71
     72	ret = dmaengine_slave_config(chan, &slave_config);
     73	if (ret)
     74		return ret;
     75
     76	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
     77
     78	return 0;
     79}
     80
     81static int mmp_pcm_trigger(struct snd_soc_component *component,
     82			   struct snd_pcm_substream *substream, int cmd)
     83{
     84	return snd_dmaengine_pcm_trigger(substream, cmd);
     85}
     86
     87static snd_pcm_uframes_t mmp_pcm_pointer(struct snd_soc_component *component,
     88					 struct snd_pcm_substream *substream)
     89{
     90	return snd_dmaengine_pcm_pointer(substream);
     91}
     92
     93static bool filter(struct dma_chan *chan, void *param)
     94{
     95	struct mmp_dma_data *dma_data = param;
     96	bool found = false;
     97	char *devname;
     98
     99	devname = kasprintf(GFP_KERNEL, "%s.%d", dma_data->dma_res->name,
    100		dma_data->ssp_id);
    101	if ((strcmp(dev_name(chan->device->dev), devname) == 0) &&
    102		(chan->chan_id == dma_data->dma_res->start)) {
    103		found = true;
    104	}
    105
    106	kfree(devname);
    107	return found;
    108}
    109
    110static int mmp_pcm_open(struct snd_soc_component *component,
    111			struct snd_pcm_substream *substream)
    112{
    113	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    114	struct platform_device *pdev = to_platform_device(component->dev);
    115	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    116	struct mmp_dma_data dma_data;
    117	struct resource *r;
    118
    119	r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream);
    120	if (!r)
    121		return -EBUSY;
    122
    123	snd_soc_set_runtime_hwparams(substream,
    124				&mmp_pcm_hardware[substream->stream]);
    125
    126	dma_data.dma_res = r;
    127	dma_data.ssp_id = cpu_dai->id;
    128
    129	return snd_dmaengine_pcm_open_request_chan(substream, filter,
    130		    &dma_data);
    131}
    132
    133static int mmp_pcm_close(struct snd_soc_component *component,
    134			 struct snd_pcm_substream *substream)
    135{
    136	return snd_dmaengine_pcm_close_release_chan(substream);
    137}
    138
    139static int mmp_pcm_mmap(struct snd_soc_component *component,
    140			struct snd_pcm_substream *substream,
    141			struct vm_area_struct *vma)
    142{
    143	struct snd_pcm_runtime *runtime = substream->runtime;
    144	unsigned long off = vma->vm_pgoff;
    145
    146	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    147	return remap_pfn_range(vma, vma->vm_start,
    148		__phys_to_pfn(runtime->dma_addr) + off,
    149		vma->vm_end - vma->vm_start, vma->vm_page_prot);
    150}
    151
    152static void mmp_pcm_free_dma_buffers(struct snd_soc_component *component,
    153				     struct snd_pcm *pcm)
    154{
    155	struct snd_pcm_substream *substream;
    156	struct snd_dma_buffer *buf;
    157	int stream;
    158	struct gen_pool *gpool;
    159
    160	gpool = sram_get_gpool("asram");
    161	if (!gpool)
    162		return;
    163
    164	for (stream = 0; stream < 2; stream++) {
    165		size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
    166
    167		substream = pcm->streams[stream].substream;
    168		if (!substream)
    169			continue;
    170
    171		buf = &substream->dma_buffer;
    172		if (!buf->area)
    173			continue;
    174		gen_pool_free(gpool, (unsigned long)buf->area, size);
    175		buf->area = NULL;
    176	}
    177
    178}
    179
    180static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream,
    181								int stream)
    182{
    183	struct snd_dma_buffer *buf = &substream->dma_buffer;
    184	size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
    185	struct gen_pool *gpool;
    186
    187	buf->dev.type = SNDRV_DMA_TYPE_DEV;
    188	buf->dev.dev = substream->pcm->card->dev;
    189	buf->private_data = NULL;
    190
    191	gpool = sram_get_gpool("asram");
    192	if (!gpool)
    193		return -ENOMEM;
    194
    195	buf->area = gen_pool_dma_alloc(gpool, size, &buf->addr);
    196	if (!buf->area)
    197		return -ENOMEM;
    198	buf->bytes = size;
    199	return 0;
    200}
    201
    202static int mmp_pcm_new(struct snd_soc_component *component,
    203		       struct snd_soc_pcm_runtime *rtd)
    204{
    205	struct snd_pcm_substream *substream;
    206	struct snd_pcm *pcm = rtd->pcm;
    207	int ret, stream;
    208
    209	for (stream = 0; stream < 2; stream++) {
    210		substream = pcm->streams[stream].substream;
    211
    212		ret = mmp_pcm_preallocate_dma_buffer(substream,	stream);
    213		if (ret)
    214			goto err;
    215	}
    216
    217	return 0;
    218
    219err:
    220	mmp_pcm_free_dma_buffers(component, pcm);
    221	return ret;
    222}
    223
    224static const struct snd_soc_component_driver mmp_soc_component = {
    225	.name		= DRV_NAME,
    226	.open		= mmp_pcm_open,
    227	.close		= mmp_pcm_close,
    228	.hw_params	= mmp_pcm_hw_params,
    229	.trigger	= mmp_pcm_trigger,
    230	.pointer	= mmp_pcm_pointer,
    231	.mmap		= mmp_pcm_mmap,
    232	.pcm_construct	= mmp_pcm_new,
    233	.pcm_destruct	= mmp_pcm_free_dma_buffers,
    234};
    235
    236static int mmp_pcm_probe(struct platform_device *pdev)
    237{
    238	struct mmp_audio_platdata *pdata = pdev->dev.platform_data;
    239
    240	if (pdata) {
    241		mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].buffer_bytes_max =
    242						pdata->buffer_max_playback;
    243		mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].period_bytes_max =
    244						pdata->period_max_playback;
    245		mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].buffer_bytes_max =
    246						pdata->buffer_max_capture;
    247		mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].period_bytes_max =
    248						pdata->period_max_capture;
    249	}
    250	return devm_snd_soc_register_component(&pdev->dev, &mmp_soc_component,
    251					       NULL, 0);
    252}
    253
    254static struct platform_driver mmp_pcm_driver = {
    255	.driver = {
    256		.name = "mmp-pcm-audio",
    257	},
    258
    259	.probe = mmp_pcm_probe,
    260};
    261
    262module_platform_driver(mmp_pcm_driver);
    263
    264MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
    265MODULE_DESCRIPTION("MMP Soc Audio DMA module");
    266MODULE_LICENSE("GPL");
    267MODULE_ALIAS("platform:mmp-pcm-audio");