History

ASoC: SOF: Intel: hda: Fix compressed stream position tracking

Commit 288fad2f71fa ("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.

Peter Ujfalusi committed 4 years ago

Commit ca7ab1d1 parent 427eb3e3 files · +94 −77Browse files

Unified · Split

3 files
  1. sound/soc/sof/intel/hda-pcm.c +1 −73
  2. sound/soc/sof/intel/hda-stream.c +90 −4
  3. sound/soc/sof/intel/hda.h +3 −0
sound/soc/sof/intel/hda-pcm.c+1−73
@@ -192,79 +192,7 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, · 191 unmodified lines
192 goto found;192 goto found;
193 }193 }
194 194
195 switch (sof_hda_position_quirk) {195 pos = hda_dsp_stream_get_position(hstream, substream->stream, true);
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
268found:196found:
269 pos = bytes_to_frames(substream->runtime, pos);197 pos = bytes_to_frames(substream->runtime, pos);
270 198
sound/soc/sof/intel/hda-stream.c+90−4
@@ -707,12 +707,13 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) · 706 unmodified lines
707}707}
708 708
709static void709static void
710hda_dsp_set_bytes_transferred(struct hdac_stream *hstream, u64 buffer_size)710hda_dsp_compr_bytes_transferred(struct hdac_stream *hstream, int direction)
711{711{
712 u64 buffer_size = hstream->bufsize;
712 u64 prev_pos, pos, num_bytes;713 u64 prev_pos, pos, num_bytes;
713 714
714 div64_u64_rem(hstream->curr_pos, buffer_size, &prev_pos);715 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);
716 717
717 if (pos < prev_pos)718 if (pos < prev_pos)
718 num_bytes = (buffer_size - prev_pos) + pos;719 num_bytes = (buffer_size - prev_pos) + pos;
@@ -748,8 +749,7 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status) · 29 unmodified lines
748 if (s->substream && sof_hda->no_ipc_position) {749 if (s->substream && sof_hda->no_ipc_position) {
749 snd_sof_pcm_period_elapsed(s->substream);750 snd_sof_pcm_period_elapsed(s->substream);
750 } else if (s->cstream) {751 } else if (s->cstream) {
751 hda_dsp_set_bytes_transferred(s,752 hda_dsp_compr_bytes_transferred(s, s->cstream->direction);
752 s->cstream->runtime->buffer_size);
753 snd_compr_fragment_elapsed(s->cstream);753 snd_compr_fragment_elapsed(s->cstream);
754 }754 }
755 }755 }
@@ -1009,3 +1009,89 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev) · 253 unmodified lines
1009 devm_kfree(sdev->dev, hda_stream);1009 devm_kfree(sdev->dev, hda_stream);
1010 }1010 }
1011}1011}
1012
1013snd_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+3−0
@@ -565,6 +565,9 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, · 564 unmodified lines
565bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev);565bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
566bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);566bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
567 567
568snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
569 int direction, bool can_sleep);
570
568struct hdac_ext_stream *571struct hdac_ext_stream *
569 hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);572 hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);
570int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag);573int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag);