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

hda-pcm.c (8118B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
      2//
      3// This file is provided under a dual BSD/GPLv2 license.  When using or
      4// redistributing this file, you may do so under either license.
      5//
      6// Copyright(c) 2018 Intel Corporation. All rights reserved.
      7//
      8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
      9//	    Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
     10//	    Rander Wang <rander.wang@intel.com>
     11//          Keyon Jie <yang.jie@linux.intel.com>
     12//
     13
     14/*
     15 * Hardware interface for generic Intel audio DSP HDA IP
     16 */
     17
     18#include <linux/moduleparam.h>
     19#include <sound/hda_register.h>
     20#include <sound/pcm_params.h>
     21#include "../sof-audio.h"
     22#include "../ops.h"
     23#include "hda.h"
     24
     25#define SDnFMT_BASE(x)	((x) << 14)
     26#define SDnFMT_MULT(x)	(((x) - 1) << 11)
     27#define SDnFMT_DIV(x)	(((x) - 1) << 8)
     28#define SDnFMT_BITS(x)	((x) << 4)
     29#define SDnFMT_CHAN(x)	((x) << 0)
     30
     31static bool hda_always_enable_dmi_l1;
     32module_param_named(always_enable_dmi_l1, hda_always_enable_dmi_l1, bool, 0444);
     33MODULE_PARM_DESC(always_enable_dmi_l1, "SOF HDA always enable DMI l1");
     34
     35static bool hda_disable_rewinds = IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_DISABLE_REWINDS);
     36module_param_named(disable_rewinds, hda_disable_rewinds, bool, 0444);
     37MODULE_PARM_DESC(disable_rewinds, "SOF HDA disable rewinds");
     38
     39u32 hda_dsp_get_mult_div(struct snd_sof_dev *sdev, int rate)
     40{
     41	switch (rate) {
     42	case 8000:
     43		return SDnFMT_DIV(6);
     44	case 9600:
     45		return SDnFMT_DIV(5);
     46	case 11025:
     47		return SDnFMT_BASE(1) | SDnFMT_DIV(4);
     48	case 16000:
     49		return SDnFMT_DIV(3);
     50	case 22050:
     51		return SDnFMT_BASE(1) | SDnFMT_DIV(2);
     52	case 32000:
     53		return SDnFMT_DIV(3) | SDnFMT_MULT(2);
     54	case 44100:
     55		return SDnFMT_BASE(1);
     56	case 48000:
     57		return 0;
     58	case 88200:
     59		return SDnFMT_BASE(1) | SDnFMT_MULT(2);
     60	case 96000:
     61		return SDnFMT_MULT(2);
     62	case 176400:
     63		return SDnFMT_BASE(1) | SDnFMT_MULT(4);
     64	case 192000:
     65		return SDnFMT_MULT(4);
     66	default:
     67		dev_warn(sdev->dev, "can't find div rate %d using 48kHz\n",
     68			 rate);
     69		return 0; /* use 48KHz if not found */
     70	}
     71};
     72
     73u32 hda_dsp_get_bits(struct snd_sof_dev *sdev, int sample_bits)
     74{
     75	switch (sample_bits) {
     76	case 8:
     77		return SDnFMT_BITS(0);
     78	case 16:
     79		return SDnFMT_BITS(1);
     80	case 20:
     81		return SDnFMT_BITS(2);
     82	case 24:
     83		return SDnFMT_BITS(3);
     84	case 32:
     85		return SDnFMT_BITS(4);
     86	default:
     87		dev_warn(sdev->dev, "can't find %d bits using 16bit\n",
     88			 sample_bits);
     89		return SDnFMT_BITS(1); /* use 16bits format if not found */
     90	}
     91};
     92
     93int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
     94			  struct snd_pcm_substream *substream,
     95			  struct snd_pcm_hw_params *params,
     96			  struct snd_sof_platform_stream_params *platform_params)
     97{
     98	struct hdac_stream *hstream = substream->runtime->private_data;
     99	struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
    100	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
    101	struct snd_dma_buffer *dmab;
    102	int ret;
    103	u32 size, rate, bits;
    104
    105	size = params_buffer_bytes(params);
    106	rate = hda_dsp_get_mult_div(sdev, params_rate(params));
    107	bits = hda_dsp_get_bits(sdev, params_width(params));
    108
    109	hstream->substream = substream;
    110
    111	dmab = substream->runtime->dma_buffer_p;
    112
    113	hstream->format_val = rate | bits | (params_channels(params) - 1);
    114	hstream->bufsize = size;
    115	hstream->period_bytes = params_period_bytes(params);
    116	hstream->no_period_wakeup  =
    117			(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
    118			(params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
    119
    120	ret = hda_dsp_stream_hw_params(sdev, hext_stream, dmab, params);
    121	if (ret < 0) {
    122		dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
    123		return ret;
    124	}
    125
    126	/* enable SPIB when rewinds are disabled */
    127	if (hda_disable_rewinds)
    128		hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_ENABLE, 0);
    129	else
    130		hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0);
    131
    132	if (hda)
    133		platform_params->no_ipc_position = hda->no_ipc_position;
    134
    135	platform_params->stream_tag = hstream->stream_tag;
    136
    137	return 0;
    138}
    139
    140/* update SPIB register with appl position */
    141int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
    142{
    143	struct hdac_stream *hstream = substream->runtime->private_data;
    144	struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
    145	struct snd_pcm_runtime *runtime = substream->runtime;
    146	ssize_t appl_pos, buf_size;
    147	u32 spib;
    148
    149	appl_pos = frames_to_bytes(runtime, runtime->control->appl_ptr);
    150	buf_size = frames_to_bytes(runtime, runtime->buffer_size);
    151
    152	spib = appl_pos % buf_size;
    153
    154	/* Allowable value for SPIB is 1 byte to max buffer size */
    155	if (!spib)
    156		spib = buf_size;
    157
    158	sof_io_write(sdev, hext_stream->spib_addr, spib);
    159
    160	return 0;
    161}
    162
    163int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev,
    164			struct snd_pcm_substream *substream, int cmd)
    165{
    166	struct hdac_stream *hstream = substream->runtime->private_data;
    167	struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
    168
    169	return hda_dsp_stream_trigger(sdev, hext_stream, cmd);
    170}
    171
    172snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
    173				      struct snd_pcm_substream *substream)
    174{
    175	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    176	struct snd_soc_component *scomp = sdev->component;
    177	struct hdac_stream *hstream = substream->runtime->private_data;
    178	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
    179	struct snd_sof_pcm *spcm;
    180	snd_pcm_uframes_t pos;
    181
    182	spcm = snd_sof_find_spcm_dai(scomp, rtd);
    183	if (!spcm) {
    184		dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
    185				     rtd->dai_link->id);
    186		return 0;
    187	}
    188
    189	if (hda && !hda->no_ipc_position) {
    190		/* read position from IPC position */
    191		pos = spcm->stream[substream->stream].posn.host_posn;
    192		goto found;
    193	}
    194
    195	pos = hda_dsp_stream_get_position(hstream, substream->stream, true);
    196found:
    197	pos = bytes_to_frames(substream->runtime, pos);
    198
    199	dev_vdbg(sdev->dev, "PCM: stream %d dir %d position %lu\n",
    200		 hstream->index, substream->stream, pos);
    201	return pos;
    202}
    203
    204int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
    205		     struct snd_pcm_substream *substream)
    206{
    207	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    208	struct snd_pcm_runtime *runtime = substream->runtime;
    209	struct snd_soc_component *scomp = sdev->component;
    210	struct hdac_ext_stream *dsp_stream;
    211	struct snd_sof_pcm *spcm;
    212	int direction = substream->stream;
    213	u32 flags = 0;
    214
    215	spcm = snd_sof_find_spcm_dai(scomp, rtd);
    216	if (!spcm) {
    217		dev_err(sdev->dev, "error: can't find PCM with DAI ID %d\n", rtd->dai_link->id);
    218		return -EINVAL;
    219	}
    220
    221	/*
    222	 * if we want the .ack to work, we need to prevent the control from being mapped.
    223	 * The status can still be mapped.
    224	 */
    225	if (hda_disable_rewinds)
    226		runtime->hw.info |= SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR;
    227
    228	/*
    229	 * All playback streams are DMI L1 capable, capture streams need
    230	 * pause push/release to be disabled
    231	 */
    232	if (hda_always_enable_dmi_l1 && direction == SNDRV_PCM_STREAM_CAPTURE)
    233		runtime->hw.info &= ~SNDRV_PCM_INFO_PAUSE;
    234
    235	if (hda_always_enable_dmi_l1 ||
    236	    direction == SNDRV_PCM_STREAM_PLAYBACK ||
    237	    spcm->stream[substream->stream].d0i3_compatible)
    238		flags |= SOF_HDA_STREAM_DMI_L1_COMPATIBLE;
    239
    240	dsp_stream = hda_dsp_stream_get(sdev, direction, flags);
    241	if (!dsp_stream) {
    242		dev_err(sdev->dev, "error: no stream available\n");
    243		return -ENODEV;
    244	}
    245
    246	/* minimum as per HDA spec */
    247	snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
    248
    249	/* avoid circular buffer wrap in middle of period */
    250	snd_pcm_hw_constraint_integer(substream->runtime,
    251				      SNDRV_PCM_HW_PARAM_PERIODS);
    252
    253	/* binding pcm substream to hda stream */
    254	substream->runtime->private_data = &dsp_stream->hstream;
    255	return 0;
    256}
    257
    258int hda_dsp_pcm_close(struct snd_sof_dev *sdev,
    259		      struct snd_pcm_substream *substream)
    260{
    261	struct hdac_stream *hstream = substream->runtime->private_data;
    262	int direction = substream->stream;
    263	int ret;
    264
    265	ret = hda_dsp_stream_put(sdev, direction, hstream->stream_tag);
    266
    267	if (ret) {
    268		dev_dbg(sdev->dev, "stream %s not opened!\n", substream->name);
    269		return -ENODEV;
    270	}
    271
    272	/* unbinding pcm substream to hda stream */
    273	substream->runtime->private_data = NULL;
    274	return 0;
    275}