]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: SOF: Intel: add hda_dma_prepare/cleanup helpers
authorBard Liao <yung-chuan.liao@linux.intel.com>
Tue, 3 Feb 2026 11:40:26 +0000 (19:40 +0800)
committerMark Brown <broonie@kernel.org>
Tue, 3 Feb 2026 13:47:20 +0000 (13:47 +0000)
SoundWire BPT stream needs to use link and host DMAs. Thus we need
helpers to prepare and cleanup the link and host DMAs. Currently the
SoundWire BPT stream uses hda_cl_prepare/cleanup helpers. It works fine
because we assume the SwoundWire BPT will not run with audio streams
simultaneously. The new helpers are copied from hda_cl_prepare/cleanup
and add a flag to reserve the paired host and link DMAs. The new helpers
will be used by both code loader and SoundWire BPT.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Link: https://patch.msgid.link/20260203114027.3742558-3-yung-chuan.liao@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/intel/hda-loader.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/intel/hda.h

index 2cc11d8b0f70800cae261973d5dbd64075c8f0f4..2b3abcf75d558b56f66618e9f0de1e2856c8efb4 100644 (file)
@@ -53,65 +53,8 @@ hda_cl_prepare(struct device *dev, unsigned int format, unsigned int size,
               struct snd_dma_buffer *dmab, bool persistent_buffer, int direction,
               bool is_iccmax)
 {
-       struct snd_sof_dev *sdev = dev_get_drvdata(dev);
-       struct hdac_ext_stream *hext_stream;
-       struct hdac_stream *hstream;
-       int ret;
-
-       hext_stream = hda_dsp_stream_get(sdev, direction, 0);
-
-       if (!hext_stream) {
-               dev_err(sdev->dev, "error: no stream available\n");
-               return ERR_PTR(-ENODEV);
-       }
-       hstream = &hext_stream->hstream;
-       hstream->substream = NULL;
-
-       /*
-        * Allocate DMA buffer if it is temporary or if the buffer is intended
-        * to be persistent but not yet allocated.
-        * We cannot rely solely on !dmab->area as caller might use a struct on
-        * stack (when it is temporary) without clearing it to 0.
-        */
-       if (!persistent_buffer || !dmab->area) {
-               ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab);
-               if (ret < 0) {
-                       dev_err(sdev->dev, "%s: memory alloc failed: %d\n",
-                               __func__, ret);
-                       goto out_put;
-               }
-       }
-
-       hstream->period_bytes = 0;/* initialize period_bytes */
-       hstream->format_val = format;
-       hstream->bufsize = size;
-
-       if (is_iccmax) {
-               ret = hda_dsp_iccmax_stream_hw_params(sdev, hext_stream, dmab, NULL);
-               if (ret < 0) {
-                       dev_err(sdev->dev, "error: iccmax stream prepare failed: %d\n", ret);
-                       goto out_free;
-               }
-       } else {
-               ret = hda_dsp_stream_hw_params(sdev, hext_stream, dmab, NULL);
-               if (ret < 0) {
-                       dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
-                       goto out_free;
-               }
-               hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_ENABLE, size);
-       }
-
-       return hext_stream;
-
-out_free:
-       snd_dma_free_pages(dmab);
-       dmab->area = NULL;
-       dmab->bytes = 0;
-       hstream->bufsize = 0;
-       hstream->format_val = 0;
-out_put:
-       hda_dsp_stream_put(sdev, direction, hstream->stream_tag);
-       return ERR_PTR(ret);
+       return hda_data_stream_prepare(dev, format, size, dmab, persistent_buffer,
+                                      direction, is_iccmax, false);
 }
 EXPORT_SYMBOL_NS(hda_cl_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON");
 
@@ -275,38 +218,7 @@ EXPORT_SYMBOL_NS(hda_cl_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
 int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
                          bool persistent_buffer, struct hdac_ext_stream *hext_stream)
 {
-       struct snd_sof_dev *sdev =  dev_get_drvdata(dev);
-       struct hdac_stream *hstream = &hext_stream->hstream;
-       int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
-       int ret = 0;
-
-       if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK)
-               ret = hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0);
-       else
-               snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
-                                       SOF_HDA_SD_CTL_DMA_START, 0);
-
-       hda_dsp_stream_put(sdev, hstream->direction, hstream->stream_tag);
-       hstream->running = 0;
-       hstream->substream = NULL;
-
-       /* reset BDL address */
-       snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, 0);
-       snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0);
-
-       snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0);
-
-       if (!persistent_buffer) {
-               snd_dma_free_pages(dmab);
-               dmab->area = NULL;
-               dmab->bytes = 0;
-               hstream->bufsize = 0;
-               hstream->format_val = 0;
-       }
-
-       return ret;
+       return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream, false);
 }
 EXPORT_SYMBOL_NS(hda_cl_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON");
 
index 36b647d987fc75ff3e0e6213ec9f2cc7af96f5cc..1c04b5d9c0d8b6c6a306de57691814cb3676336b 100644 (file)
@@ -1243,3 +1243,119 @@ u64 hda_dsp_get_stream_ldp(struct snd_sof_dev *sdev,
        return ((u64)ldp_u << 32) | ldp_l;
 }
 EXPORT_SYMBOL_NS(hda_dsp_get_stream_ldp, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+struct hdac_ext_stream *
+hda_data_stream_prepare(struct device *dev, unsigned int format, unsigned int size,
+                       struct snd_dma_buffer *dmab, bool persistent_buffer, int direction,
+                       bool is_iccmax, bool pair)
+{
+       struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+       struct hdac_ext_stream *hext_stream;
+       struct hdac_stream *hstream;
+       int ret;
+
+       if (pair)
+               hext_stream = hda_dsp_stream_pair_get(sdev, direction, 0);
+       else
+               hext_stream = hda_dsp_stream_get(sdev, direction, 0);
+
+       if (!hext_stream) {
+               dev_err(sdev->dev, "%s: no stream available\n", __func__);
+               return ERR_PTR(-ENODEV);
+       }
+       hstream = &hext_stream->hstream;
+       hstream->substream = NULL;
+
+       /*
+        * Allocate DMA buffer if it is temporary or if the buffer is intended
+        * to be persistent but not yet allocated.
+        * We cannot rely solely on !dmab->area as caller might use a struct on
+        * stack (when it is temporary) without clearing it to 0.
+        */
+       if (!persistent_buffer || !dmab->area) {
+               ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab);
+               if (ret < 0) {
+                       dev_err(sdev->dev, "%s: memory alloc failed: %d\n",
+                               __func__, ret);
+                       goto out_put;
+               }
+       }
+
+       hstream->period_bytes = 0; /* initialize period_bytes */
+       hstream->format_val = format;
+       hstream->bufsize = size;
+
+       if (is_iccmax) {
+               ret = hda_dsp_iccmax_stream_hw_params(sdev, hext_stream, dmab, NULL);
+               if (ret < 0) {
+                       dev_err(sdev->dev, "%s: iccmax stream prepare failed: %d\n",
+                               __func__, ret);
+                       goto out_free;
+               }
+       } else {
+               ret = hda_dsp_stream_hw_params(sdev, hext_stream, dmab, NULL);
+               if (ret < 0) {
+                       dev_err(sdev->dev, "%s: hdac prepare failed: %d\n", __func__, ret);
+                       goto out_free;
+               }
+               hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_ENABLE, size);
+       }
+
+       return hext_stream;
+
+out_free:
+       snd_dma_free_pages(dmab);
+       dmab->area = NULL;
+       dmab->bytes = 0;
+       hstream->bufsize = 0;
+       hstream->format_val = 0;
+out_put:
+       if (pair)
+               hda_dsp_stream_pair_put(sdev, direction, hstream->stream_tag);
+       else
+               hda_dsp_stream_put(sdev, direction, hstream->stream_tag);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_NS(hda_data_stream_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
+                           bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair)
+{
+       struct snd_sof_dev *sdev =  dev_get_drvdata(dev);
+       struct hdac_stream *hstream = hdac_stream(hext_stream);
+       int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
+       int ret = 0;
+
+       if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK)
+               ret = hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0);
+       else
+               snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
+                                       SOF_HDA_SD_CTL_DMA_START, 0);
+
+       if (pair)
+               hda_dsp_stream_pair_put(sdev, hstream->direction, hstream->stream_tag);
+       else
+               hda_dsp_stream_put(sdev, hstream->direction, hstream->stream_tag);
+
+       hstream->running = 0;
+       hstream->substream = NULL;
+
+       /* reset BDL address */
+       snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, 0);
+       snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0);
+
+       snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0);
+
+       if (!persistent_buffer) {
+               snd_dma_free_pages(dmab);
+               dmab->area = NULL;
+               dmab->bytes = 0;
+               hstream->bufsize = 0;
+               hstream->format_val = 0;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_NS(hda_data_stream_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON");
index 9234e73f30fbd6a1a9338542fa892317eb8d4817..3fe00c269114ad70256c451cf0bd9ae32bc9e782 100644 (file)
@@ -905,6 +905,14 @@ int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
 int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                        struct snd_soc_dai *cpu_dai);
 
+struct hdac_ext_stream *
+hda_data_stream_prepare(struct device *dev, unsigned int format, unsigned int size,
+                       struct snd_dma_buffer *dmab, bool persistent_buffer, int direction,
+                       bool is_iccmax, bool pair);
+
+int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
+                           bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair);
+
 /* common dai driver */
 extern struct snd_soc_dai_driver skl_dai[];
 int hda_dsp_dais_suspend(struct snd_sof_dev *sdev);