ASoC: Intel: Skylake: Use DPIB to update position for Playback stream
[sfrench/cifs-2.6.git] / sound / soc / intel / skylake / skl-pcm.c
index 58c728662600455dcd9d9fbf442687728ea1bf7d..c966b40da1805772a07a67f08f9286911522d1fa 100644 (file)
@@ -1031,10 +1031,24 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer
                        (struct snd_pcm_substream *substream)
 {
        struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream);
+       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
        unsigned int pos;
 
-       /* use the position buffer as default */
-       pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream));
+       /*
+        * Use DPIB for Playback stream as the periodic DMA Position-in-
+        * Buffer Writes may be scheduled at the same time or later than
+        * the MSI and does not guarantee to reflect the Position of the
+        * last buffer that was transferred. Whereas DPIB register in
+        * HAD space reflects the actual data that is transferred.
+        * Use the position buffer for capture, as DPIB write gets
+        * completed earlier than the actual data written to the DDR.
+        */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
+                               (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                               hdac_stream(hstream)->index));
+       else
+               pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream));
 
        if (pos >= hdac_stream(hstream)->bufsize)
                pos = 0;