Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: SOF: Intel: hda: Disable DMI L1 entry during capture

There is a known issue on some Intel platforms which causes
pause/release to run into xrun's during capture usecases.
The suggested workaround to address the issue is to
disable the entry of lower power L1 state in the physical
DMI link when there is a capture stream open.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20190927200538.660-14-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Ranjani Sridharan and committed by
Mark Brown
43b2ab90 ff2be865

+56 -16
+10
sound/soc/sof/intel/Kconfig
··· 273 273 Say Y if you want to enable HDAudio codecs with SOF. 274 274 If unsure select "N". 275 275 276 + config SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1 277 + bool "SOF enable DMI Link L1" 278 + help 279 + This option enables DMI L1 for both playback and capture 280 + and disables known workarounds for specific HDaudio platforms. 281 + Only use to look into power optimizations on platforms not 282 + affected by DMI L1 issues. This option is not recommended. 283 + Say Y if you want to enable DMI Link L1 284 + If unsure, select "N". 285 + 276 286 endif ## SND_SOC_SOF_HDA_COMMON 277 287 278 288 config SND_SOC_SOF_HDA_LINK_BASELINE
+4 -8
sound/soc/sof/intel/hda-ctrl.c
··· 139 139 */ 140 140 int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) 141 141 { 142 - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 143 - struct hdac_bus *bus = sof_to_bus(sdev); 144 - #endif 145 142 u32 val; 146 143 147 144 /* enable/disable audio dsp clock gating */ 148 145 val = enable ? PCI_CGCTL_ADSPDCGE : 0; 149 146 snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val); 150 147 151 - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 152 - /* enable/disable L1 support */ 153 - val = enable ? SOF_HDA_VS_EM2_L1SEN : 0; 154 - snd_hdac_chip_updatel(bus, VS_EM2, SOF_HDA_VS_EM2_L1SEN, val); 155 - #endif 148 + /* enable/disable DMI Link L1 support */ 149 + val = enable ? HDA_VS_INTEL_EM2_L1SEN : 0; 150 + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2, 151 + HDA_VS_INTEL_EM2_L1SEN, val); 156 152 157 153 /* enable/disable audio dsp power gating */ 158 154 val = enable ? 0 : PCI_PGCTL_ADSPPGD;
+38 -7
sound/soc/sof/intel/hda-stream.c
··· 185 185 direction == SNDRV_PCM_STREAM_PLAYBACK ? 186 186 "playback" : "capture"); 187 187 188 + /* 189 + * Disable DMI Link L1 entry when capture stream is opened. 190 + * Workaround to address a known issue with host DMA that results 191 + * in xruns during pause/release in capture scenarios. 192 + */ 193 + if (!IS_ENABLED(SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1)) 194 + if (stream && direction == SNDRV_PCM_STREAM_CAPTURE) 195 + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, 196 + HDA_VS_INTEL_EM2, 197 + HDA_VS_INTEL_EM2_L1SEN, 0); 198 + 188 199 return stream; 189 200 } 190 201 ··· 204 193 { 205 194 struct hdac_bus *bus = sof_to_bus(sdev); 206 195 struct hdac_stream *s; 196 + bool active_capture_stream = false; 197 + bool found = false; 207 198 208 199 spin_lock_irq(&bus->reg_lock); 209 200 210 - /* find used stream */ 201 + /* 202 + * close stream matching the stream tag 203 + * and check if there are any open capture streams. 204 + */ 211 205 list_for_each_entry(s, &bus->stream_list, list) { 212 - if (s->direction == direction && 213 - s->opened && s->stream_tag == stream_tag) { 206 + if (!s->opened) 207 + continue; 208 + 209 + if (s->direction == direction && s->stream_tag == stream_tag) { 214 210 s->opened = false; 215 - spin_unlock_irq(&bus->reg_lock); 216 - return 0; 211 + found = true; 212 + } else if (s->direction == SNDRV_PCM_STREAM_CAPTURE) { 213 + active_capture_stream = true; 217 214 } 218 215 } 219 216 220 217 spin_unlock_irq(&bus->reg_lock); 221 218 222 - dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag); 223 - return -ENODEV; 219 + /* Enable DMI L1 entry if there are no capture streams open */ 220 + if (!IS_ENABLED(SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1)) 221 + if (!active_capture_stream) 222 + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, 223 + HDA_VS_INTEL_EM2, 224 + HDA_VS_INTEL_EM2_L1SEN, 225 + HDA_VS_INTEL_EM2_L1SEN); 226 + 227 + if (!found) { 228 + dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag); 229 + return -ENODEV; 230 + } 231 + 232 + return 0; 224 233 } 225 234 226 235 int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
+4 -1
sound/soc/sof/intel/hda.h
··· 39 39 #define SOF_HDA_WAKESTS 0x0E 40 40 #define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1) 41 41 #define SOF_HDA_RIRBSTS 0x5d 42 - #define SOF_HDA_VS_EM2_L1SEN BIT(13) 43 42 44 43 /* SOF_HDA_GCTL register bist */ 45 44 #define SOF_HDA_GCTL_RESET BIT(0) ··· 226 227 #define HDA_DSP_REG_HIPCI (HDA_DSP_IPC_BASE + 0x08) 227 228 #define HDA_DSP_REG_HIPCIE (HDA_DSP_IPC_BASE + 0x0C) 228 229 #define HDA_DSP_REG_HIPCCTL (HDA_DSP_IPC_BASE + 0x10) 230 + 231 + /* Intel Vendor Specific Registers */ 232 + #define HDA_VS_INTEL_EM2 0x1030 233 + #define HDA_VS_INTEL_EM2_L1SEN BIT(13) 229 234 230 235 /* HIPCI */ 231 236 #define HDA_DSP_REG_HIPCI_BUSY BIT(31)