| @@ -707,12 +707,13 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) · 706 unmodified lines |
| 707 | } | 707 | } |
| 708 | | 708 | |
| 709 | static void | 709 | 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) |
| 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 | |
| | 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 | } |