diff options
-rw-r--r-- | sound/soc/intel/skylake/skl-pcm.c | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 58c728662600..c966b40da180 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -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; |