diff options
Diffstat (limited to 'sound/soc/sof/intel/hda-stream.c')
-rw-r--r-- | sound/soc/sof/intel/hda-stream.c | 109 |
1 files changed, 104 insertions, 5 deletions
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index b387b1a69d7e..8213debde497 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2018 Intel Corporation. All rights reserved. +// Copyright(c) 2018 Intel Corporation // // Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com> // Ranjani Sridharan <ranjani.sridharan@linux.intel.com> @@ -24,6 +24,11 @@ #include "../ipc4-priv.h" #include "hda.h" +int sof_hda_position_quirk = SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS; +module_param_named(position_quirk, sof_hda_position_quirk, int, 0444); +MODULE_PARM_DESC(position_quirk, "SOF HDaudio position quirk"); +EXPORT_SYMBOL_NS(sof_hda_position_quirk, SND_SOC_SOF_INTEL_HDA_COMMON); + #define HDA_LTRP_GB_VALUE_US 95 static inline const char *hda_hstream_direction_str(struct hdac_stream *hstream) @@ -709,6 +714,7 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, return 0; } +EXPORT_SYMBOL_NS(hda_dsp_stream_hw_free, SND_SOC_SOF_INTEL_HDA_COMMON); bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) { @@ -731,6 +737,7 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) return ret; } +EXPORT_SYMBOL_NS(hda_dsp_check_stream_irq, SND_SOC_SOF_INTEL_HDA_COMMON); static void hda_dsp_compr_bytes_transferred(struct hdac_stream *hstream, int direction) @@ -765,12 +772,27 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status) writeb(sd_status, s->sd_addr + SOF_HDA_ADSP_REG_SD_STS); active = true; - if ((!s->substream && !s->cstream) || - !s->running || - (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) + if (!s->running) + continue; + if ((sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) continue; + if (!s->substream && !s->cstream) { + /* + * when no substream is found, the DMA may used for code loading + * or data transfers which can rely on wait_for_completion() + */ + struct sof_intel_hda_stream *hda_stream; + struct hdac_ext_stream *hext_stream; + + hext_stream = stream_to_hdac_ext_stream(s); + hda_stream = container_of(hext_stream, struct sof_intel_hda_stream, + hext_stream); + + complete(&hda_stream->ioc); + continue; + } - /* Inform ALSA only in case not do that with IPC */ + /* Inform ALSA only if the IPC position is not used */ if (s->substream && sof_hda->no_ipc_position) { snd_sof_pcm_period_elapsed(s->substream); } else if (s->cstream) { @@ -812,6 +834,7 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) return IRQ_HANDLED; } +EXPORT_SYMBOL_NS(hda_dsp_stream_threaded_handler, SND_SOC_SOF_INTEL_HDA_COMMON); int hda_dsp_stream_init(struct snd_sof_dev *sdev) { @@ -880,6 +903,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) return -ENOMEM; hda_stream->sdev = sdev; + init_completion(&hda_stream->ioc); hext_stream = &hda_stream->hext_stream; @@ -948,6 +972,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) return 0; } +EXPORT_SYMBOL_NS(hda_dsp_stream_init, SND_SOC_SOF_INTEL_HDA_COMMON); void hda_dsp_stream_free(struct snd_sof_dev *sdev) { @@ -977,6 +1002,7 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev) devm_kfree(sdev->dev, hda_stream); } } +EXPORT_SYMBOL_NS(hda_dsp_stream_free, SND_SOC_SOF_INTEL_HDA_COMMON); snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream, int direction, bool can_sleep) @@ -1063,3 +1089,76 @@ snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream, return pos; } +EXPORT_SYMBOL_NS(hda_dsp_stream_get_position, SND_SOC_SOF_INTEL_HDA_COMMON); + +#define merge_u64(u32_u, u32_l) (((u64)(u32_u) << 32) | (u32_l)) + +/** + * hda_dsp_get_stream_llp - Retrieve the LLP (Linear Link Position) of the stream + * @sdev: SOF device + * @component: ASoC component + * @substream: PCM substream + * + * Returns the raw Linear Link Position value + */ +u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); + u32 llp_l, llp_u; + + /* + * The pplc_addr have been calculated during probe in + * hda_dsp_stream_init(): + * pplc_addr = sdev->bar[HDA_DSP_PP_BAR] + + * SOF_HDA_PPLC_BASE + + * SOF_HDA_PPLC_MULTI * total_stream + + * SOF_HDA_PPLC_INTERVAL * stream_index + * + * Use this pre-calculated address to avoid repeated re-calculation. + */ + llp_l = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL); + llp_u = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU); + + /* Compensate the LLP counter with the saved offset */ + if (hext_stream->pplcllpl || hext_stream->pplcllpu) + return merge_u64(llp_u, llp_l) - + merge_u64(hext_stream->pplcllpu, hext_stream->pplcllpl); + + return merge_u64(llp_u, llp_l); +} +EXPORT_SYMBOL_NS(hda_dsp_get_stream_llp, SND_SOC_SOF_INTEL_HDA_COMMON); + +/** + * hda_dsp_get_stream_ldp - Retrieve the LDP (Linear DMA Position) of the stream + * @sdev: SOF device + * @component: ASoC component + * @substream: PCM substream + * + * Returns the raw Linear Link Position value + */ +u64 hda_dsp_get_stream_ldp(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); + u32 ldp_l, ldp_u; + + /* + * The pphc_addr have been calculated during probe in + * hda_dsp_stream_init(): + * pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + + * SOF_HDA_PPHC_BASE + + * SOF_HDA_PPHC_INTERVAL * stream_index + * + * Use this pre-calculated address to avoid repeated re-calculation. + */ + ldp_l = readl(hext_stream->pphc_addr + AZX_REG_PPHCLDPL); + ldp_u = readl(hext_stream->pphc_addr + AZX_REG_PPHCLDPU); + + return ((u64)ldp_u << 32) | ldp_l; +} +EXPORT_SYMBOL_NS(hda_dsp_get_stream_ldp, SND_SOC_SOF_INTEL_HDA_COMMON); |