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

aiu-fifo-spdif.c (4956B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Copyright (c) 2020 BayLibre, SAS.
      4// Author: Jerome Brunet <jbrunet@baylibre.com>
      5
      6#include <linux/clk.h>
      7#include <sound/pcm_params.h>
      8#include <sound/soc.h>
      9#include <sound/soc-dai.h>
     10
     11#include "aiu.h"
     12#include "aiu-fifo.h"
     13
     14#define AIU_IEC958_DCU_FF_CTRL_EN		BIT(0)
     15#define AIU_IEC958_DCU_FF_CTRL_AUTO_DISABLE	BIT(1)
     16#define AIU_IEC958_DCU_FF_CTRL_IRQ_MODE		GENMASK(3, 2)
     17#define AIU_IEC958_DCU_FF_CTRL_IRQ_OUT_THD	BIT(2)
     18#define AIU_IEC958_DCU_FF_CTRL_IRQ_FRAME_READ	BIT(3)
     19#define AIU_IEC958_DCU_FF_CTRL_SYNC_HEAD_EN	BIT(4)
     20#define AIU_IEC958_DCU_FF_CTRL_BYTE_SEEK	BIT(5)
     21#define AIU_IEC958_DCU_FF_CTRL_CONTINUE		BIT(6)
     22#define AIU_MEM_IEC958_CONTROL_ENDIAN		GENMASK(5, 3)
     23#define AIU_MEM_IEC958_CONTROL_RD_DDR		BIT(6)
     24#define AIU_MEM_IEC958_CONTROL_MODE_16BIT	BIT(7)
     25#define AIU_MEM_IEC958_CONTROL_MODE_LINEAR	BIT(8)
     26#define AIU_MEM_IEC958_BUF_CNTL_INIT		BIT(0)
     27
     28#define AIU_FIFO_SPDIF_BLOCK			8
     29
     30static struct snd_pcm_hardware fifo_spdif_pcm = {
     31	.info = (SNDRV_PCM_INFO_INTERLEAVED |
     32		 SNDRV_PCM_INFO_MMAP |
     33		 SNDRV_PCM_INFO_MMAP_VALID |
     34		 SNDRV_PCM_INFO_PAUSE),
     35	.formats = AIU_FORMATS,
     36	.rate_min = 5512,
     37	.rate_max = 192000,
     38	.channels_min = 2,
     39	.channels_max = 2,
     40	.period_bytes_min = AIU_FIFO_SPDIF_BLOCK,
     41	.period_bytes_max = AIU_FIFO_SPDIF_BLOCK * USHRT_MAX,
     42	.periods_min = 2,
     43	.periods_max = UINT_MAX,
     44
     45	/* No real justification for this */
     46	.buffer_bytes_max = 1 * 1024 * 1024,
     47};
     48
     49static void fifo_spdif_dcu_enable(struct snd_soc_component *component,
     50				  bool enable)
     51{
     52	snd_soc_component_update_bits(component, AIU_IEC958_DCU_FF_CTRL,
     53				      AIU_IEC958_DCU_FF_CTRL_EN,
     54				      enable ? AIU_IEC958_DCU_FF_CTRL_EN : 0);
     55}
     56
     57static int fifo_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
     58			      struct snd_soc_dai *dai)
     59{
     60	struct snd_soc_component *component = dai->component;
     61	int ret;
     62
     63	ret = aiu_fifo_trigger(substream, cmd, dai);
     64	if (ret)
     65		return ret;
     66
     67	switch (cmd) {
     68	case SNDRV_PCM_TRIGGER_START:
     69	case SNDRV_PCM_TRIGGER_RESUME:
     70	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
     71		fifo_spdif_dcu_enable(component, true);
     72		break;
     73	case SNDRV_PCM_TRIGGER_SUSPEND:
     74	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
     75	case SNDRV_PCM_TRIGGER_STOP:
     76		fifo_spdif_dcu_enable(component, false);
     77		break;
     78	default:
     79		return -EINVAL;
     80	}
     81
     82	return 0;
     83}
     84
     85static int fifo_spdif_prepare(struct snd_pcm_substream *substream,
     86			      struct snd_soc_dai *dai)
     87{
     88	struct snd_soc_component *component = dai->component;
     89	int ret;
     90
     91	ret = aiu_fifo_prepare(substream, dai);
     92	if (ret)
     93		return ret;
     94
     95	snd_soc_component_update_bits(component,
     96				      AIU_MEM_IEC958_BUF_CNTL,
     97				      AIU_MEM_IEC958_BUF_CNTL_INIT,
     98				      AIU_MEM_IEC958_BUF_CNTL_INIT);
     99	snd_soc_component_update_bits(component,
    100				      AIU_MEM_IEC958_BUF_CNTL,
    101				      AIU_MEM_IEC958_BUF_CNTL_INIT, 0);
    102
    103	return 0;
    104}
    105
    106static int fifo_spdif_hw_params(struct snd_pcm_substream *substream,
    107				struct snd_pcm_hw_params *params,
    108				struct snd_soc_dai *dai)
    109{
    110	struct snd_soc_component *component = dai->component;
    111	unsigned int val;
    112	int ret;
    113
    114	ret = aiu_fifo_hw_params(substream, params, dai);
    115	if (ret)
    116		return ret;
    117
    118	val = AIU_MEM_IEC958_CONTROL_RD_DDR |
    119	      AIU_MEM_IEC958_CONTROL_MODE_LINEAR;
    120
    121	switch (params_physical_width(params)) {
    122	case 16:
    123		val |= AIU_MEM_IEC958_CONTROL_MODE_16BIT;
    124		break;
    125	case 32:
    126		break;
    127	default:
    128		dev_err(dai->dev, "Unsupported physical width %u\n",
    129			params_physical_width(params));
    130		return -EINVAL;
    131	}
    132
    133	snd_soc_component_update_bits(component, AIU_MEM_IEC958_CONTROL,
    134				      AIU_MEM_IEC958_CONTROL_ENDIAN |
    135				      AIU_MEM_IEC958_CONTROL_RD_DDR |
    136				      AIU_MEM_IEC958_CONTROL_MODE_LINEAR |
    137				      AIU_MEM_IEC958_CONTROL_MODE_16BIT,
    138				      val);
    139
    140	/* Number bytes read by the FIFO between each IRQ */
    141	snd_soc_component_write(component, AIU_IEC958_BPF,
    142				params_period_bytes(params));
    143
    144	/*
    145	 * AUTO_DISABLE and SYNC_HEAD are enabled by default but
    146	 * this should be disabled in PCM (uncompressed) mode
    147	 */
    148	snd_soc_component_update_bits(component, AIU_IEC958_DCU_FF_CTRL,
    149				      AIU_IEC958_DCU_FF_CTRL_AUTO_DISABLE |
    150				      AIU_IEC958_DCU_FF_CTRL_IRQ_MODE |
    151				      AIU_IEC958_DCU_FF_CTRL_SYNC_HEAD_EN,
    152				      AIU_IEC958_DCU_FF_CTRL_IRQ_FRAME_READ);
    153
    154	return 0;
    155}
    156
    157const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = {
    158	.trigger	= fifo_spdif_trigger,
    159	.prepare	= fifo_spdif_prepare,
    160	.hw_params	= fifo_spdif_hw_params,
    161	.startup	= aiu_fifo_startup,
    162	.shutdown	= aiu_fifo_shutdown,
    163};
    164
    165int aiu_fifo_spdif_dai_probe(struct snd_soc_dai *dai)
    166{
    167	struct snd_soc_component *component = dai->component;
    168	struct aiu *aiu = snd_soc_component_get_drvdata(component);
    169	struct aiu_fifo *fifo;
    170	int ret;
    171
    172	ret = aiu_fifo_dai_probe(dai);
    173	if (ret)
    174		return ret;
    175
    176	fifo = dai->playback_dma_data;
    177
    178	fifo->pcm = &fifo_spdif_pcm;
    179	fifo->mem_offset = AIU_MEM_IEC958_START;
    180	fifo->fifo_block = 1;
    181	fifo->pclk = aiu->spdif.clks[PCLK].clk;
    182	fifo->irq = aiu->spdif.irq;
    183
    184	return 0;
    185}