summaryrefslogtreecommitdiff
path: root/sound/soc/sof
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof')
-rw-r--r--sound/soc/sof/amd/acp.h3
-rw-r--r--sound/soc/sof/amd/pci-rmb.c3
-rw-r--r--sound/soc/sof/amd/pci-rn.c3
-rw-r--r--sound/soc/sof/intel/Kconfig3
-rw-r--r--sound/soc/sof/intel/hda-bus.c11
-rw-r--r--sound/soc/sof/intel/hda-dai-ops.c79
-rw-r--r--sound/soc/sof/intel/hda-dai.c104
-rw-r--r--sound/soc/sof/intel/hda-loader-skl.c1
-rw-r--r--sound/soc/sof/intel/hda-stream.c1
-rw-r--r--sound/soc/sof/intel/hda.c6
-rw-r--r--sound/soc/sof/intel/hda.h6
-rw-r--r--sound/soc/sof/intel/mtl.c33
-rw-r--r--sound/soc/sof/intel/skl.c1
-rw-r--r--sound/soc/sof/intel/tgl.c10
-rw-r--r--sound/soc/sof/ipc3-control.c54
-rw-r--r--sound/soc/sof/ipc4-control.c39
-rw-r--r--sound/soc/sof/ipc4-loader.c72
-rw-r--r--sound/soc/sof/ipc4-pcm.c4
-rw-r--r--sound/soc/sof/ipc4-priv.h10
-rw-r--r--sound/soc/sof/ipc4-topology.c415
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186-clk.c1
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186.c97
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195-clk.c1
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195.c36
-rw-r--r--sound/soc/sof/nocodec.c8
-rw-r--r--sound/soc/sof/pcm.c2
-rw-r--r--sound/soc/sof/sof-audio.h1
-rw-r--r--sound/soc/sof/topology.c2
28 files changed, 665 insertions, 341 deletions
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index 1c535cc6c3a9..dc624f727aa3 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -55,6 +55,9 @@
#define ACP_DSP_TO_HOST_IRQ 0x04
+#define ACP_RN_PCI_ID 0x01
+#define ACP_RMB_PCI_ID 0x6F
+
#define HOST_BRIDGE_CZN 0x1630
#define HOST_BRIDGE_RMB 0x14B5
#define ACP_SHA_STAT 0x8000
diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c
index eaf70ea6e556..58b3092425f1 100644
--- a/sound/soc/sof/amd/pci-rmb.c
+++ b/sound/soc/sof/amd/pci-rmb.c
@@ -65,6 +65,9 @@ static int acp_pci_rmb_probe(struct pci_dev *pci, const struct pci_device_id *pc
{
unsigned int flag;
+ if (pci->revision != ACP_RMB_PCI_ID)
+ return -ENODEV;
+
flag = snd_amd_acp_find_config(pci);
if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC)
return -ENODEV;
diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c
index 4809cb644152..7409e21ce5aa 100644
--- a/sound/soc/sof/amd/pci-rn.c
+++ b/sound/soc/sof/amd/pci-rn.c
@@ -65,6 +65,9 @@ static int acp_pci_rn_probe(struct pci_dev *pci, const struct pci_device_id *pci
{
unsigned int flag;
+ if (pci->revision != ACP_RN_PCI_ID)
+ return -ENODEV;
+
flag = snd_amd_acp_find_config(pci);
if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC)
return -ENODEV;
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index f4eeacf1f281..69c1a370d3b6 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -284,8 +284,6 @@ if SND_SOC_SOF_HDA_COMMON
config SND_SOC_SOF_HDA_LINK
bool "SOF support for HDA Links(HDA/HDMI)"
- depends on SND_SOC_SOF_NOCODEC_SUPPORT=n
- select SND_SOC_SOF_PROBE_WORK_QUEUE
help
This adds support for HDA links(HDA/HDMI) with Sound Open Firmware
for Intel(R) platforms.
@@ -295,6 +293,7 @@ config SND_SOC_SOF_HDA_LINK
config SND_SOC_SOF_HDA_AUDIO_CODEC
bool "SOF support for HDAudio codecs"
depends on SND_SOC_SOF_HDA_LINK
+ select SND_SOC_SOF_PROBE_WORK_QUEUE
help
This adds support for HDAudio codecs with Sound Open Firmware
for Intel(R) platforms.
diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c
index acb4b85868d0..fc63085d2d74 100644
--- a/sound/soc/sof/intel/hda-bus.c
+++ b/sound/soc/sof/intel/hda-bus.c
@@ -70,9 +70,14 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops);
-#else /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
+#else
+ snd_hdac_ext_bus_init(bus, dev, NULL, NULL);
+#endif
+#else
+
memset(bus, 0, sizeof(*bus));
bus->dev = dev;
@@ -87,12 +92,12 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev)
bus->idx = 0;
spin_lock_init(&bus->reg_lock);
-#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
+#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
}
void sof_hda_bus_exit(struct snd_sof_dev *sdev)
{
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
struct hdac_bus *bus = sof_to_bus(sdev);
snd_hdac_ext_bus_exit(bus);
diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c
index 4b39cecacd68..1e58256c8003 100644
--- a/sound/soc/sof/intel/hda-dai-ops.c
+++ b/sound/soc/sof/intel/hda-dai-ops.c
@@ -16,7 +16,7 @@
#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)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
/*
* This function checks if the host dma channel corresponding
* to the link DMA stream_tag argument is assigned to one
@@ -120,6 +120,26 @@ static struct hdac_ext_stream *hda_get_hext_stream(struct snd_sof_dev *sdev,
return snd_soc_dai_get_dma_data(cpu_dai, substream);
}
+static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev,
+ struct snd_soc_dai *cpu_dai,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_sof_widget *pipe_widget;
+ struct sof_ipc4_pipeline *pipeline;
+ struct snd_sof_widget *swidget;
+ struct snd_soc_dapm_widget *w;
+
+ w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+ swidget = w->dobj.private;
+ pipe_widget = swidget->spipe->pipe_widget;
+ pipeline = pipe_widget->private;
+
+ /* mark pipeline so that it can be skipped during FE trigger */
+ pipeline->skip_during_fe_trigger = true;
+
+ 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)
@@ -158,17 +178,20 @@ static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stre
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 sof_ipc4_fw_data *ipc4_data = sdev->private;
struct snd_sof_widget *pipe_widget;
struct sof_ipc4_pipeline *pipeline;
struct snd_sof_widget *swidget;
struct snd_soc_dapm_widget *w;
- int ret;
+ int ret = 0;
w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
swidget = w->dobj.private;
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
+ mutex_lock(&ipc4_data->pipeline_state_mutex);
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -179,16 +202,17 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp
ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
SOF_IPC4_PIPE_PAUSED);
if (ret < 0)
- return ret;
+ goto out;
pipeline->state = SOF_IPC4_PIPE_PAUSED;
break;
default:
dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
- return -EINVAL;
+ ret = -EINVAL;
}
-
- return 0;
+out:
+ mutex_unlock(&ipc4_data->pipeline_state_mutex);
+ return ret;
}
static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
@@ -217,57 +241,66 @@ static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
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 sof_ipc4_fw_data *ipc4_data = sdev->private;
struct snd_sof_widget *pipe_widget;
struct sof_ipc4_pipeline *pipeline;
struct snd_sof_widget *swidget;
struct snd_soc_dapm_widget *w;
- int ret;
+ int ret = 0;
w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
swidget = w->dobj.private;
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
+ mutex_lock(&ipc4_data->pipeline_state_mutex);
+
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;
+ goto out;
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;
+ goto out;
pipeline->state = SOF_IPC4_PIPE_RUNNING;
+ swidget->spipe->started_count++;
break;
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
- {
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
- SOF_IPC4_PIPE_RESET);
+ SOF_IPC4_PIPE_RUNNING);
if (ret < 0)
- return ret;
-
- pipeline->state = SOF_IPC4_PIPE_RESET;
+ goto out;
+ pipeline->state = SOF_IPC4_PIPE_RUNNING;
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ /*
+ * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have
+ * been stopped. So, clear the started_count so that the pipeline can be reset
+ */
+ swidget->spipe->started_count = 0;
break;
- }
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
break;
default:
dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
-
- return 0;
+out:
+ mutex_unlock(&ipc4_data->pipeline_state_mutex);
+ return ret;
}
static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
- .get_hext_stream = hda_get_hext_stream,
+ .get_hext_stream = hda_ipc4_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
.release_hext_stream = hda_release_hext_stream,
.setup_hext_stream = hda_setup_hext_stream,
@@ -350,7 +383,7 @@ static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
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)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
struct snd_sof_dai *sdai;
if (sdev->dspless_mode_selected)
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 44a5d94c5050..09d8ee98581d 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -27,20 +27,26 @@ 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");
+static struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w)
+{
+ struct snd_sof_widget *swidget = w->dobj.private;
+ struct snd_soc_component *component = swidget->scomp;
+
+ return snd_soc_component_get_drvdata(component);
+}
+
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;
const struct sof_ipc_tplg_ops *tplg_ops;
- struct snd_soc_component *component;
struct snd_sof_dev *sdev;
int ret;
if (!swidget)
return 0;
- component = swidget->scomp;
- sdev = snd_soc_component_get_drvdata(component);
+ sdev = widget_to_sdev(w);
tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops && tplg_ops->dai_config) {
@@ -55,16 +61,26 @@ 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)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
+
+static struct snd_sof_dev *dai_to_sdev(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+
+ return widget_to_sdev(w);
+}
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_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_dev *sdev;
struct snd_sof_dai *sdai;
+ sdev = widget_to_sdev(w);
+
/*
* The swidget parameter of hda_select_dai_widget_ops() is ignored in
* case of DSPless mode
@@ -96,14 +112,16 @@ 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;
struct hdac_ext_link *hlink;
+ struct snd_sof_dev *sdev;
int stream_tag;
+ sdev = dai_to_sdev(substream, cpu_dai);
+
hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
if (!hlink)
return -EINVAL;
@@ -140,7 +158,7 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
unsigned int link_bps;
int stream_tag;
- sdev = snd_soc_component_get_drvdata(cpu_dai->component);
+ sdev = dai_to_sdev(substream, cpu_dai);
bus = sof_to_bus(sdev);
hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
@@ -188,21 +206,14 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int hda_link_dma_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
+static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- int stream = substream->stream;
-
- return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
-}
-
-static int hda_dai_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;
+ struct snd_sof_dev *sdev = dai_to_sdev(substream, cpu_dai);
if (!ops) {
dev_err(sdev->dev, "DAI widget ops not set\n");
@@ -216,16 +227,16 @@ static int hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_d
return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai);
}
-static int hda_dai_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+static int __maybe_unused 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;
+ struct snd_sof_dev *sdev = widget_to_sdev(w);
int ret;
if (!ops) {
@@ -249,50 +260,25 @@ static int hda_dai_hw_params(struct snd_pcm_substream *substream,
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 hdac_ext_stream *hext_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);
- if (hext_stream && hext_stream->link_prepared)
- return 0;
-
- dev_dbg(sdev->dev, "prepare stream dir %d\n", substream->stream);
-
- ret = hda_link_dma_prepare(substream, dai);
- if (ret < 0)
- return ret;
-
- 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);
-}
-
/*
* 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 hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
+static int __maybe_unused 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);
struct hdac_ext_stream *hext_stream;
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai *codec_dai;
+ struct snd_sof_dev *sdev;
int ret;
dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
dai->name, substream->stream);
+ sdev = dai_to_sdev(substream, dai);
+
hext_stream = ops->get_hext_stream(sdev, dai, substream);
if (!hext_stream)
return -EINVAL;
@@ -333,6 +319,16 @@ static int hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct
return 0;
}
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
+
+static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ int stream = substream->stream;
+
+ return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, dai);
+}
+
static const struct snd_soc_dai_ops hda_dai_ops = {
.hw_params = hda_dai_hw_params,
.hw_free = hda_dai_hw_free,
@@ -340,6 +336,8 @@ static const struct snd_soc_dai_ops hda_dai_ops = {
.prepare = hda_dai_prepare,
};
+#endif
+
static int hda_dai_suspend(struct hdac_bus *bus)
{
struct snd_soc_pcm_runtime *rtd;
@@ -372,7 +370,7 @@ static int hda_dai_suspend(struct hdac_bus *bus)
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);
+ sdev = widget_to_sdev(w);
sdai = swidget->private;
ops = sdai->platform_private;
@@ -588,7 +586,7 @@ int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
* Since the component suspend is called last, we can trap this corner case
* and force the DAIs to release their resources.
*/
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
int ret;
ret = hda_dai_suspend(sof_to_bus(sdev));
diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c
index 69fdef8f89ae..1e77ca936f80 100644
--- a/sound/soc/sof/intel/hda-loader-skl.c
+++ b/sound/soc/sof/intel/hda-loader-skl.c
@@ -15,7 +15,6 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <sound/hdaudio_ext.h>
#include <sound/sof.h>
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 8de422604ad5..b13acb959653 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -15,7 +15,6 @@
* Hardware interface for generic Intel audio DSP HDA IP
*/
-#include <linux/pm_runtime.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda_register.h>
#include <sound/sof.h>
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 3153e21f100a..835c2568dd60 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -1562,7 +1562,11 @@ void hda_set_mach_params(struct snd_soc_acpi_mach *mach,
mach_params = &mach->mach_params;
mach_params->platform = dev_name(sdev->dev);
- mach_params->num_dai_drivers = desc->ops->num_drv;
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ mach_params->num_dai_drivers = SOF_SKL_NUM_DAIS_NOCODEC;
+ else
+ mach_params->num_dai_drivers = desc->ops->num_drv;
mach_params->dai_drivers = desc->ops->drv;
}
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index c4befacde23e..5b3dad2dadf4 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -414,10 +414,12 @@
(HDA_DSP_BDL_SIZE / sizeof(struct sof_intel_dsp_bdl))
/* Number of DAIs */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#define SOF_SKL_NUM_DAIS_NOCODEC 8
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
#define SOF_SKL_NUM_DAIS 15
#else
-#define SOF_SKL_NUM_DAIS 8
+#define SOF_SKL_NUM_DAIS SOF_SKL_NUM_DAIS_NOCODEC
#endif
/* Intel HD Audio SRAM Window 0*/
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 46caf3ccde66..93dc2c9d8448 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -613,6 +613,36 @@ static u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
return ((u64)llp_u << 32) | llp_l;
}
+static int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
+{
+ const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
+
+ if (core == SOF_DSP_PRIMARY_CORE)
+ return mtl_dsp_core_power_up(sdev, SOF_DSP_PRIMARY_CORE);
+
+ if (pm_ops->set_core_state)
+ return pm_ops->set_core_state(sdev, core, true);
+
+ return 0;
+}
+
+static int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)
+{
+ const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
+ int ret;
+
+ if (pm_ops->set_core_state) {
+ ret = pm_ops->set_core_state(sdev, core, false);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (core == SOF_DSP_PRIMARY_CORE)
+ return mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE);
+
+ return 0;
+}
+
/* Meteorlake ops */
struct snd_sof_dsp_ops sof_mtl_ops;
EXPORT_SYMBOL_NS(sof_mtl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
@@ -649,7 +679,8 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev)
sof_mtl_ops.parse_platform_ext_manifest = NULL;
/* dsp core get/put */
- /* TODO: add core_get and core_put */
+ sof_mtl_ops.core_get = mtl_dsp_core_get;
+ sof_mtl_ops.core_put = mtl_dsp_core_put;
sof_mtl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position;
diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c
index 13efdb94d071..d24e64e71b58 100644
--- a/sound/soc/sof/intel/skl.c
+++ b/sound/soc/sof/intel/skl.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/pci.h>
-#include <linux/pm_runtime.h>
#include <sound/hdaudio_ext.h>
#include <sound/pcm_params.h>
#include <sound/sof.h>
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index 2713b7dc7931..8e2b07e1612b 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -39,14 +39,18 @@ static int tgl_dsp_core_get(struct snd_sof_dev *sdev, int core)
static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core)
{
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
+ int ret;
+
+ if (pm_ops->set_core_state) {
+ ret = pm_ops->set_core_state(sdev, core, false);
+ if (ret < 0)
+ return ret;
+ }
/* power down primary core and return */
if (core == SOF_DSP_PRIMARY_CORE)
return hda_dsp_core_reset_power_down(sdev, BIT(core));
- if (pm_ops->set_core_state)
- return pm_ops->set_core_state(sdev, core, false);
-
return 0;
}
diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c
index ad040e7bb850..a8deec7dc021 100644
--- a/sound/soc/sof/ipc3-control.c
+++ b/sound/soc/sof/ipc3-control.c
@@ -96,6 +96,26 @@ static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol,
cdata->elems_remaining = 0;
ret = iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set);
+ if (!set)
+ goto unlock;
+
+ /* It is a set-data operation, and we have a backup that we can restore */
+ if (ret < 0) {
+ if (!scontrol->old_ipc_control_data)
+ goto unlock;
+ /*
+ * Current ipc_control_data is not valid, we use the last known good
+ * configuration
+ */
+ memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data,
+ scontrol->max_size);
+ kfree(scontrol->old_ipc_control_data);
+ scontrol->old_ipc_control_data = NULL;
+ /* Send the last known good configuration to firmware */
+ ret = iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set);
+ if (ret < 0)
+ goto unlock;
+ }
unlock:
if (lock)
@@ -351,6 +371,7 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_ctl_tlv header;
+ int ret = -EINVAL;
/*
* The beginning of bytes data contains a header from where
@@ -381,31 +402,52 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
return -EINVAL;
}
- if (copy_from_user(cdata->data, tlvd->tlv, header.length))
- return -EFAULT;
+ if (!scontrol->old_ipc_control_data) {
+ /* Create a backup of the current, valid bytes control */
+ scontrol->old_ipc_control_data = kmemdup(scontrol->ipc_control_data,
+ scontrol->max_size, GFP_KERNEL);
+ if (!scontrol->old_ipc_control_data)
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(cdata->data, tlvd->tlv, header.length)) {
+ ret = -EFAULT;
+ goto err_restore;
+ }
if (cdata->data->magic != SOF_ABI_MAGIC) {
dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n", cdata->data->magic);
- return -EINVAL;
+ goto err_restore;
}
if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
dev_err_ratelimited(scomp->dev, "Incompatible ABI version 0x%08x\n",
cdata->data->abi);
- return -EINVAL;
+ goto err_restore;
}
/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
dev_err_ratelimited(scomp->dev, "Mismatch in ABI data size (truncated?)\n");
- return -EINVAL;
+ goto err_restore;
}
/* notify DSP of byte control updates */
- if (pm_runtime_active(scomp->dev))
+ if (pm_runtime_active(scomp->dev)) {
+ /* Actually send the data to the DSP; this is an opportunity to validate the data */
return sof_ipc3_set_get_kcontrol_data(scontrol, true, true);
+ }
return 0;
+
+err_restore:
+ /* If we have an issue, we restore the old, valid bytes control data */
+ if (scontrol->old_ipc_control_data) {
+ memcpy(cdata->data, scontrol->old_ipc_control_data, scontrol->max_size);
+ kfree(scontrol->old_ipc_control_data);
+ scontrol->old_ipc_control_data = NULL;
+ }
+ return ret;
}
static int _sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol,
diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c
index 6f0698be9451..c6d404d44097 100644
--- a/sound/soc/sof/ipc4-control.c
+++ b/sound/soc/sof/ipc4-control.c
@@ -54,6 +54,26 @@ static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol,
msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
ret = iops->set_get_data(sdev, msg, msg->data_size, set);
+ if (!set)
+ goto unlock;
+
+ /* It is a set-data operation, and we have a valid backup that we can restore */
+ if (ret < 0) {
+ if (!scontrol->old_ipc_control_data)
+ goto unlock;
+ /*
+ * Current ipc_control_data is not valid, we use the last known good
+ * configuration
+ */
+ memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data,
+ scontrol->max_size);
+ kfree(scontrol->old_ipc_control_data);
+ scontrol->old_ipc_control_data = NULL;
+ /* Send the last known good configuration to firmware */
+ ret = iops->set_get_data(sdev, msg, msg->data_size, set);
+ if (ret < 0)
+ goto unlock;
+ }
unlock:
if (lock)
@@ -327,13 +347,24 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol,
return -EINVAL;
}
+ if (!scontrol->old_ipc_control_data) {
+ /* Create a backup of the current, valid bytes control */
+ scontrol->old_ipc_control_data = kmemdup(scontrol->ipc_control_data,
+ scontrol->max_size, GFP_KERNEL);
+ if (!scontrol->old_ipc_control_data)
+ return -ENOMEM;
+ }
+
/* Copy the whole binary data which includes the ABI header and the payload */
- if (copy_from_user(data, tlvd->tlv, header.length))
+ if (copy_from_user(data, tlvd->tlv, header.length)) {
+ memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data,
+ scontrol->max_size);
+ kfree(scontrol->old_ipc_control_data);
+ scontrol->old_ipc_control_data = NULL;
return -EFAULT;
+ }
- sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
-
- return 0;
+ return sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
}
static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c
index 1321acc402fd..eaa04762eb11 100644
--- a/sound/soc/sof/ipc4-loader.c
+++ b/sound/soc/sof/ipc4-loader.c
@@ -112,16 +112,13 @@ static ssize_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev,
return -EINVAL;
}
- /* a module's config is always the same size */
- fw_module->bss_size = fm_config[fm_entry->cfg_offset].is_bytes;
+ fw_module->fw_mod_cfg = &fm_config[fm_entry->cfg_offset];
dev_dbg(sdev->dev,
"module %s: UUID %pUL cfg_count: %u, bss_size: %#x\n",
fm_entry->name, &fm_entry->uuid, fm_entry->cfg_count,
- fw_module->bss_size);
+ fm_config[fm_entry->cfg_offset].is_bytes);
} else {
- fw_module->bss_size = 0;
-
dev_dbg(sdev->dev, "module %s: UUID %pUL\n", fm_entry->name,
&fm_entry->uuid);
}
@@ -426,6 +423,71 @@ int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev)
return ret;
}
+/**
+ * sof_ipc4_update_cpc_from_manifest - Update the cpc in base config from manifest
+ * @sdev: SOF device
+ * @fw_module: pointer struct sof_ipc4_fw_module to parse
+ * @basecfg: Pointer to the base_config to update
+ */
+void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev,
+ struct sof_ipc4_fw_module *fw_module,
+ struct sof_ipc4_base_module_cfg *basecfg)
+{
+ const struct sof_man4_module_config *fw_mod_cfg;
+ u32 cpc_pick = 0;
+ u32 max_cpc = 0;
+ const char *msg;
+ int i;
+
+ if (!fw_module->fw_mod_cfg) {
+ msg = "No mod_cfg available for CPC lookup in the firmware file's manifest";
+ goto no_cpc;
+ }
+
+ /*
+ * Find the best matching (highest) CPC value based on the module's
+ * IBS/OBS configuration inferred from the audio format selection.
+ *
+ * The CPC value in each module config entry has been measured and
+ * recorded as a IBS/OBS/CPC triplet and stored in the firmware file's
+ * manifest
+ */
+ fw_mod_cfg = fw_module->fw_mod_cfg;
+ for (i = 0; i < fw_module->man4_module_entry.cfg_count; i++) {
+ if (basecfg->obs == fw_mod_cfg[i].obs &&
+ basecfg->ibs == fw_mod_cfg[i].ibs &&
+ cpc_pick < fw_mod_cfg[i].cpc)
+ cpc_pick = fw_mod_cfg[i].cpc;
+
+ if (max_cpc < fw_mod_cfg[i].cpc)
+ max_cpc = fw_mod_cfg[i].cpc;
+ }
+
+ basecfg->cpc = cpc_pick;
+
+ /* We have a matching configuration for CPC */
+ if (basecfg->cpc)
+ return;
+
+ /*
+ * No matching IBS/OBS found, the firmware manifest is missing
+ * information in the module's module configuration table.
+ */
+ if (!max_cpc)
+ msg = "No CPC value available in the firmware file's manifest";
+ else if (!cpc_pick)
+ msg = "No CPC match in the firmware file's manifest";
+
+no_cpc:
+ dev_warn(sdev->dev, "%s (UUID: %pUL): %s (ibs/obs: %u/%u)\n",
+ fw_module->man4_module_entry.name,
+ &fw_module->man4_module_entry.uuid, msg, basecfg->ibs,
+ basecfg->obs);
+ dev_warn_once(sdev->dev, "Please try to update the firmware.\n");
+ dev_warn_once(sdev->dev, "If the issue persists, file a bug at\n");
+ dev_warn_once(sdev->dev, "https://github.com/thesofproject/sof/issues/\n");
+}
+
const struct sof_ipc_fw_loader_ops ipc4_loader_ops = {
.validate = sof_ipc4_validate_firmware,
.parse_ext_manifest = sof_ipc4_fw_parse_basefw_ext_man,
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index 9e2b6c45080d..0c905bd0fab4 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -69,7 +69,7 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state,
struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
- if (pipeline->skip_during_fe_trigger)
+ if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET)
return;
switch (state) {
@@ -108,7 +108,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
int i;
- if (pipeline->skip_during_fe_trigger)
+ if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET)
return;
/* set state for pipeline if it was just triggered */
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index f461b8c70df3..a5d0b2eae464 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -28,14 +28,14 @@ enum sof_ipc4_mtrace_type {
/**
* struct sof_ipc4_fw_module - IPC4 module info
* @sof_man4_module: Module info
+ * @fw_mod_cfg: Pointer to the module config start of the module
* @m_ida: Module instance identifier
- * @bss_size: Module object size
* @private: Module private data
*/
struct sof_ipc4_fw_module {
struct sof_man4_module man4_module_entry;
+ const struct sof_man4_module_config *fw_mod_cfg;
struct ida m_ida;
- u32 bss_size;
void *private;
};
@@ -114,4 +114,10 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev);
int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev);
struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
const guid_t *uuid);
+
+struct sof_ipc4_base_module_cfg;
+void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev,
+ struct sof_ipc4_fw_module *fw_module,
+ struct sof_ipc4_base_module_cfg *basecfg);
+
#endif
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 5abe616a2054..db64e0cb8663 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -39,8 +39,6 @@ static const struct sof_topology_token pipeline_tokens[] = {
};
static const struct sof_topology_token ipc4_comp_tokens[] = {
- {SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_base_module_cfg, cpc)},
{SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_base_module_cfg, is_pages)},
};
@@ -235,7 +233,7 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
"Number of input audio formats: %d. Number of output audio formats: %d\n",
available_fmt->num_input_formats, available_fmt->num_output_formats);
- /* set cpc and is_pages in the module's base_config */
+ /* set is_pages in the module's base_config */
ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*module_base_cfg), 1);
if (ret) {
@@ -244,8 +242,8 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
return ret;
}
- dev_dbg(scomp->dev, "widget %s cpc: %d is_pages: %d\n",
- swidget->widget->name, module_base_cfg->cpc, module_base_cfg->is_pages);
+ dev_dbg(scomp->dev, "widget %s: is_pages: %d\n", swidget->widget->name,
+ module_base_cfg->is_pages);
if (available_fmt->num_input_formats) {
in_format = kcalloc(available_fmt->num_input_formats,
@@ -723,9 +721,9 @@ static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
}
dev_dbg(scomp->dev,
- "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n",
+ "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x\n",
swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l,
- gain->data.init_val, gain->base_config.cpc);
+ gain->data.init_val);
ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
if (ret)
@@ -936,8 +934,8 @@ static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget)
}
static void
-sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
- struct sof_ipc4_base_module_cfg *base_config)
+sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+ struct sof_ipc4_base_module_cfg *base_config)
{
struct sof_ipc4_fw_module *fw_module = swidget->module_info;
struct snd_sof_widget *pipe_widget;
@@ -968,6 +966,13 @@ sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widg
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
pipeline->mem_usage += total;
+
+ /* Update base_config->cpc from the module manifest */
+ sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config);
+
+ dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n",
+ swidget->widget->name, base_config->ibs, base_config->obs,
+ base_config->cpc);
}
static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
@@ -1028,47 +1033,125 @@ static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw
return 0;
}
-static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
- struct snd_sof_widget *swidget,
- struct sof_ipc4_base_module_cfg *base_config,
- struct snd_pcm_hw_params *params,
- struct sof_ipc4_available_audio_format *available_fmt,
- struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size)
+static bool sof_ipc4_is_single_format(struct snd_sof_dev *sdev,
+ struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size)
{
- u32 valid_bits;
- u32 channels;
- u32 rate;
- int sample_valid_bits;
+ struct sof_ipc4_audio_format *fmt;
+ u32 rate, channels, valid_bits;
+ int i;
+
+ fmt = &pin_fmts[0].audio_fmt;
+ rate = fmt->sampling_frequency;
+ channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
+ valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+
+ /* check if all output formats in topology are the same */
+ for (i = 1; i < pin_fmts_size; i++) {
+ u32 _rate, _channels, _valid_bits;
+
+ fmt = &pin_fmts[i].audio_fmt;
+ _rate = fmt->sampling_frequency;
+ _channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
+ _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+
+ if (_rate != rate || _channels != channels || _valid_bits != valid_bits)
+ return false;
+ }
+
+ return true;
+}
+
+static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev,
+ struct sof_ipc4_base_module_cfg *base_config,
+ struct sof_ipc4_available_audio_format *available_fmt,
+ u32 out_ref_rate, u32 out_ref_channels,
+ u32 out_ref_valid_bits)
+{
+ struct sof_ipc4_audio_format *out_fmt;
+ bool single_format;
int i;
- if (!pin_fmts) {
- dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name);
+ if (!available_fmt->num_output_formats)
return -EINVAL;
+
+ single_format = sof_ipc4_is_single_format(sdev, available_fmt->output_pin_fmts,
+ available_fmt->num_output_formats);
+
+ /* pick the first format if there's only one available or if all formats are the same */
+ if (single_format) {
+ base_config->obs = available_fmt->output_pin_fmts[0].buffer_size;
+ return 0;
+ }
+
+ /*
+ * if there are multiple output formats, then choose the output format that matches
+ * the reference params
+ */
+ for (i = 0; i < available_fmt->num_output_formats; i++) {
+ u32 _out_rate, _out_channels, _out_valid_bits;
+
+ out_fmt = &available_fmt->output_pin_fmts[i].audio_fmt;
+ _out_rate = out_fmt->sampling_frequency;
+ _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg);
+ _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
+
+ if (_out_rate == out_ref_rate && _out_channels == out_ref_channels &&
+ _out_valid_bits == out_ref_valid_bits) {
+ base_config->obs = available_fmt->output_pin_fmts[i].buffer_size;
+ return i;
+ }
}
+ return -EINVAL;
+}
+
+static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params)
+{
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- sample_valid_bits = 16;
- break;
+ return 16;
case SNDRV_PCM_FORMAT_S24_LE:
- sample_valid_bits = 24;
- break;
+ return 24;
case SNDRV_PCM_FORMAT_S32_LE:
- sample_valid_bits = 32;
- break;
+ return 32;
default:
dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
return -EINVAL;
}
+}
+
+static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
+ struct sof_ipc4_base_module_cfg *base_config,
+ struct snd_pcm_hw_params *params,
+ struct sof_ipc4_available_audio_format *available_fmt)
+{
+ struct sof_ipc4_pin_format *pin_fmts = available_fmt->input_pin_fmts;
+ u32 pin_fmts_size = available_fmt->num_input_formats;
+ u32 valid_bits;
+ u32 channels;
+ u32 rate;
+ bool single_format;
+ int sample_valid_bits;
+ int i = 0;
- if (!pin_fmts_size) {
- dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name);
+ if (!available_fmt->num_input_formats) {
+ dev_err(sdev->dev, "no input formats for %s\n", swidget->widget->name);
return -EINVAL;
}
+ single_format = sof_ipc4_is_single_format(sdev, available_fmt->input_pin_fmts,
+ available_fmt->num_input_formats);
+ if (single_format)
+ goto in_fmt;
+
+ sample_valid_bits = sof_ipc4_get_valid_bits(sdev, params);
+ if (sample_valid_bits < 0)
+ return sample_valid_bits;
+
/*
- * Search supported audio formats with pin index 0 to match rate, channels ,and
- * sample_valid_bytes from runtime params
+ * Search supported input audio formats with pin index 0 to match rate, channels and
+ * sample_valid_bits from reference params
*/
for (i = 0; i < pin_fmts_size; i++) {
struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt;
@@ -1093,6 +1176,7 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
return -EINVAL;
}
+in_fmt:
/* copy input format */
if (available_fmt->num_input_formats && i < available_fmt->num_input_formats) {
memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt,
@@ -1105,10 +1189,6 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1);
}
- if (available_fmt->num_output_formats && i < available_fmt->num_output_formats)
- base_config->obs = available_fmt->output_pin_fmts[i].buffer_size;
-
- /* Return the index of the matched format */
return i;
}
@@ -1288,50 +1368,6 @@ static int ipc4_set_fmt_mask(struct snd_mask *fmt, unsigned int bit_depth)
return 0;
}
-static int ipc4_copier_set_capture_fmt(struct snd_sof_dev *sdev,
- struct snd_pcm_hw_params *pipeline_params,
- struct snd_pcm_hw_params *fe_params,
- struct sof_ipc4_available_audio_format *available_fmt)
-{
- struct sof_ipc4_audio_format *audio_fmt;
- unsigned int sample_valid_bits;
- bool multiple_formats = false;
- bool fe_format_match = false;
- struct snd_mask *fmt;
- int i;
-
- for (i = 0; i < available_fmt->num_output_formats; i++) {
- unsigned int val;
-
- audio_fmt = &available_fmt->output_pin_fmts[i].audio_fmt;
- val = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(audio_fmt->fmt_cfg);
-
- if (i == 0)
- sample_valid_bits = val;
- else if (sample_valid_bits != val)
- multiple_formats = true;
-
- if (snd_pcm_format_width(params_format(fe_params)) == val)
- fe_format_match = true;
- }
-
- fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
- snd_mask_none(fmt);
-
- if (multiple_formats) {
- if (fe_format_match) {
- /* multiple formats defined and one matches FE */
- snd_mask_set_format(fmt, params_format(fe_params));
- return 0;
- }
-
- dev_err(sdev->dev, "Multiple audio formats for single dai_out not supported\n");
- return -EINVAL;
- }
-
- return ipc4_set_fmt_mask(fmt, sample_valid_bits);
-}
-
static int
sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct snd_pcm_hw_params *fe_params,
@@ -1341,7 +1377,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct sof_ipc4_available_audio_format *available_fmt;
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct sof_ipc4_pin_format *format_list_to_search;
struct sof_ipc4_copier_data *copier_data;
struct snd_pcm_hw_params *ref_params;
struct sof_ipc4_copier *ipc4_copier;
@@ -1351,9 +1386,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
void **ipc_config_data;
int *ipc_config_size;
u32 **data;
- int ipc_size, ret;
+ int ipc_size, ret, out_ref_valid_bits;
+ u32 out_ref_rate, out_ref_channels;
u32 deep_buffer_dma_ms = 0;
- u32 format_list_count;
+ int output_fmt_index;
dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
@@ -1417,13 +1453,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
* Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts
* for capture.
*/
- if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
- format_list_to_search = available_fmt->input_pin_fmts;
- format_list_count = available_fmt->num_input_formats;
- } else {
- format_list_to_search = available_fmt->output_pin_fmts;
- format_list_count = available_fmt->num_output_formats;
- }
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+ ref_params = fe_params;
+ else
+ ref_params = pipeline_params;
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
copier_data->gtw_cfg.node_id |=
@@ -1431,7 +1464,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
/* set gateway attributes */
gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
- ref_params = fe_params;
break;
}
case snd_soc_dapm_dai_in:
@@ -1448,20 +1480,17 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
ipc4_copier = (struct sof_ipc4_copier *)dai->private;
copier_data = &ipc4_copier->data;
available_fmt = &ipc4_copier->available_fmt;
- if (dir == SNDRV_PCM_STREAM_CAPTURE) {
- format_list_to_search = available_fmt->output_pin_fmts;
- format_list_count = available_fmt->num_output_formats;
-
- ret = ipc4_copier_set_capture_fmt(sdev, pipeline_params, fe_params,
- available_fmt);
- if (ret < 0)
- return ret;
- } else {
- format_list_to_search = available_fmt->input_pin_fmts;
- format_list_count = available_fmt->num_input_formats;
- }
- ref_params = pipeline_params;
+ /*
+ * When there is format conversion within a pipeline, the number of supported
+ * output formats is typically limited to just 1 for the DAI copiers. But when there
+ * is no format conversion, the DAI copiers input format must match that of the
+ * FE hw_params for capture and the pipeline params for playback.
+ */
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+ ref_params = pipeline_params;
+ else
+ ref_params = fe_params;
ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index,
ipc4_copier->dai_type, dir,
@@ -1477,10 +1506,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
copier_data = &ipc4_copier->data;
available_fmt = &ipc4_copier->available_fmt;
-
- /* Use the input formats to match pcm params */
- format_list_to_search = available_fmt->input_pin_fmts;
- format_list_count = available_fmt->num_input_formats;
ref_params = pipeline_params;
break;
@@ -1492,11 +1517,51 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
}
/* set input and output audio formats */
- ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params,
- available_fmt, format_list_to_search, format_list_count);
+ ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params,
+ available_fmt);
if (ret < 0)
return ret;
+ /* set the reference params for output format selection */
+ switch (swidget->id) {
+ case snd_soc_dapm_aif_in:
+ case snd_soc_dapm_dai_out:
+ case snd_soc_dapm_buffer:
+ {
+ struct sof_ipc4_audio_format *in_fmt;
+
+ in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
+ out_ref_rate = in_fmt->sampling_frequency;
+ out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
+ out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+ break;
+ }
+ case snd_soc_dapm_aif_out:
+ case snd_soc_dapm_dai_in:
+ out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
+ if (out_ref_valid_bits < 0)
+ return out_ref_valid_bits;
+
+ out_ref_rate = params_rate(fe_params);
+ out_ref_channels = params_channels(fe_params);
+ break;
+ default:
+ /*
+ * Unsupported type should be caught by the former switch default
+ * case, this should never happen in reality.
+ */
+ return -EINVAL;
+ }
+
+ output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config,
+ available_fmt, out_ref_rate,
+ out_ref_channels, out_ref_valid_bits);
+ if (output_fmt_index < 0) {
+ dev_err(sdev->dev, "Failed to initialize output format for %s",
+ swidget->widget->name);
+ return output_fmt_index;
+ }
+
/*
* Set the output format. Current topology defines pin 0 input and output formats in pairs.
* This assumes that the pin 0 formats are defined before all other pins.
@@ -1504,10 +1569,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
* input format. This logic will need to be updated when the format definitions
* in topology change.
*/
- memcpy(&copier_data->out_format, &available_fmt->output_pin_fmts[ret].audio_fmt,
+ memcpy(&copier_data->out_format,
+ &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt,
sizeof(struct sof_ipc4_audio_format));
dev_dbg(sdev->dev, "Output audio format for %s\n", swidget->widget->name);
- sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[ret], 1);
+ sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[output_fmt_index], 1);
switch (swidget->id) {
case snd_soc_dapm_dai_in:
@@ -1515,7 +1581,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
{
/*
* Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
- * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt
+ * That's why only ALH dai's blob is set after sof_ipc4_init_input_audio_fmt
*/
if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
struct sof_ipc4_alh_configuration_blob *blob;
@@ -1650,7 +1716,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
*data, copier_data->gtw_cfg.config_length * 4);
/* update pipeline memory usage */
- sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
+ sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
return 0;
}
@@ -1664,17 +1730,30 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_gain *gain = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt;
+ struct sof_ipc4_audio_format *in_fmt;
+ u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
int ret;
- ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config,
- pipeline_params, available_fmt,
- available_fmt->input_pin_fmts,
- available_fmt->num_input_formats);
+ ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &gain->base_config,
+ pipeline_params, available_fmt);
if (ret < 0)
return ret;
+ in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
+ out_ref_rate = in_fmt->sampling_frequency;
+ out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
+ out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+
+ ret = sof_ipc4_init_output_audio_fmt(sdev, &gain->base_config, available_fmt,
+ out_ref_rate, out_ref_channels, out_ref_valid_bits);
+ if (ret < 0) {
+ dev_err(sdev->dev, "Failed to initialize output format for %s",
+ swidget->widget->name);
+ return ret;
+ }
+
/* update pipeline memory usage */
- sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
+ sof_ipc4_update_resource_usage(sdev, swidget, &gain->base_config);
return 0;
}
@@ -1688,17 +1767,30 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_mixer *mixer = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt;
+ struct sof_ipc4_audio_format *in_fmt;
+ u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
int ret;
- ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config,
- pipeline_params, available_fmt,
- available_fmt->input_pin_fmts,
- available_fmt->num_input_formats);
+ ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &mixer->base_config,
+ pipeline_params, available_fmt);
if (ret < 0)
return ret;
+ in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
+ out_ref_rate = in_fmt->sampling_frequency;
+ out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
+ out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+
+ ret = sof_ipc4_init_output_audio_fmt(sdev, &mixer->base_config, available_fmt,
+ out_ref_rate, out_ref_channels, out_ref_valid_bits);
+ if (ret < 0) {
+ dev_err(sdev->dev, "Failed to initialize output format for %s",
+ swidget->widget->name);
+ return ret;
+ }
+
/* update pipeline memory usage */
- sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
+ sof_ipc4_update_resource_usage(sdev, swidget, &mixer->base_config);
return 0;
}
@@ -1712,18 +1804,30 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_src *src = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt;
+ struct sof_ipc4_audio_format *in_fmt;
+ u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
struct snd_interval *rate;
int ret;
- ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config,
- pipeline_params, available_fmt,
- available_fmt->input_pin_fmts,
- available_fmt->num_input_formats);
+ ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config,
+ pipeline_params, available_fmt);
if (ret < 0)
return ret;
+ in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
+ out_ref_rate = in_fmt->sampling_frequency;
+ out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
+ out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+
+ ret = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, available_fmt,
+ out_ref_rate, out_ref_channels, out_ref_valid_bits);
+ if (ret < 0) {
+ dev_err(sdev->dev, "Failed to initialize output format for %s",
+ swidget->widget->name);
+ }
+
/* update pipeline memory usage */
- sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config);
+ sof_ipc4_update_resource_usage(sdev, swidget, &src->base_config);
/* update pipeline_params for sink widgets */
rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE);
@@ -1820,20 +1924,37 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_process *process = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
+ struct sof_ipc4_audio_format *in_fmt;
+ u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
void *cfg = process->ipc_config_data;
+ int output_fmt_index;
int ret;
- ret = sof_ipc4_init_audio_fmt(sdev, swidget, &process->base_config,
- pipeline_params, available_fmt,
- available_fmt->input_pin_fmts,
- available_fmt->num_input_formats);
+ ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &process->base_config,
+ pipeline_params, available_fmt);
if (ret < 0)
return ret;
+ in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
+ out_ref_rate = in_fmt->sampling_frequency;
+ out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
+ out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+
+ output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &process->base_config,
+ available_fmt, out_ref_rate,
+ out_ref_channels, out_ref_valid_bits);
+ if (output_fmt_index < 0 && available_fmt->num_output_formats) {
+ dev_err(sdev->dev, "Failed to initialize output format for %s",
+ swidget->widget->name);
+ return output_fmt_index;
+ }
+
/* copy Pin 0 output format */
- if (available_fmt->num_output_formats && ret < available_fmt->num_output_formats &&
- !available_fmt->output_pin_fmts[ret].pin_index) {
- memcpy(&process->output_format, &available_fmt->output_pin_fmts[ret].audio_fmt,
+ if (available_fmt->num_output_formats &&
+ output_fmt_index < available_fmt->num_output_formats &&
+ !available_fmt->output_pin_fmts[output_fmt_index].pin_index) {
+ memcpy(&process->output_format,
+ &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt,
sizeof(struct sof_ipc4_audio_format));
/* modify the pipeline params with the pin 0 output format */
@@ -1843,7 +1964,7 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
}
/* update pipeline memory usage */
- sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &process->base_config);
+ sof_ipc4_update_resource_usage(sdev, swidget, &process->base_config);
/* ipc_config_data is composed of the base_config followed by an optional extension */
memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg));
@@ -2271,11 +2392,11 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
int sink_id)
{
struct sof_ipc4_copier_config_set_sink_format format;
+ const struct sof_ipc_ops *iops = sdev->ipc->ops;
struct sof_ipc4_base_module_cfg *src_config;
const struct sof_ipc4_audio_format *pin_fmt;
struct sof_ipc4_fw_module *fw_module;
struct sof_ipc4_msg msg = {{ 0 }};
- u32 header, extension;
dev_dbg(sdev->dev, "%s set copier sink %d format\n",
src_widget->widget->name, sink_id);
@@ -2305,22 +2426,15 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
msg.data_size = sizeof(format);
msg.data_ptr = &format;
- header = fw_module->man4_module_entry.id;
- header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
- header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
- header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
- header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+ msg.primary = fw_module->man4_module_entry.id;
+ msg.primary |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
- extension = SOF_IPC4_MOD_EXT_MSG_SIZE(msg.data_size);
- extension |=
+ msg.extension =
SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT);
- extension |= SOF_IPC4_MOD_EXT_MSG_LAST_BLOCK(1);
- extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1);
-
- msg.primary = header;
- msg.extension = extension;
- return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, msg.data_size);
+ return iops->set_get_data(sdev, &msg, msg.data_size, true);
}
static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
@@ -2507,7 +2621,6 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
}
gtw_attr = ipc4_copier->gtw_attr;
gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
- pipeline->skip_during_fe_trigger = true;
fallthrough;
case SOF_DAI_INTEL_ALH:
/*
diff --git a/sound/soc/sof/mediatek/mt8186/mt8186-clk.c b/sound/soc/sof/mediatek/mt8186/mt8186-clk.c
index 2df3b7ae1c6f..cb2ab5884b8c 100644
--- a/sound/soc/sof/mediatek/mt8186/mt8186-clk.c
+++ b/sound/soc/sof/mediatek/mt8186/mt8186-clk.c
@@ -8,7 +8,6 @@
// Hardware interface for mt8186 DSP clock
#include <linux/clk.h>
-#include <linux/pm_runtime.h>
#include <linux/io.h>
#include "../../sof-audio.h"
diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c
index 597cb4476acb..cc91c2928fb6 100644
--- a/sound/soc/sof/mediatek/mt8186/mt8186.c
+++ b/sound/soc/sof/mediatek/mt8186/mt8186.c
@@ -48,47 +48,13 @@ static int mt8186_send_msg(struct snd_sof_dev *sdev,
return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ);
}
-static void mt8186_get_reply(struct snd_sof_dev *sdev)
-{
- struct snd_sof_ipc_msg *msg = sdev->msg;
- struct sof_ipc_reply reply;
- int ret = 0;
-
- if (!msg) {
- dev_warn(sdev->dev, "unexpected ipc interrupt\n");
- return;
- }
-
- /* get reply */
- sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
- if (reply.error < 0) {
- memcpy(msg->reply_data, &reply, sizeof(reply));
- ret = reply.error;
- } else {
- /* reply has correct size? */
- if (reply.hdr.size != msg->reply_size) {
- dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n",
- msg->reply_size, reply.hdr.size);
- ret = -EINVAL;
- }
-
- /* read the message */
- if (msg->reply_size > 0)
- sof_mailbox_read(sdev, sdev->host_box.offset,
- msg->reply_data, msg->reply_size);
- }
-
- msg->reply_error = ret;
-}
-
static void mt8186_dsp_handle_reply(struct mtk_adsp_ipc *ipc)
{
struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
unsigned long flags;
spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
- mt8186_get_reply(priv->sdev);
- snd_sof_ipc_reply(priv->sdev, 0);
+ snd_sof_ipc_process_reply(priv->sdev, 0);
spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
}
@@ -628,7 +594,65 @@ static const struct sof_dev_desc sof_of_mt8186_desc = {
.ops = &sof_mt8186_ops,
};
+/*
+ * DL2, DL3, UL4, UL5 are registered as SOF FE, so creating the corresponding
+ * SOF BE to complete the pipeline.
+ */
+static struct snd_soc_dai_driver mt8188_dai[] = {
+{
+ .name = "SOF_DL2",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+},
+{
+ .name = "SOF_DL3",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+},
+{
+ .name = "SOF_UL4",
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+},
+{
+ .name = "SOF_UL5",
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+},
+};
+
+/* mt8188 ops */
+static struct snd_sof_dsp_ops sof_mt8188_ops;
+
+static int sof_mt8188_ops_init(struct snd_sof_dev *sdev)
+{
+ /* common defaults */
+ memcpy(&sof_mt8188_ops, &sof_mt8186_ops, sizeof(sof_mt8188_ops));
+
+ sof_mt8188_ops.drv = mt8188_dai;
+ sof_mt8188_ops.num_drv = ARRAY_SIZE(mt8188_dai);
+
+ return 0;
+}
+
+static struct snd_sof_of_mach sof_mt8188_machs[] = {
+ {
+ .compatible = "mediatek,mt8188",
+ .sof_tplg_filename = "sof-mt8188.tplg",
+ },
+ {}
+};
+
static const struct sof_dev_desc sof_of_mt8188_desc = {
+ .of_machines = sof_mt8188_machs,
.ipc_supported_mask = BIT(SOF_IPC),
.ipc_default = SOF_IPC,
.default_fw_path = {
@@ -641,7 +665,8 @@ static const struct sof_dev_desc sof_of_mt8188_desc = {
[SOF_IPC] = "sof-mt8188.ri",
},
.nocodec_tplg_filename = "sof-mt8188-nocodec.tplg",
- .ops = &sof_mt8186_ops,
+ .ops = &sof_mt8188_ops,
+ .ops_init = sof_mt8188_ops_init,
};
static const struct of_device_id sof_of_mt8186_ids[] = {
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c
index 9ef08e43aa38..7cffcad00f9b 100644
--- a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c
+++ b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c
@@ -7,7 +7,6 @@
// Hardware interface for mt8195 DSP clock
#include <linux/clk.h>
-#include <linux/pm_runtime.h>
#include <linux/io.h>
#include "mt8195.h"
#include "mt8195-clk.h"
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c
index 42bae574c87a..7d6a568556ea 100644
--- a/sound/soc/sof/mediatek/mt8195/mt8195.c
+++ b/sound/soc/sof/mediatek/mt8195/mt8195.c
@@ -49,47 +49,13 @@ static int mt8195_send_msg(struct snd_sof_dev *sdev,
return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ);
}
-static void mt8195_get_reply(struct snd_sof_dev *sdev)
-{
- struct snd_sof_ipc_msg *msg = sdev->msg;
- struct sof_ipc_reply reply;
- int ret = 0;
-
- if (!msg) {
- dev_warn(sdev->dev, "unexpected ipc interrupt\n");
- return;
- }
-
- /* get reply */
- sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
- if (reply.error < 0) {
- memcpy(msg->reply_data, &reply, sizeof(reply));
- ret = reply.error;
- } else {
- /* reply has correct size? */
- if (reply.hdr.size != msg->reply_size) {
- dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n",
- msg->reply_size, reply.hdr.size);
- ret = -EINVAL;
- }
-
- /* read the message */
- if (msg->reply_size > 0)
- sof_mailbox_read(sdev, sdev->host_box.offset,
- msg->reply_data, msg->reply_size);
- }
-
- msg->reply_error = ret;
-}
-
static void mt8195_dsp_handle_reply(struct mtk_adsp_ipc *ipc)
{
struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
unsigned long flags;
spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
- mt8195_get_reply(priv->sdev);
- snd_sof_ipc_reply(priv->sdev, 0);
+ snd_sof_ipc_process_reply(priv->sdev, 0);
spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
}
diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c
index b13bfdeb2b70..7c5bb9badb6c 100644
--- a/sound/soc/sof/nocodec.c
+++ b/sound/soc/sof/nocodec.c
@@ -32,7 +32,7 @@ static int sof_nocodec_bes_setup(struct device *dev,
/* set up BE dai_links */
for (i = 0; i < link_num; i++) {
- dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL);
+ dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL);
if (!dlc)
return -ENOMEM;
@@ -44,8 +44,8 @@ static int sof_nocodec_bes_setup(struct device *dev,
links[i].stream_name = links[i].name;
links[i].cpus = &dlc[0];
- links[i].codecs = &dlc[1];
- links[i].platforms = &dlc[2];
+ links[i].codecs = &asoc_dummy_dlc;
+ links[i].platforms = &dlc[1];
links[i].num_cpus = 1;
links[i].num_codecs = 1;
@@ -55,8 +55,6 @@ static int sof_nocodec_bes_setup(struct device *dev,
links[i].no_pcm = 1;
links[i].cpus->dai_name = drv[i].name;
links[i].platforms->name = dev_name(dev->parent);
- links[i].codecs->dai_name = "snd-soc-dummy-dai";
- links[i].codecs->name = "snd-soc-dummy";
if (drv[i].playback.channels_min)
links[i].dpcm_playback = 1;
if (drv[i].capture.channels_min)
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index d0ab6f390734..d778717cab10 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -369,7 +369,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
/* invoke platform trigger to stop DMA even if pcm_ops isn't set or if it failed */
- if (!pcm_ops || (pcm_ops && !pcm_ops->platform_stop_during_hw_free))
+ if (!pcm_ops || !pcm_ops->platform_stop_during_hw_free)
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
break;
default:
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index a090a9eb4828..5d5eeb1a1a6f 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -362,6 +362,7 @@ struct snd_sof_control {
size_t priv_size; /* size of private data */
size_t max_size;
void *ipc_control_data;
+ void *old_ipc_control_data;
int max; /* applicable to volume controls */
u32 size; /* cdata size */
u32 *volume_table; /* volume table computed from tlv data*/
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index f160dc454b44..698129dccc7d 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1077,7 +1077,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp,
list_for_each_entry(rtd, &card->rtd_list, list) {
/* does stream match DAI link ? */
if (!rtd->dai_link->stream_name ||
- strcmp(w->sname, rtd->dai_link->stream_name))
+ !strstr(rtd->dai_link->stream_name, w->sname))
continue;
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {