aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sof/intel/hda-pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof/intel/hda-pcm.c')
-rw-r--r--sound/soc/sof/intel/hda-pcm.c112
1 files changed, 52 insertions, 60 deletions
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index cc8ddef37f37..0a9c80216a8c 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -18,6 +18,7 @@
#include <linux/moduleparam.h>
#include <sound/hda_register.h>
#include <sound/pcm_params.h>
+#include <trace/events/sof_intel.h>
#include "../sof-audio.h"
#include "../ops.h"
#include "hda.h"
@@ -32,6 +33,10 @@ static bool hda_always_enable_dmi_l1;
module_param_named(always_enable_dmi_l1, hda_always_enable_dmi_l1, bool, 0444);
MODULE_PARM_DESC(always_enable_dmi_l1, "SOF HDA always enable DMI l1");
+static bool hda_disable_rewinds = IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_DISABLE_REWINDS);
+module_param_named(disable_rewinds, hda_disable_rewinds, bool, 0444);
+MODULE_PARM_DESC(disable_rewinds, "SOF HDA disable rewinds");
+
u32 hda_dsp_get_mult_div(struct snd_sof_dev *sdev, int rate)
{
switch (rate) {
@@ -89,13 +94,12 @@ u32 hda_dsp_get_bits(struct snd_sof_dev *sdev, int sample_bits)
int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct sof_ipc_stream_params *ipc_params)
+ struct snd_sof_platform_stream_params *platform_params)
{
struct hdac_stream *hstream = substream->runtime->private_data;
- struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream);
+ struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
struct snd_dma_buffer *dmab;
- struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
int ret;
u32 size, rate, bits;
@@ -114,28 +118,45 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
(params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
- ret = hda_dsp_stream_hw_params(sdev, stream, dmab, params);
+ ret = hda_dsp_stream_hw_params(sdev, hext_stream, dmab, params);
if (ret < 0) {
dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
return ret;
}
- /* disable SPIB, to enable buffer wrap for stream */
- hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0);
-
- /* update no_stream_position flag for ipc params */
- if (hda && hda->no_ipc_position) {
- /* For older ABIs set host_period_bytes to zero to inform
- * FW we don't want position updates. Newer versions use
- * no_stream_position for this purpose.
- */
- if (v->abi_version < SOF_ABI_VER(3, 10, 0))
- ipc_params->host_period_bytes = 0;
- else
- ipc_params->no_stream_position = 1;
- }
+ /* enable SPIB when rewinds are disabled */
+ if (hda_disable_rewinds)
+ hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_ENABLE, 0);
+ else
+ hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0);
+
+ if (hda)
+ platform_params->no_ipc_position = hda->no_ipc_position;
+
+ platform_params->stream_tag = hstream->stream_tag;
+
+ return 0;
+}
+
+/* update SPIB register with appl position */
+int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
+{
+ struct hdac_stream *hstream = substream->runtime->private_data;
+ struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ ssize_t appl_pos, buf_size;
+ u32 spib;
- ipc_params->stream_tag = hstream->stream_tag;
+ appl_pos = frames_to_bytes(runtime, runtime->control->appl_ptr);
+ buf_size = frames_to_bytes(runtime, runtime->buffer_size);
+
+ spib = appl_pos % buf_size;
+
+ /* Allowable value for SPIB is 1 byte to max buffer size */
+ if (!spib)
+ spib = buf_size;
+
+ sof_io_write(sdev, hext_stream->spib_addr, spib);
return 0;
}
@@ -144,9 +165,9 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream, int cmd)
{
struct hdac_stream *hstream = substream->runtime->private_data;
- struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream);
+ struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
- return hda_dsp_stream_trigger(sdev, stream, cmd);
+ return hda_dsp_stream_trigger(sdev, hext_stream, cmd);
}
snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
@@ -172,48 +193,11 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
goto found;
}
- /*
- * DPIB/posbuf position mode:
- * For Playback, Use DPIB register from HDA space which
- * reflects the actual data transferred.
- * For Capture, Use the position buffer for pointer, as DPIB
- * is not accurate enough, its update may be completed
- * earlier than the data written to DDR.
- */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
- AZX_REG_VS_SDXDPIB_XBASE +
- (AZX_REG_VS_SDXDPIB_XINTERVAL *
- hstream->index));
- } else {
- /*
- * For capture stream, we need more workaround to fix the
- * position incorrect issue:
- *
- * 1. Wait at least 20us before reading position buffer after
- * the interrupt generated(IOC), to make sure position update
- * happens on frame boundary i.e. 20.833uSec for 48KHz.
- * 2. Perform a dummy Read to DPIB register to flush DMA
- * position value.
- * 3. Read the DMA Position from posbuf. Now the readback
- * value should be >= period boundary.
- */
- usleep_range(20, 21);
- snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
- AZX_REG_VS_SDXDPIB_XBASE +
- (AZX_REG_VS_SDXDPIB_XINTERVAL *
- hstream->index));
- pos = snd_hdac_stream_get_pos_posbuf(hstream);
- }
-
- if (pos >= hstream->bufsize)
- pos = 0;
-
+ pos = hda_dsp_stream_get_position(hstream, substream->stream, true);
found:
pos = bytes_to_frames(substream->runtime, pos);
- dev_vdbg(sdev->dev, "PCM: stream %d dir %d position %lu\n",
- hstream->index, substream->stream, pos);
+ trace_sof_intel_hda_dsp_pcm(sdev, hstream, substream, pos);
return pos;
}
@@ -235,6 +219,13 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
}
/*
+ * if we want the .ack to work, we need to prevent the control from being mapped.
+ * The status can still be mapped.
+ */
+ if (hda_disable_rewinds)
+ runtime->hw.info |= SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR;
+
+ /*
* All playback streams are DMI L1 capable, capture streams need
* pause push/release to be disabled
*/
@@ -242,6 +233,7 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
runtime->hw.info &= ~SNDRV_PCM_INFO_PAUSE;
if (hda_always_enable_dmi_l1 ||
+ direction == SNDRV_PCM_STREAM_PLAYBACK ||
spcm->stream[substream->stream].d0i3_compatible)
flags |= SOF_HDA_STREAM_DMI_L1_COMPATIBLE;