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

ux500_pcm.c (4784B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) ST-Ericsson SA 2012
      4 *
      5 * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
      6 *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
      7 *         for ST-Ericsson.
      8 *
      9 * License terms:
     10 */
     11
     12#include <asm/page.h>
     13
     14#include <linux/module.h>
     15#include <linux/dma-mapping.h>
     16#include <linux/dmaengine.h>
     17#include <linux/slab.h>
     18#include <linux/platform_data/dma-ste-dma40.h>
     19
     20#include <sound/pcm.h>
     21#include <sound/pcm_params.h>
     22#include <sound/soc.h>
     23#include <sound/dmaengine_pcm.h>
     24
     25#include "ux500_msp_i2s.h"
     26#include "ux500_pcm.h"
     27
     28#define UX500_PLATFORM_PERIODS_BYTES_MIN	128
     29#define UX500_PLATFORM_PERIODS_BYTES_MAX	(64 * PAGE_SIZE)
     30#define UX500_PLATFORM_PERIODS_MIN		2
     31#define UX500_PLATFORM_PERIODS_MAX		48
     32#define UX500_PLATFORM_BUFFER_BYTES_MAX		(2048 * PAGE_SIZE)
     33
     34static const struct snd_pcm_hardware ux500_pcm_hw = {
     35	.info = SNDRV_PCM_INFO_INTERLEAVED |
     36		SNDRV_PCM_INFO_MMAP |
     37		SNDRV_PCM_INFO_RESUME |
     38		SNDRV_PCM_INFO_PAUSE,
     39	.buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
     40	.period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
     41	.period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
     42	.periods_min = UX500_PLATFORM_PERIODS_MIN,
     43	.periods_max = UX500_PLATFORM_PERIODS_MAX,
     44};
     45
     46static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
     47	struct snd_pcm_substream *substream)
     48{
     49	struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
     50	u16 per_data_width, mem_data_width;
     51	struct stedma40_chan_cfg *dma_cfg;
     52	struct ux500_msp_dma_params *dma_params;
     53
     54	dma_params = snd_soc_dai_get_dma_data(dai, substream);
     55	dma_cfg = dma_params->dma_cfg;
     56
     57	mem_data_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
     58
     59	switch (dma_params->data_size) {
     60	case 32:
     61		per_data_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
     62		break;
     63	case 16:
     64		per_data_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
     65		break;
     66	case 8:
     67		per_data_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
     68		break;
     69	default:
     70		per_data_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
     71	}
     72
     73	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
     74		dma_cfg->src_info.data_width = mem_data_width;
     75		dma_cfg->dst_info.data_width = per_data_width;
     76	} else {
     77		dma_cfg->src_info.data_width = per_data_width;
     78		dma_cfg->dst_info.data_width = mem_data_width;
     79	}
     80
     81	return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg);
     82}
     83
     84static int ux500_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
     85		struct snd_pcm_hw_params *params,
     86		struct dma_slave_config *slave_config)
     87{
     88	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
     89	struct msp_i2s_platform_data *pdata = asoc_rtd_to_cpu(rtd, 0)->dev->platform_data;
     90	struct snd_dmaengine_dai_dma_data *snd_dma_params;
     91	struct ux500_msp_dma_params *ste_dma_params;
     92	dma_addr_t dma_addr;
     93	int ret;
     94
     95	if (pdata) {
     96		ste_dma_params =
     97			snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
     98		dma_addr = ste_dma_params->tx_rx_addr;
     99	} else {
    100		snd_dma_params =
    101			snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
    102		dma_addr = snd_dma_params->addr;
    103	}
    104
    105	ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
    106	if (ret)
    107		return ret;
    108
    109	slave_config->dst_maxburst = 4;
    110	slave_config->src_maxburst = 4;
    111
    112	slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
    113	slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
    114
    115	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    116		slave_config->dst_addr = dma_addr;
    117	else
    118		slave_config->src_addr = dma_addr;
    119
    120	return 0;
    121}
    122
    123static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = {
    124	.pcm_hardware = &ux500_pcm_hw,
    125	.compat_request_channel = ux500_pcm_request_chan,
    126	.prealloc_buffer_size = 128 * 1024,
    127	.prepare_slave_config = ux500_pcm_prepare_slave_config,
    128};
    129
    130static const struct snd_dmaengine_pcm_config ux500_dmaengine_of_pcm_config = {
    131	.compat_request_channel = ux500_pcm_request_chan,
    132	.prepare_slave_config = ux500_pcm_prepare_slave_config,
    133};
    134
    135int ux500_pcm_register_platform(struct platform_device *pdev)
    136{
    137	const struct snd_dmaengine_pcm_config *pcm_config;
    138	struct device_node *np = pdev->dev.of_node;
    139	int ret;
    140
    141	if (np)
    142		pcm_config = &ux500_dmaengine_of_pcm_config;
    143	else
    144		pcm_config = &ux500_dmaengine_pcm_config;
    145
    146	ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config,
    147					 SND_DMAENGINE_PCM_FLAG_COMPAT);
    148	if (ret < 0) {
    149		dev_err(&pdev->dev,
    150			"%s: ERROR: Failed to register platform '%s' (%d)!\n",
    151			__func__, pdev->name, ret);
    152		return ret;
    153	}
    154
    155	return 0;
    156}
    157EXPORT_SYMBOL_GPL(ux500_pcm_register_platform);
    158
    159int ux500_pcm_unregister_platform(struct platform_device *pdev)
    160{
    161	snd_dmaengine_pcm_unregister(&pdev->dev);
    162	return 0;
    163}
    164EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform);
    165
    166MODULE_AUTHOR("Ola Lilja");
    167MODULE_AUTHOR("Roger Nilsson");
    168MODULE_DESCRIPTION("ASoC UX500 driver");
    169MODULE_LICENSE("GPL v2");