Skip to content

Commit ca7ab1d

Browse files
ujfalusibroonie
authored andcommitted
ASoC: SOF: Intel: hda: Fix compressed stream position tracking
Commit 288fad2 ("ASoC: SOF: Intel: hda: add quirks for HDAudio DMA position information") modified the PCM path only, but left the compressed data patch using an obsolete option. Move the functionality in a helper that can be called for both PCM and compressed data. Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Fixes: 288fad2 ("ASoC: SOF: Intel: hda: add quirks for HDAudio DMA position information") Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Link: https://lore.kernel.org/r/20220616201953.130876-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 427eb3e commit ca7ab1d

3 files changed

Lines changed: 94 additions & 77 deletions

File tree

sound/soc/sof/intel/hda-pcm.c

Lines changed: 1 addition & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -192,79 +192,7 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
192192
goto found;
193193
}
194194

195-
switch (sof_hda_position_quirk) {
196-
case SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY:
197-
/*
198-
* This legacy code, inherited from the Skylake driver,
199-
* mixes DPIB registers and DPIB DDR updates and
200-
* does not seem to follow any known hardware recommendations.
201-
* It's not clear e.g. why there is a different flow
202-
* for capture and playback, the only information that matters is
203-
* what traffic class is used, and on all SOF-enabled platforms
204-
* only VC0 is supported so the work-around was likely not necessary
205-
* and quite possibly wrong.
206-
*/
207-
208-
/* DPIB/posbuf position mode:
209-
* For Playback, Use DPIB register from HDA space which
210-
* reflects the actual data transferred.
211-
* For Capture, Use the position buffer for pointer, as DPIB
212-
* is not accurate enough, its update may be completed
213-
* earlier than the data written to DDR.
214-
*/
215-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
216-
pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
217-
AZX_REG_VS_SDXDPIB_XBASE +
218-
(AZX_REG_VS_SDXDPIB_XINTERVAL *
219-
hstream->index));
220-
} else {
221-
/*
222-
* For capture stream, we need more workaround to fix the
223-
* position incorrect issue:
224-
*
225-
* 1. Wait at least 20us before reading position buffer after
226-
* the interrupt generated(IOC), to make sure position update
227-
* happens on frame boundary i.e. 20.833uSec for 48KHz.
228-
* 2. Perform a dummy Read to DPIB register to flush DMA
229-
* position value.
230-
* 3. Read the DMA Position from posbuf. Now the readback
231-
* value should be >= period boundary.
232-
*/
233-
usleep_range(20, 21);
234-
snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
235-
AZX_REG_VS_SDXDPIB_XBASE +
236-
(AZX_REG_VS_SDXDPIB_XINTERVAL *
237-
hstream->index));
238-
pos = snd_hdac_stream_get_pos_posbuf(hstream);
239-
}
240-
break;
241-
case SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS:
242-
/*
243-
* In case VC1 traffic is disabled this is the recommended option
244-
*/
245-
pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
246-
AZX_REG_VS_SDXDPIB_XBASE +
247-
(AZX_REG_VS_SDXDPIB_XINTERVAL *
248-
hstream->index));
249-
break;
250-
case SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE:
251-
/*
252-
* This is the recommended option when VC1 is enabled.
253-
* While this isn't needed for SOF platforms it's added for
254-
* consistency and debug.
255-
*/
256-
pos = snd_hdac_stream_get_pos_posbuf(hstream);
257-
break;
258-
default:
259-
dev_err_once(sdev->dev, "hda_position_quirk value %d not supported\n",
260-
sof_hda_position_quirk);
261-
pos = 0;
262-
break;
263-
}
264-
265-
if (pos >= hstream->bufsize)
266-
pos = 0;
267-
195+
pos = hda_dsp_stream_get_position(hstream, substream->stream, true);
268196
found:
269197
pos = bytes_to_frames(substream->runtime, pos);
270198

sound/soc/sof/intel/hda-stream.c

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -707,12 +707,13 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
707707
}
708708

709709
static void
710-
hda_dsp_set_bytes_transferred(struct hdac_stream *hstream, u64 buffer_size)
710+
hda_dsp_compr_bytes_transferred(struct hdac_stream *hstream, int direction)
711711
{
712+
u64 buffer_size = hstream->bufsize;
712713
u64 prev_pos, pos, num_bytes;
713714

714715
div64_u64_rem(hstream->curr_pos, buffer_size, &prev_pos);
715-
pos = snd_hdac_stream_get_pos_posbuf(hstream);
716+
pos = hda_dsp_stream_get_position(hstream, direction, false);
716717

717718
if (pos < prev_pos)
718719
num_bytes = (buffer_size - prev_pos) + pos;
@@ -748,8 +749,7 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
748749
if (s->substream && sof_hda->no_ipc_position) {
749750
snd_sof_pcm_period_elapsed(s->substream);
750751
} else if (s->cstream) {
751-
hda_dsp_set_bytes_transferred(s,
752-
s->cstream->runtime->buffer_size);
752+
hda_dsp_compr_bytes_transferred(s, s->cstream->direction);
753753
snd_compr_fragment_elapsed(s->cstream);
754754
}
755755
}
@@ -1009,3 +1009,89 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev)
10091009
devm_kfree(sdev->dev, hda_stream);
10101010
}
10111011
}
1012+
1013+
snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
1014+
int direction, bool can_sleep)
1015+
{
1016+
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
1017+
struct sof_intel_hda_stream *hda_stream = hstream_to_sof_hda_stream(hext_stream);
1018+
struct snd_sof_dev *sdev = hda_stream->sdev;
1019+
snd_pcm_uframes_t pos;
1020+
1021+
switch (sof_hda_position_quirk) {
1022+
case SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY:
1023+
/*
1024+
* This legacy code, inherited from the Skylake driver,
1025+
* mixes DPIB registers and DPIB DDR updates and
1026+
* does not seem to follow any known hardware recommendations.
1027+
* It's not clear e.g. why there is a different flow
1028+
* for capture and playback, the only information that matters is
1029+
* what traffic class is used, and on all SOF-enabled platforms
1030+
* only VC0 is supported so the work-around was likely not necessary
1031+
* and quite possibly wrong.
1032+
*/
1033+
1034+
/* DPIB/posbuf position mode:
1035+
* For Playback, Use DPIB register from HDA space which
1036+
* reflects the actual data transferred.
1037+
* For Capture, Use the position buffer for pointer, as DPIB
1038+
* is not accurate enough, its update may be completed
1039+
* earlier than the data written to DDR.
1040+
*/
1041+
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
1042+
pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
1043+
AZX_REG_VS_SDXDPIB_XBASE +
1044+
(AZX_REG_VS_SDXDPIB_XINTERVAL *
1045+
hstream->index));
1046+
} else {
1047+
/*
1048+
* For capture stream, we need more workaround to fix the
1049+
* position incorrect issue:
1050+
*
1051+
* 1. Wait at least 20us before reading position buffer after
1052+
* the interrupt generated(IOC), to make sure position update
1053+
* happens on frame boundary i.e. 20.833uSec for 48KHz.
1054+
* 2. Perform a dummy Read to DPIB register to flush DMA
1055+
* position value.
1056+
* 3. Read the DMA Position from posbuf. Now the readback
1057+
* value should be >= period boundary.
1058+
*/
1059+
if (can_sleep)
1060+
usleep_range(20, 21);
1061+
1062+
snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
1063+
AZX_REG_VS_SDXDPIB_XBASE +
1064+
(AZX_REG_VS_SDXDPIB_XINTERVAL *
1065+
hstream->index));
1066+
pos = snd_hdac_stream_get_pos_posbuf(hstream);
1067+
}
1068+
break;
1069+
case SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS:
1070+
/*
1071+
* In case VC1 traffic is disabled this is the recommended option
1072+
*/
1073+
pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
1074+
AZX_REG_VS_SDXDPIB_XBASE +
1075+
(AZX_REG_VS_SDXDPIB_XINTERVAL *
1076+
hstream->index));
1077+
break;
1078+
case SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE:
1079+
/*
1080+
* This is the recommended option when VC1 is enabled.
1081+
* While this isn't needed for SOF platforms it's added for
1082+
* consistency and debug.
1083+
*/
1084+
pos = snd_hdac_stream_get_pos_posbuf(hstream);
1085+
break;
1086+
default:
1087+
dev_err_once(sdev->dev, "hda_position_quirk value %d not supported\n",
1088+
sof_hda_position_quirk);
1089+
pos = 0;
1090+
break;
1091+
}
1092+
1093+
if (pos >= hstream->bufsize)
1094+
pos = 0;
1095+
1096+
return pos;
1097+
}

sound/soc/sof/intel/hda.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,9 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
565565
bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
566566
bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
567567

568+
snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
569+
int direction, bool can_sleep);
570+
568571
struct hdac_ext_stream *
569572
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);
570573
int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag);

0 commit comments

Comments
 (0)