summaryrefslogtreecommitdiff
path: root/sound/soc/sof/intel/hda-stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof/intel/hda-stream.c')
-rw-r--r--sound/soc/sof/intel/hda-stream.c109
1 files changed, 104 insertions, 5 deletions
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index b387b1a69d7e..8213debde497 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -3,7 +3,7 @@
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
-// Copyright(c) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@@ -24,6 +24,11 @@
#include "../ipc4-priv.h"
#include "hda.h"
+int sof_hda_position_quirk = SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS;
+module_param_named(position_quirk, sof_hda_position_quirk, int, 0444);
+MODULE_PARM_DESC(position_quirk, "SOF HDaudio position quirk");
+EXPORT_SYMBOL_NS(sof_hda_position_quirk, SND_SOC_SOF_INTEL_HDA_COMMON);
+
#define HDA_LTRP_GB_VALUE_US 95
static inline const char *hda_hstream_direction_str(struct hdac_stream *hstream)
@@ -709,6 +714,7 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_stream_hw_free, SND_SOC_SOF_INTEL_HDA_COMMON);
bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
{
@@ -731,6 +737,7 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_check_stream_irq, SND_SOC_SOF_INTEL_HDA_COMMON);
static void
hda_dsp_compr_bytes_transferred(struct hdac_stream *hstream, int direction)
@@ -765,12 +772,27 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
writeb(sd_status, s->sd_addr + SOF_HDA_ADSP_REG_SD_STS);
active = true;
- if ((!s->substream && !s->cstream) ||
- !s->running ||
- (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0)
+ if (!s->running)
+ continue;
+ if ((sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0)
continue;
+ if (!s->substream && !s->cstream) {
+ /*
+ * when no substream is found, the DMA may used for code loading
+ * or data transfers which can rely on wait_for_completion()
+ */
+ struct sof_intel_hda_stream *hda_stream;
+ struct hdac_ext_stream *hext_stream;
+
+ hext_stream = stream_to_hdac_ext_stream(s);
+ hda_stream = container_of(hext_stream, struct sof_intel_hda_stream,
+ hext_stream);
+
+ complete(&hda_stream->ioc);
+ continue;
+ }
- /* Inform ALSA only in case not do that with IPC */
+ /* Inform ALSA only if the IPC position is not used */
if (s->substream && sof_hda->no_ipc_position) {
snd_sof_pcm_period_elapsed(s->substream);
} else if (s->cstream) {
@@ -812,6 +834,7 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_NS(hda_dsp_stream_threaded_handler, SND_SOC_SOF_INTEL_HDA_COMMON);
int hda_dsp_stream_init(struct snd_sof_dev *sdev)
{
@@ -880,6 +903,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
return -ENOMEM;
hda_stream->sdev = sdev;
+ init_completion(&hda_stream->ioc);
hext_stream = &hda_stream->hext_stream;
@@ -948,6 +972,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_stream_init, SND_SOC_SOF_INTEL_HDA_COMMON);
void hda_dsp_stream_free(struct snd_sof_dev *sdev)
{
@@ -977,6 +1002,7 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev)
devm_kfree(sdev->dev, hda_stream);
}
}
+EXPORT_SYMBOL_NS(hda_dsp_stream_free, SND_SOC_SOF_INTEL_HDA_COMMON);
snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
int direction, bool can_sleep)
@@ -1063,3 +1089,76 @@ snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
return pos;
}
+EXPORT_SYMBOL_NS(hda_dsp_stream_get_position, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+#define merge_u64(u32_u, u32_l) (((u64)(u32_u) << 32) | (u32_l))
+
+/**
+ * hda_dsp_get_stream_llp - Retrieve the LLP (Linear Link Position) of the stream
+ * @sdev: SOF device
+ * @component: ASoC component
+ * @substream: PCM substream
+ *
+ * Returns the raw Linear Link Position value
+ */
+u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
+ struct snd_soc_component *component,
+ 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);
+ u32 llp_l, llp_u;
+
+ /*
+ * The pplc_addr have been calculated during probe in
+ * hda_dsp_stream_init():
+ * pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
+ * SOF_HDA_PPLC_BASE +
+ * SOF_HDA_PPLC_MULTI * total_stream +
+ * SOF_HDA_PPLC_INTERVAL * stream_index
+ *
+ * Use this pre-calculated address to avoid repeated re-calculation.
+ */
+ llp_l = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL);
+ llp_u = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU);
+
+ /* Compensate the LLP counter with the saved offset */
+ if (hext_stream->pplcllpl || hext_stream->pplcllpu)
+ return merge_u64(llp_u, llp_l) -
+ merge_u64(hext_stream->pplcllpu, hext_stream->pplcllpl);
+
+ return merge_u64(llp_u, llp_l);
+}
+EXPORT_SYMBOL_NS(hda_dsp_get_stream_llp, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+/**
+ * hda_dsp_get_stream_ldp - Retrieve the LDP (Linear DMA Position) of the stream
+ * @sdev: SOF device
+ * @component: ASoC component
+ * @substream: PCM substream
+ *
+ * Returns the raw Linear Link Position value
+ */
+u64 hda_dsp_get_stream_ldp(struct snd_sof_dev *sdev,
+ struct snd_soc_component *component,
+ 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);
+ u32 ldp_l, ldp_u;
+
+ /*
+ * The pphc_addr have been calculated during probe in
+ * hda_dsp_stream_init():
+ * pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
+ * SOF_HDA_PPHC_BASE +
+ * SOF_HDA_PPHC_INTERVAL * stream_index
+ *
+ * Use this pre-calculated address to avoid repeated re-calculation.
+ */
+ ldp_l = readl(hext_stream->pphc_addr + AZX_REG_PPHCLDPL);
+ ldp_u = readl(hext_stream->pphc_addr + AZX_REG_PPHCLDPU);
+
+ return ((u64)ldp_u << 32) | ldp_l;
+}
+EXPORT_SYMBOL_NS(hda_dsp_get_stream_ldp, SND_SOC_SOF_INTEL_HDA_COMMON);