ASoC: SOF: Intel: hda: Implement get_stream_position (Linear Link Position)
authorPeter Ujfalusi <peter.ujfalusi@linux.intel.com>
Thu, 21 Mar 2024 13:08:01 +0000 (15:08 +0200)
committerMark Brown <broonie@kernel.org>
Mon, 25 Mar 2024 16:35:54 +0000 (16:35 +0000)
When the Linear Link Position is not available in firmware SRAM window we
use the host accessible position registers to read it.
The address of the PPLCLLPL/U registers depend on the number of streams
(playback+capture).
At probe time the pplc_addr is calculated for each stream and we can use
it to read the LLP without the need of address re-calculation.

Set the get_stream_position callback in sof_hda_common_ops for all
platforms:
The callback is used for IPC4 delay calculations only but the register is
a generic HDA register, not tied to any specific IPC version.

Cc: stable@vger.kernel.org # 6.8
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Rander Wang <rander.wang@intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://msgid.link/r/20240321130814.4412-5-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/intel/hda-common-ops.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/intel/hda.h

index 2b385cddc385c5bd59e11acfe8e6bda45704fdd1..80a69599a8c305c8247b996146a00c046730bdac 100644 (file)
@@ -57,6 +57,8 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
        .pcm_pointer    = hda_dsp_pcm_pointer,
        .pcm_ack        = hda_dsp_pcm_ack,
 
+       .get_stream_position = hda_dsp_get_stream_llp,
+
        /* firmware loading */
        .load_firmware = snd_sof_load_firmware_raw,
 
index b387b1a69d7ea3ceaed9fe814b174d9040e3eae1..48ea187f72302d7a39928662ee2fc5cd9eafda29 100644 (file)
@@ -1063,3 +1063,35 @@ snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
 
        return pos;
 }
+
+/**
+ * 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);
+
+       return ((u64)llp_u << 32) | llp_l;
+}
index b36eb7c7891335a3038d5e1402d6f73ede754b81..9d26cad785fe059a1ea59ebedd6d158ae08da4f9 100644 (file)
@@ -662,6 +662,9 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
 
 snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
                                              int direction, bool can_sleep);
+u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
+                          struct snd_soc_component *component,
+                          struct snd_pcm_substream *substream);
 
 struct hdac_ext_stream *
        hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);