From d24984635654efb4e50b4151298b4629e5c3aa43 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sat, 29 Oct 2022 09:30:11 -0700 Subject: [PATCH 1/7] ASoC: SOF: Intel: hda-dai: Introduce DAI widget ops Introduce a new ops structure for HDA DAI widget DMA ops and add a new field to struct snd_sof_dai that will be used to set the ops pointer for DAI widgets. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda.h | 31 +++++++++++++++++++++++++++++++ sound/soc/sof/sof-audio.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index eb85a8abdd0cbb..1cbd87fa9f3882 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -927,4 +927,35 @@ extern struct sdw_intel_ops sdw_callback; struct sof_ipc4_fw_library; int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, struct sof_ipc4_fw_library *fw_lib, bool reload); + +/** + * struct hda_dai_widget_dma_ops - DAI DMA ops optional by default unless specified otherwise + * @get_hext_stream: Mandatory function pointer to get the saved pointer to struct hdac_ext_stream + * @assign_hext_stream: Function pointer to assign a hdac_ext_stream + * @release_hext_stream: Function pointer to release the hdac_ext_stream + * @setup_hext_stream: Function pointer for hdac_ext_stream setup + * @reset_hext_stream: Function pointer for hdac_ext_stream reset + * @pre_trigger: Function pointer for DAI DMA pre-trigger actions + * @trigger: Function pointer for DAI DMA trigger actions + * @post_trigger: Function pointer for DAI DMA post-trigger actions + */ +struct hda_dai_widget_dma_ops { + struct hdac_ext_stream *(*get_hext_stream)(struct snd_sof_dev *sdev, + struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream); + struct hdac_ext_stream *(*assign_hext_stream)(struct snd_sof_dev *sdev, + struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream); + void (*release_hext_stream)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream); + void (*setup_hext_stream)(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, + unsigned int format_val); + void (*reset_hext_stream)(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_sream); + int (*pre_trigger)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream, int cmd); + int (*trigger)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream, int cmd); + int (*post_trigger)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream, int cmd); +}; #endif diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index b766af1cf53ce0..7ecd9c3105d21f 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -494,6 +494,8 @@ struct snd_sof_dai { int number_configs; int current_config; struct list_head list; /* list in sdev dai list */ + /* core should not touch this */ + const void *platform_private; void *private; }; From 78b470fcef759c00408c2c8fddc19f1932c29d1b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 14 Nov 2022 21:37:35 -0800 Subject: [PATCH 2/7] ASoC: SOF: Intel: hda-dai: Define and set the HDA DAI widget DMA ops Define and set the get_hext_stream, assign_hext_stream and release_hext_stream DMA ops for HDA DAIs. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/Makefile | 2 +- sound/soc/sof/intel/hda-dai-ops.c | 183 +++++++++++++++++++++++++++++ sound/soc/sof/intel/hda-dai.c | 188 +++++++++++------------------- sound/soc/sof/intel/hda.h | 4 + 4 files changed, 259 insertions(+), 118 deletions(-) create mode 100644 sound/soc/sof/intel/hda-dai-ops.c diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index 8201cbdd654c26..38ab86b6a9fed2 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -5,7 +5,7 @@ snd-sof-acpi-intel-bdw-objs := bdw.o snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ - hda-dai.o hda-bus.o hda-mlink.o \ + hda-dai.o hda-dai-ops.o hda-bus.o hda-mlink.o \ skl.o hda-loader-skl.o \ apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c new file mode 100644 index 00000000000000..9dfcafeab9e467 --- /dev/null +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// 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) 2022 Intel Corporation. All rights reserved. + +#include +#include +#include +#include +#include "../ipc4-priv.h" +#include "../ipc4-topology.h" +#include "../sof-priv.h" +#include "../sof-audio.h" +#include "hda.h" + +/* These ops are only applicable for the HDA DAI's in their current form */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +/* + * This function checks if the host dma channel corresponding + * to the link DMA stream_tag argument is assigned to one + * of the FEs connected to the BE DAI. + */ +static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd, + int dir, int stream_tag) +{ + struct snd_pcm_substream *fe_substream; + struct hdac_stream *fe_hstream; + struct snd_soc_dpcm *dpcm; + + for_each_dpcm_fe(rtd, dir, dpcm) { + fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir); + fe_hstream = fe_substream->runtime->private_data; + if (fe_hstream->stream_tag == stream_tag) + return true; + } + + return false; +} + +static struct hdac_ext_stream * +hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct sof_intel_hda_stream *hda_stream; + const struct sof_intel_dsp_desc *chip; + struct snd_sof_dev *sdev; + struct hdac_ext_stream *res = NULL; + struct hdac_stream *hstream = NULL; + + int stream_dir = substream->stream; + + if (!bus->ppcap) { + dev_err(bus->dev, "stream type not supported\n"); + return NULL; + } + + spin_lock_irq(&bus->reg_lock); + list_for_each_entry(hstream, &bus->stream_list, list) { + struct hdac_ext_stream *hext_stream = + stream_to_hdac_ext_stream(hstream); + if (hstream->direction != substream->stream) + continue; + + hda_stream = hstream_to_sof_hda_stream(hext_stream); + sdev = hda_stream->sdev; + chip = get_chip_info(sdev->pdata); + + /* check if link is available */ + if (!hext_stream->link_locked) { + /* + * choose the first available link for platforms that do not have the + * PROCEN_FMT_QUIRK set. + */ + if (!(chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK)) { + res = hext_stream; + break; + } + + if (hstream->opened) { + /* + * check if the stream tag matches the stream + * tag of one of the connected FEs + */ + if (hda_check_fes(rtd, stream_dir, + hstream->stream_tag)) { + res = hext_stream; + break; + } + } else { + res = hext_stream; + + /* + * This must be a hostless stream. + * So reserve the host DMA channel. + */ + hda_stream->host_reserved = 1; + break; + } + } + } + + if (res) { + /* Make sure that host and link DMA is decoupled. */ + snd_hdac_ext_stream_decouple_locked(bus, res, true); + + res->link_locked = 1; + res->link_substream = substream; + } + spin_unlock_irq(&bus->reg_lock); + + return res; +} + +static struct hdac_ext_stream *hda_get_hext_stream(struct snd_sof_dev *sdev, + struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream) +{ + return snd_soc_dai_get_dma_data(cpu_dai, substream); +} + +static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, + struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream) +{ + struct hdac_ext_stream *hext_stream; + + hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); + if (!hext_stream) + return NULL; + + snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream); + + return hext_stream; +} + +static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream) +{ + struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); + + snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); + snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); +} + +static const struct hda_dai_widget_dma_ops hda_dma_ops = { + .get_hext_stream = hda_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, +}; + +#endif + +const struct hda_dai_widget_dma_ops * +hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) +{ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) + struct snd_sof_dai *sdai = swidget->private; + + switch (sdev->pdata->ipc_type) { + case SOF_IPC: + { + struct sof_dai_private_data *private = sdai->private; + + if (private->dai_config->type == SOF_DAI_INTEL_HDA) + return &hda_dma_ops; + break; + } + case SOF_INTEL_IPC4: + { + struct sof_ipc4_copier *ipc4_copier = sdai->private; + + if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) + return &hda_dma_ops; + break; + } + default: + break; + } +#endif + return NULL; +} diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index a397de8e09e9d0..99867cdac806c2 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -29,101 +29,30 @@ MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override"); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) -/* - * This function checks if the host dma channel corresponding - * to the link DMA stream_tag argument is assigned to one - * of the FEs connected to the BE DAI. - */ -static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd, - int dir, int stream_tag) -{ - struct snd_pcm_substream *fe_substream; - struct hdac_stream *fe_hstream; - struct snd_soc_dpcm *dpcm; - - for_each_dpcm_fe(rtd, dir, dpcm) { - fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir); - fe_hstream = fe_substream->runtime->private_data; - if (fe_hstream->stream_tag == stream_tag) - return true; - } - - return false; -} - -static struct hdac_ext_stream * -hda_link_stream_assign(struct hdac_bus *bus, - struct snd_pcm_substream *substream) +static const struct hda_dai_widget_dma_ops * +hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct sof_intel_hda_stream *hda_stream; - const struct sof_intel_dsp_desc *chip; - struct snd_sof_dev *sdev; - struct hdac_ext_stream *res = NULL; - struct hdac_stream *hstream = NULL; - - int stream_dir = substream->stream; + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_dai *sdai = swidget->private; - if (!bus->ppcap) { - dev_err(bus->dev, "stream type not supported\n"); - return NULL; - } + /* select and set the DAI widget ops if not set already */ + if (!sdai->platform_private) { + const struct hda_dai_widget_dma_ops *ops = + hda_select_dai_widget_ops(sdev, swidget); - spin_lock_irq(&bus->reg_lock); - list_for_each_entry(hstream, &bus->stream_list, list) { - struct hdac_ext_stream *hext_stream = - stream_to_hdac_ext_stream(hstream); - if (hstream->direction != substream->stream) - continue; - - hda_stream = hstream_to_sof_hda_stream(hext_stream); - sdev = hda_stream->sdev; - chip = get_chip_info(sdev->pdata); - - /* check if link is available */ - if (!hext_stream->link_locked) { - /* - * choose the first available link for platforms that do not have the - * PROCEN_FMT_QUIRK set. - */ - if (!(chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK)) { - res = hext_stream; - break; - } - - if (hstream->opened) { - /* - * check if the stream tag matches the stream - * tag of one of the connected FEs - */ - if (hda_check_fes(rtd, stream_dir, - hstream->stream_tag)) { - res = hext_stream; - break; - } - } else { - res = hext_stream; - - /* - * This must be a hostless stream. - * So reserve the host DMA channel. - */ - hda_stream->host_reserved = 1; - break; - } - } - } + if (!ops) + return NULL; - if (res) { - /* Make sure that host and link DMA is decoupled. */ - snd_hdac_ext_stream_decouple_locked(bus, res, true); + /* check if mandatory ops are set */ + if (!ops || !ops->get_hext_stream) + return NULL; - res->link_locked = 1; - res->link_substream = substream; + sdai->platform_private = ops; } - spin_unlock_irq(&bus->reg_lock); - return res; + return sdai->platform_private; } static int hda_link_dma_cleanup(struct snd_pcm_substream *substream, @@ -131,6 +60,8 @@ static int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai, struct snd_soc_dai *codec_dai) { + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); + const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); struct hdac_stream *hstream = &hext_stream->hstream; struct hdac_bus *bus = hstream->bus; struct sof_intel_hda_stream *hda_stream; @@ -145,8 +76,10 @@ static int hda_link_dma_cleanup(struct snd_pcm_substream *substream, stream_tag = hdac_stream(hext_stream)->stream_tag; snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag); } - snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); - snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); + + if (ops->release_hext_stream) + ops->release_hext_stream(sdev, cpu_dai, substream); + hext_stream->link_prepared = 0; /* free the host DMA channel reserved by hostless streams */ @@ -159,6 +92,7 @@ static int hda_link_dma_cleanup(struct snd_pcm_substream *substream, static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) { + const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct hdac_ext_stream *hext_stream; @@ -168,20 +102,21 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, struct hdac_bus *bus; unsigned int format_val; unsigned int link_bps; - unsigned char stream_tag; + int stream_tag; sdev = snd_soc_component_get_drvdata(cpu_dai->component); bus = sof_to_bus(sdev); - hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream); - if (!hext_stream) { - hext_stream = hda_link_stream_assign(bus, substream); - if (!hext_stream) - return -EBUSY; + hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); - snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream); + if (!hext_stream) { + if (ops->assign_hext_stream) + hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream); } + if (!hext_stream) + return -EBUSY; + hstream = &hext_stream->hstream; stream_tag = hstream->stream_tag; hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); @@ -225,11 +160,15 @@ static int hda_link_dma_prepare(struct snd_pcm_substream *substream, struct snd_ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai, int cmd) { + const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream); + struct hdac_ext_stream *hext_stream; int ret; + hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); + if (!hext_stream) return 0; @@ -258,11 +197,18 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, struct snd_ static int hda_link_dma_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); + const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct hdac_ext_stream *hext_stream; - hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream); + if (!ops) { + dev_err(sdev->dev, "DAI widget ops not set\n"); + return -EINVAL; + } + + hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); if (!hext_stream) return 0; @@ -287,18 +233,18 @@ static int hda_dai_hw_params_update(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); + const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); struct hdac_ext_stream *hext_stream; - struct snd_soc_dapm_widget *w; int stream_tag; - hext_stream = snd_soc_dai_get_dma_data(dai, substream); + hext_stream = ops->get_hext_stream(sdev, dai, substream); if (!hext_stream) return -EINVAL; stream_tag = hdac_stream(hext_stream)->stream_tag; - w = snd_soc_dai_get_widget(dai, substream->stream); - /* set up the DAI widget and send the DAI_CONFIG with the new tag */ return hda_dai_widget_update(w, stream_tag - 1, true); } @@ -307,10 +253,17 @@ static int hda_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct hdac_ext_stream *hext_stream = - snd_soc_dai_get_dma_data(dai, substream); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); + struct hdac_ext_stream *hext_stream; int ret; + if (!ops) { + dev_err(sdev->dev, "DAI widget ops not set\n"); + return -EINVAL; + } + + hext_stream = ops->get_hext_stream(sdev, dai, substream); if (hext_stream && hext_stream->link_prepared) return 0; @@ -342,13 +295,14 @@ static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w) static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct hdac_ext_stream *hext_stream = - snd_soc_dai_get_dma_data(dai, substream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct hdac_ext_stream *hext_stream; int stream = substream->stream; int ret; + hext_stream = ops->get_hext_stream(sdev, dai, substream); if (hext_stream && hext_stream->link_prepared) return 0; @@ -417,27 +371,27 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream, static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(dai, substream); + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); - struct snd_sof_widget *pipe_widget; - struct sof_ipc4_pipeline *pipeline; + const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); + struct snd_sof_widget *swidget = w->dobj.private; + struct hdac_ext_stream *hext_stream; + struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; struct snd_soc_pcm_runtime *rtd; - struct snd_sof_widget *swidget; - struct snd_soc_dapm_widget *w; struct snd_soc_dai *codec_dai; int ret; dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd, dai->name, substream->stream); + hext_stream = ops->get_hext_stream(sdev, dai, substream); + if (!hext_stream) + return -EINVAL; + rtd = asoc_substream_to_rtd(substream); codec_dai = asoc_rtd_to_codec(rtd, 0); - w = snd_soc_dai_get_widget(dai, substream->stream); - swidget = w->dobj.private; - pipe_widget = swidget->spipe->pipe_widget; - pipeline = pipe_widget->private; - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 1cbd87fa9f3882..19379ef7ec7b40 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -958,4 +958,8 @@ struct hda_dai_widget_dma_ops { int (*post_trigger)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd); }; + +const struct hda_dai_widget_dma_ops * +hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); + #endif From b070e78518957ebb2917f7ba6f2c385fa081fb8a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sat, 29 Oct 2022 14:51:52 -0700 Subject: [PATCH 3/7] ASoC: SOF: Intel: hda-dai: Add setup_hext_stream/reset_hext_stream DMA ops Define and use the setup_hext_stream/reset_hext_stream DMA ops during link hw_params and cleanup. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dai-ops.c | 13 +++++++++++++ sound/soc/sof/intel/hda-dai.c | 6 ++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 9dfcafeab9e467..57db589906db80 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -144,10 +144,23 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); } +static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, + unsigned int format_val) +{ + snd_hdac_ext_stream_setup(hext_stream, format_val); +} + +static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream) +{ + snd_hdac_ext_stream_reset(hext_stream); +} + static const struct hda_dai_widget_dma_ops hda_dma_ops = { .get_hext_stream = hda_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, }; #endif diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 99867cdac806c2..f1045dc4442f33 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -134,7 +134,8 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, else link_bps = codec_dai->driver->capture.sig_bits; - snd_hdac_ext_stream_reset(hext_stream); + if (ops->reset_hext_stream) + ops->reset_hext_stream(sdev, hext_stream); format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params), params_format(params), link_bps, 0); @@ -142,7 +143,8 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", format_val, params_rate(params), params_channels(params), params_format(params)); - snd_hdac_ext_stream_setup(hext_stream, format_val); + if (ops->setup_hext_stream) + ops->setup_hext_stream(sdev, hext_stream, format_val); hext_stream->link_prepared = 1; From bf8e96285fc47cd61ce95fdb34d8f11303d98b24 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sat, 29 Oct 2022 15:20:00 -0700 Subject: [PATCH 4/7] ASoC: SOF: hda-dai: Use the topology IPC dai_config op Use the topology IPC dai_config to update the dai_config for HDA DAI widgets. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dai.c | 86 +++++++++++++++++------------------ 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index f1045dc4442f33..09bede4df5a7b2 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -29,6 +29,27 @@ MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override"); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +static int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, + struct snd_sof_dai_config_data *data) +{ + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_soc_component *component = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); + int ret; + + if (tplg_ops && tplg_ops->dai_config) { + ret = tplg_ops->dai_config(sdev, swidget, flags, data); + if (ret < 0) { + dev_err(sdev->dev, "DAI config with flags %x failed for widget %s\n", + flags, w->name); + return ret; + } + } + + return 0; +} + static const struct hda_dai_widget_dma_ops * hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { @@ -231,33 +252,16 @@ static int hda_dai_widget_update(struct snd_soc_dapm_widget *w, return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data); } -static int hda_dai_hw_params_update(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); - const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); - struct hdac_ext_stream *hext_stream; - int stream_tag; - - hext_stream = ops->get_hext_stream(sdev, dai, substream); - if (!hext_stream) - return -EINVAL; - - stream_tag = hdac_stream(hext_stream)->stream_tag; - - /* set up the DAI widget and send the DAI_CONFIG with the new tag */ - return hda_dai_widget_update(w, stream_tag - 1, true); -} - static int hda_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); struct hdac_ext_stream *hext_stream; + struct snd_sof_dai_config_data data = { 0 }; + unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS; int ret; if (!ops) { @@ -273,35 +277,22 @@ static int hda_dai_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - return hda_dai_hw_params_update(substream, params, dai); -} - - -static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w) -{ - struct snd_sof_widget *swidget = w->dobj.private; - struct snd_soc_component *component = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - int ret = 0; + hext_stream = ops->get_hext_stream(sdev, dai, substream); - if (tplg_ops->dai_config) { - ret = tplg_ops->dai_config(sdev, swidget, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL); - if (ret < 0) - dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__, - w->name); - } + flags |= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; + data.dai_data = hdac_stream(hext_stream)->stream_tag - 1; - return ret; + return hda_dai_config(w, flags, &data); } static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct hdac_ext_stream *hext_stream; - int stream = substream->stream; + struct snd_sof_dai_config_data data = { 0 }; + unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS; int ret; hext_stream = ops->get_hext_stream(sdev, dai, substream); @@ -314,7 +305,12 @@ static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_d if (ret < 0) return ret; - return hda_dai_hw_params_update(substream, &rtd->dpcm[stream].hw_params, dai); + hext_stream = ops->get_hext_stream(sdev, dai, substream); + + flags |= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; + data.dai_data = hdac_stream(hext_stream)->stream_tag - 1; + + return hda_dai_config(w, flags, &data); } static int hda_dai_hw_free_ipc(int stream, /* direction */ @@ -355,7 +351,7 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = hda_dai_config_pause_push_ipc(w); + ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL); if (ret < 0) return ret; break; @@ -461,13 +457,17 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, static int hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); + struct snd_sof_dai_config_data data = { 0 }; int ret; ret = hda_link_dma_hw_free(substream, dai); if (ret < 0) return ret; - return hda_dai_hw_free_ipc(substream->stream, dai); + data.dai_data = DMA_CHAN_INVALID; + + return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data); } static const struct snd_soc_dai_ops ipc3_hda_dai_ops = { From 153dca494c2ae7bde8900eef0d09e76713c1911f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sat, 29 Oct 2022 15:23:20 -0700 Subject: [PATCH 5/7] ASoC: SOF: Intel: hda-dai: Define DAI widget DMA trigger ops for IPC4 Define and use the SOF widget's DMA pre_trigger/trigger/post_trigger ops in ipc4_hda_dai_trigger(). Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dai-ops.c | 128 +++++++++++++++++++++++++++++- sound/soc/sof/intel/hda-dai.c | 62 ++++----------- 2 files changed, 139 insertions(+), 51 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 57db589906db80..992c3177259309 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -155,7 +155,129 @@ static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stre snd_hdac_ext_stream_reset(hext_stream); } -static const struct hda_dai_widget_dma_ops hda_dma_ops = { +static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream, int cmd) +{ + struct snd_sof_widget *pipe_widget; + struct sof_ipc4_pipeline *pipeline; + struct snd_sof_widget *swidget; + struct snd_soc_dapm_widget *w; + int ret; + + w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + swidget = w->dobj.private; + pipe_widget = swidget->spipe->pipe_widget; + pipeline = pipe_widget->private; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, + SOF_IPC4_PIPE_PAUSED); + if (ret < 0) + return ret; + + pipeline->state = SOF_IPC4_PIPE_PAUSED; + break; + default: + dev_err(sdev->dev, "unknown trigger command %d\n", cmd); + return -EINVAL; + } + + return 0; +} + +static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream, int cmd) +{ + struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + snd_hdac_ext_stream_start(hext_stream); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + snd_hdac_ext_stream_clear(hext_stream); + break; + default: + dev_err(sdev->dev, "unknown trigger command %d\n", cmd); + return -EINVAL; + } + + return 0; +} + +static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream, int cmd) +{ + struct snd_sof_widget *pipe_widget; + struct sof_ipc4_pipeline *pipeline; + struct snd_sof_widget *swidget; + struct snd_soc_dapm_widget *w; + int ret; + + w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + swidget = w->dobj.private; + pipe_widget = swidget->spipe->pipe_widget; + pipeline = pipe_widget->private; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (pipeline->state != SOF_IPC4_PIPE_PAUSED) { + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, + SOF_IPC4_PIPE_PAUSED); + if (ret < 0) + return ret; + pipeline->state = SOF_IPC4_PIPE_PAUSED; + } + + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, + SOF_IPC4_PIPE_RUNNING); + if (ret < 0) + return ret; + pipeline->state = SOF_IPC4_PIPE_RUNNING; + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + { + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, + SOF_IPC4_PIPE_RESET); + if (ret < 0) + return ret; + + pipeline->state = SOF_IPC4_PIPE_RESET; + break; + } + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + default: + dev_err(sdev->dev, "unknown trigger command %d\n", cmd); + return -EINVAL; + } + + return 0; +} + +static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { + .get_hext_stream = hda_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, + .pre_trigger = hda_ipc4_pre_trigger, + .trigger = hda_trigger, + .post_trigger = hda_ipc4_post_trigger +}; + +static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = { .get_hext_stream = hda_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, .release_hext_stream = hda_release_hext_stream, @@ -177,7 +299,7 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg struct sof_dai_private_data *private = sdai->private; if (private->dai_config->type == SOF_DAI_INTEL_HDA) - return &hda_dma_ops; + return &hda_ipc3_dma_ops; break; } case SOF_INTEL_IPC4: @@ -185,7 +307,7 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg struct sof_ipc4_copier *ipc4_copier = sdai->private; if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) - return &hda_dma_ops; + return &hda_ipc4_dma_ops; break; } default: diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 09bede4df5a7b2..d5fe5ba679922d 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -369,13 +369,9 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream, static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); - struct snd_sof_widget *swidget = w->dobj.private; struct hdac_ext_stream *hext_stream; - struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; - struct sof_ipc4_pipeline *pipeline = pipe_widget->private; struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai *codec_dai; int ret; @@ -390,65 +386,35 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, rtd = asoc_substream_to_rtd(substream); codec_dai = asoc_rtd_to_codec(rtd, 0); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_hdac_ext_stream_start(hext_stream); - if (pipeline->state != SOF_IPC4_PIPE_PAUSED) { - ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, - SOF_IPC4_PIPE_PAUSED); - if (ret < 0) - return ret; - pipeline->state = SOF_IPC4_PIPE_PAUSED; - } - - ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, - SOF_IPC4_PIPE_RUNNING); + if (ops->pre_trigger) { + ret = ops->pre_trigger(sdev, dai, substream, cmd); if (ret < 0) return ret; - pipeline->state = SOF_IPC4_PIPE_RUNNING; - break; - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - { - ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, - SOF_IPC4_PIPE_PAUSED); + } + + if (ops->trigger) { + ret = ops->trigger(sdev, dai, substream, cmd); if (ret < 0) return ret; + } - pipeline->state = SOF_IPC4_PIPE_PAUSED; - - snd_hdac_ext_stream_clear(hext_stream); - - ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, - SOF_IPC4_PIPE_RESET); + if (ops->post_trigger) { + ret = ops->post_trigger(sdev, dai, substream, cmd); if (ret < 0) return ret; + } - pipeline->state = SOF_IPC4_PIPE_RESET; - + switch (cmd) { + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: ret = hda_link_dma_cleanup(substream, hext_stream, dai, codec_dai); if (ret < 0) { dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__); return ret; } break; - } - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - { - ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, - SOF_IPC4_PIPE_PAUSED); - if (ret < 0) - return ret; - - pipeline->state = SOF_IPC4_PIPE_PAUSED; - - snd_hdac_ext_stream_clear(hext_stream); - break; - } default: - dev_err(sdev->dev, "%s: unknown trigger command %d\n", __func__, cmd); - return -EINVAL; + break; } return 0; From aad70087b04d07fe48c6963a1abd261ef345bf92 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sat, 29 Oct 2022 15:51:56 -0700 Subject: [PATCH 6/7] ASoC: SOF: Intel: hda: Unify DAI drv ops for IPC3 and IPC4 Define the post_trigger DMA op for IPC3 and unify the DAI driver ops for IPC3 and IPC4 for HDA DAI's. Also, use the post_trigger op to stop the paused streams properly in the hda_dai_suspend() function. This fixes the suspend while paused case for IPC4 because previously we weren't resetting the pipeline when suspending the system with some paused streams. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dai-ops.c | 25 ++++ sound/soc/sof/intel/hda-dai.c | 183 ++++++------------------------ sound/soc/sof/intel/hda.h | 2 + 3 files changed, 62 insertions(+), 148 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 992c3177259309..be109f33715f24 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -277,12 +277,37 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { .post_trigger = hda_ipc4_post_trigger }; +static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + { + struct snd_sof_dai_config_data data = { 0 }; + + data.dai_data = DMA_CHAN_INVALID; + return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data); + } + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL); + default: + break; + } + + return 0; +} + static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = { .get_hext_stream = hda_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, .release_hext_stream = hda_release_hext_stream, .setup_hext_stream = hda_setup_hext_stream, .reset_hext_stream = hda_reset_hext_stream, + .trigger = hda_trigger, + .post_trigger = hda_ipc3_post_trigger, }; #endif diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index d5fe5ba679922d..557d6d977c1120 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -27,10 +27,8 @@ static bool hda_use_tplg_nhlt; module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444); MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override"); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - -static int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, - struct snd_sof_dai_config_data *data) +int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, + struct snd_sof_dai_config_data *data) { struct snd_sof_widget *swidget = w->dobj.private; struct snd_soc_component *component = swidget->scomp; @@ -50,6 +48,8 @@ static int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, return 0; } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) + static const struct hda_dai_widget_dma_ops * hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { @@ -180,44 +180,6 @@ static int hda_link_dma_prepare(struct snd_pcm_substream *substream, struct snd_ return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai); } -static int hda_link_dma_trigger(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai, - int cmd) -{ - const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct hdac_ext_stream *hext_stream; - int ret; - - hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); - - if (!hext_stream) - return 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_hdac_ext_stream_start(hext_stream); - break; - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - snd_hdac_ext_stream_clear(hext_stream); - ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai); - if (ret < 0) - return ret; - - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - snd_hdac_ext_stream_clear(hext_stream); - - break; - default: - return -EINVAL; - } - return 0; -} - static int hda_link_dma_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); @@ -238,20 +200,6 @@ static int hda_link_dma_hw_free(struct snd_pcm_substream *substream, struct snd_ return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai); } -static int hda_dai_widget_update(struct snd_soc_dapm_widget *w, - int channel, bool widget_setup) -{ - struct snd_sof_dai_config_data data; - - data.dai_data = channel; - - /* set up/free DAI widget and send DAI_CONFIG IPC */ - if (widget_setup) - return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data); - - return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data); -} - static int hda_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -313,61 +261,11 @@ static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_d return hda_dai_config(w, flags, &data); } -static int hda_dai_hw_free_ipc(int stream, /* direction */ - struct snd_soc_dai *dai) -{ - struct snd_soc_dapm_widget *w; - - w = snd_soc_dai_get_widget(dai, stream); - - /* free the link DMA channel in the FW and the DAI widget */ - return hda_dai_widget_update(w, DMA_CHAN_INVALID, false); -} - -static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - struct snd_soc_dapm_widget *w; - int ret; - - dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd, - dai->name, substream->stream); - - ret = hda_link_dma_trigger(substream, dai, cmd); - if (ret < 0) - return ret; - - w = snd_soc_dai_get_widget(dai, substream->stream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - /* - * free DAI widget during stop/suspend to keep widget use_count's balanced. - */ - ret = hda_dai_hw_free_ipc(substream->stream, dai); - if (ret < 0) - return ret; - - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL); - if (ret < 0) - return ret; - break; - - default: - break; - } - return 0; -} - /* * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes * (over IPC channel) and DMA state change (direct host register changes). */ -static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) +static int hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); @@ -436,10 +334,10 @@ static int hda_dai_hw_free(struct snd_pcm_substream *substream, return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data); } -static const struct snd_soc_dai_ops ipc3_hda_dai_ops = { +static const struct snd_soc_dai_ops hda_dai_ops = { .hw_params = hda_dai_hw_params, .hw_free = hda_dai_hw_free, - .trigger = ipc3_hda_dai_trigger, + .trigger = hda_dai_trigger, .prepare = hda_dai_prepare, }; @@ -462,12 +360,22 @@ static int hda_dai_suspend(struct hdac_bus *bus) * explicitly during suspend. */ if (hext_stream->link_substream) { - struct snd_soc_dai *cpu_dai; + const struct hda_dai_widget_dma_ops *ops; + struct snd_sof_widget *swidget; + struct snd_soc_dapm_widget *w; struct snd_soc_dai *codec_dai; + struct snd_soc_dai *cpu_dai; + struct snd_sof_dev *sdev; + struct snd_sof_dai *sdai; rtd = asoc_substream_to_rtd(hext_stream->link_substream); cpu_dai = asoc_rtd_to_cpu(rtd, 0); codec_dai = asoc_rtd_to_codec(rtd, 0); + w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction); + swidget = w->dobj.private; + sdev = snd_soc_component_get_drvdata(swidget->scomp); + sdai = swidget->private; + ops = sdai->platform_private; ret = hda_link_dma_cleanup(hext_stream->link_substream, hext_stream, @@ -475,60 +383,39 @@ static int hda_dai_suspend(struct hdac_bus *bus) if (ret < 0) return ret; - /* for consistency with TRIGGER_SUSPEND we free DAI resources */ - ret = hda_dai_hw_free_ipc(hdac_stream(hext_stream)->direction, cpu_dai); - if (ret < 0) - return ret; + /* for consistency with TRIGGER_SUSPEND */ + if (ops->post_trigger) { + ret = ops->post_trigger(sdev, cpu_dai, + hext_stream->link_substream, + SNDRV_PCM_TRIGGER_SUSPEND); + if (ret < 0) + return ret; + } } } return 0; } -static const struct snd_soc_dai_ops ipc4_hda_dai_ops = { - .hw_params = hda_dai_hw_params, - .hw_free = hda_dai_hw_free, - .trigger = ipc4_hda_dai_trigger, - .prepare = hda_dai_prepare, -}; - #endif void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) { int i; - switch (sdev->pdata->ipc_type) { - case SOF_IPC: - for (i = 0; i < ops->num_drv; i++) { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - if (strstr(ops->drv[i].name, "iDisp") || - strstr(ops->drv[i].name, "Analog") || - strstr(ops->drv[i].name, "Digital")) - ops->drv[i].ops = &ipc3_hda_dai_ops; -#endif - } - break; - case SOF_INTEL_IPC4: - { - struct sof_ipc4_fw_data *ipc4_data = sdev->private; - - for (i = 0; i < ops->num_drv; i++) { + for (i = 0; i < ops->num_drv; i++) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - if (strstr(ops->drv[i].name, "iDisp") || - strstr(ops->drv[i].name, "Analog") || - strstr(ops->drv[i].name, "Digital")) - ops->drv[i].ops = &ipc4_hda_dai_ops; + if (strstr(ops->drv[i].name, "iDisp") || + strstr(ops->drv[i].name, "Analog") || + strstr(ops->drv[i].name, "Digital")) + ops->drv[i].ops = &hda_dai_ops; #endif - } + } - if (!hda_use_tplg_nhlt) - ipc4_data->nhlt = intel_nhlt_init(sdev->dev); + if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) { + struct sof_ipc4_fw_data *ipc4_data = sdev->private; - break; - } - default: - break; + ipc4_data->nhlt = intel_nhlt_init(sdev->dev); } } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 19379ef7ec7b40..0ce8ff2e58c050 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -961,5 +961,7 @@ struct hda_dai_widget_dma_ops { const struct hda_dai_widget_dma_ops * hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); +int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, + struct snd_sof_dai_config_data *data); #endif From ee710aeef92b667631ae99f0fd7398425c7717bb Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 15 Nov 2022 18:06:06 -0800 Subject: [PATCH 7/7] ASoC: SOF: Intel: hda: Remove hda_ctrl_dai_widget_setup/free() Remove these functions and reuse hda_dai_config(). Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda.c | 78 +++------------------------------------ sound/soc/sof/intel/hda.h | 4 -- 2 files changed, 6 insertions(+), 76 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 81c697e2010859..890993b2f14b80 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -44,70 +44,6 @@ #define EXCEPT_MAX_HDR_SIZE 0x400 #define HDA_EXT_ROM_STATUS_SIZE 8 -int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags, - struct snd_sof_dai_config_data *data) -{ - struct snd_sof_widget *swidget = w->dobj.private; - struct snd_soc_component *component = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - struct snd_sof_dai *sof_dai = swidget->private; - int ret; - - if (!sof_dai) { - dev_err(sdev->dev, "%s: No DAI for DAI widget %s\n", __func__, w->name); - return -EINVAL; - } - - if (tplg_ops->dai_config) { - unsigned int flags; - - /* set HW_PARAMS flag along with quirks */ - flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS | - quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; - - ret = tplg_ops->dai_config(sdev, swidget, flags, data); - if (ret < 0) { - dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__, - w->name); - return ret; - } - } - - return 0; -} - -int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags, - struct snd_sof_dai_config_data *data) -{ - struct snd_sof_widget *swidget = w->dobj.private; - struct snd_soc_component *component = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - struct snd_sof_dai *sof_dai = swidget->private; - - if (!sof_dai) { - dev_err(sdev->dev, "%s: No DAI for BE DAI widget %s\n", __func__, w->name); - return -EINVAL; - } - - if (tplg_ops->dai_config) { - unsigned int flags; - int ret; - - /* set HW_FREE flag along with any quirks */ - flags = SOF_DAI_CONFIG_FLAGS_HW_FREE | - quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; - - ret = tplg_ops->dai_config(sdev, swidget, flags, data); - if (ret < 0) - dev_err(sdev->dev, "%s: DAI config failed for widget '%s'\n", __func__, - w->name); - } - - return 0; -} - #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) /* @@ -124,30 +60,28 @@ static int sdw_params_stream(struct device *dev, struct sdw_intel_stream_params_data *params_data) { struct snd_soc_dai *d = params_data->dai; - struct snd_sof_dai_config_data data; - struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(d, params_data->stream); + struct snd_sof_dai_config_data data = { 0 }; - w = snd_soc_dai_get_widget(d, params_data->stream); data.dai_index = (params_data->link_id << 8) | d->id; data.dai_data = params_data->alh_stream_id; - return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE, &data); + return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_PARAMS, &data); } static int sdw_free_stream(struct device *dev, struct sdw_intel_stream_free_data *free_data) { struct snd_soc_dai *d = free_data->dai; - struct snd_sof_dai_config_data data; - struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(d, free_data->stream); + struct snd_sof_dai_config_data data = { 0 }; - w = snd_soc_dai_get_widget(d, free_data->stream); data.dai_index = (free_data->link_id << 8) | d->id; /* send invalid stream_id */ data.dai_data = 0xFFFF; - return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data); + return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data); } struct sdw_intel_ops sdw_callback = { diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 0ce8ff2e58c050..926f755a7e98c1 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -895,10 +895,6 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) struct snd_sof_dai; struct sof_ipc_dai_config; -int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags, - struct snd_sof_dai_config_data *data); -int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags, - struct snd_sof_dai_config_data *data); #define SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY (0) /* previous implementation */ #define SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS (1) /* recommended if VC0 only */