summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/ak4118.c11
-rw-r--r--sound/soc/codecs/wm_adsp.c20
-rw-r--r--sound/soc/intel/boards/sof_nau8825.c10
-rw-r--r--sound/soc/intel/boards/sof_sdw.c49
-rw-r--r--sound/soc/intel/common/Makefile1
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-lnl-match.c72
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c57
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-rpl-match.c12
-rw-r--r--sound/soc/soc-component.c22
-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.c73
-rw-r--r--sound/soc/sof/intel/hda-dai.c104
-rw-r--r--sound/soc/sof/intel/hda.h2
-rw-r--r--sound/soc/sof/ipc4-pcm.c4
-rw-r--r--sound/soc/sof/ipc4-topology.c22
-rw-r--r--sound/soc/sof/pcm.c2
17 files changed, 344 insertions, 131 deletions
diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c
index ebcdc412e39c..e34e5533765c 100644
--- a/sound/soc/codecs/ak4118.c
+++ b/sound/soc/codecs/ak4118.c
@@ -264,8 +264,6 @@ static irqreturn_t ak4118_irq_handler(int irq, void *data)
struct ak4118_priv *ak4118 = data;
struct snd_soc_component *component = ak4118->component;
struct snd_kcontrol_new *kctl_new;
- struct snd_kcontrol *kctl;
- struct snd_ctl_elem_id *id;
unsigned int i;
if (!component)
@@ -273,13 +271,8 @@ static irqreturn_t ak4118_irq_handler(int irq, void *data)
for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) {
kctl_new = &ak4118_iec958_controls[i];
- kctl = snd_soc_card_get_kcontrol(component->card,
- kctl_new->name);
- if (!kctl)
- continue;
- id = &kctl->id;
- snd_ctl_notify(component->card->snd_card,
- SNDRV_CTL_EVENT_MASK_VALUE, id);
+
+ snd_soc_component_notify_control(component, kctl_new->name);
}
return IRQ_HANDLED;
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 216120b68b64..6270cb2e9395 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -686,8 +686,6 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
{
struct cs_dsp_coeff_ctl *cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
struct wm_coeff_ctl *ctl;
- struct snd_kcontrol *kcontrol;
- char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
int ret;
ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
@@ -699,23 +697,7 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
ctl = cs_ctl->priv;
- if (dsp->component->name_prefix)
- snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s",
- dsp->component->name_prefix, ctl->name);
- else
- snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s",
- ctl->name);
-
- kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl_name);
- if (!kcontrol) {
- adsp_err(dsp, "Can't find kcontrol %s\n", ctl_name);
- return -EINVAL;
- }
-
- snd_ctl_notify(dsp->component->card->snd_card,
- SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id);
-
- return 0;
+ return snd_soc_component_notify_control(dsp->component, ctl->name);
}
EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c
index 30e798431e1f..4fc6e1c6aef3 100644
--- a/sound/soc/intel/boards/sof_nau8825.c
+++ b/sound/soc/intel/boards/sof_nau8825.c
@@ -674,6 +674,16 @@ static const struct platform_device_id board_ids[] = {
SOF_BT_OFFLOAD_SSP(2) |
SOF_SSP_BT_OFFLOAD_PRESENT),
},
+ {
+ .name = "rpl_max98373_8825",
+ .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
+ SOF_SPEAKER_AMP_PRESENT |
+ SOF_MAX98373_SPEAKER_AMP_PRESENT |
+ SOF_NAU8825_SSP_AMP(1) |
+ SOF_NAU8825_NUM_HDMIDEV(4) |
+ SOF_BT_OFFLOAD_SSP(2) |
+ SOF_SSP_BT_OFFLOAD_PRESENT),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index c845a5cf7f4d..d16ceef702a7 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -192,6 +192,20 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
RT711_JD1),
},
{
+ /*
+ * this entry covers HP Spectre x360 where the DMI information
+ * changed somehow
+ */
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+ DMI_MATCH(DMI_BOARD_NAME, "8709"),
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ SOF_SDW_PCH_DMIC |
+ RT711_JD1),
+ },
+ {
/* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */
.callback = sof_sdw_quirk_cb,
.matches = {
@@ -413,7 +427,24 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
.matches = {
DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
},
- .driver_data = (void *)(RT711_JD1 | SOF_SDW_TGL_HDMI),
+ .driver_data = (void *)(RT711_JD1),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Meteor Lake Client Platform"),
+ },
+ .driver_data = (void *)(RT711_JD2_100K),
+ },
+ /* LunarLake devices */
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"),
+ },
+ .driver_data = (void *)(RT711_JD2_100K),
},
{}
};
@@ -902,17 +933,20 @@ static int create_codec_dai_name(struct device *dev,
static int set_codec_init_func(struct snd_soc_card *card,
const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
- bool playback, int group_id)
+ bool playback, int group_id, int adr_index)
{
- int i;
+ int i = adr_index;
do {
/*
* Initialize the codec. If codec is part of an aggregated
* group (group_id>0), initialize all codecs belonging to
* same group.
+ * The first link should start with link->adr_d[adr_index]
+ * because that is the device that we want to initialize and
+ * we should end immediately if it is not aggregated (group_id=0)
*/
- for (i = 0; i < link->num_adr; i++) {
+ for ( ; i < link->num_adr; i++) {
int codec_index;
codec_index = find_codec_info_part(link->adr_d[i].adr);
@@ -928,9 +962,12 @@ static int set_codec_init_func(struct snd_soc_card *card,
dai_links,
&codec_info_list[codec_index],
playback);
+ if (!group_id)
+ return 0;
}
+ i = 0;
link++;
- } while (link->mask && group_id);
+ } while (link->mask);
return 0;
}
@@ -1180,7 +1217,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
dai_links[*link_index].nonatomic = true;
ret = set_codec_init_func(card, link, dai_links + (*link_index)++,
- playback, group_id);
+ playback, group_id, adr_index);
if (ret < 0) {
dev_err(dev, "failed to init codec %d", codec_index);
return ret;
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index 41054cf09ec9..07aa37dd90e9 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -10,6 +10,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \
soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \
soc-acpi-intel-rpl-match.o soc-acpi-intel-mtl-match.o \
+ soc-acpi-intel-lnl-match.o \
soc-acpi-intel-hda-match.o \
soc-acpi-intel-sdw-mockup-match.o
diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
new file mode 100644
index 000000000000..9f35b77deb11
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-acpi-intel-lnl-match.c - tables and support for LNL ACPI enumeration.
+ *
+ * Copyright (c) 2023, Intel Corporation. All rights reserved.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "soc-acpi-intel-sdw-mockup-match.h"
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[] = {
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_lnl_machines);
+
+static const struct snd_soc_acpi_endpoint single_endpoint = {
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+};
+
+static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
+ {
+ .adr = 0x000030025D071101ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt711"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr lnl_rvp[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {}
+};
+
+/* this table is used when there is no I2S codec present */
+struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
+ /* mockup tests need to be first */
+ {
+ .link_mask = GENMASK(3, 0),
+ .links = sdw_mockup_headset_2amps_mic,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt711-rt1308-rt715.tplg",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1) | BIT(3),
+ .links = sdw_mockup_headset_1amp_mic,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt711-rt1308-mono-rt715.tplg",
+ },
+ {
+ .link_mask = GENMASK(2, 0),
+ .links = sdw_mockup_mic_headset_1amp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt715-rt711-rt1308-mono.tplg",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = lnl_rvp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt711.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_lnl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
index 7911c3af8071..8fd4d0db201e 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -98,6 +98,33 @@ static const struct snd_soc_acpi_adr_device rt5682_2_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = {
+ {
+ .adr = 0x000230025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1316-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
+ {
+ .adr = 0x000331025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1316-2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt714_1_adr[] = {
+ {
+ .adr = 0x000130025D071401ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt714"
+ }
+};
+
static const struct snd_soc_acpi_link_adr rt5682_link2_max98373_link0[] = {
/* Expected order: jack -> amp */
{
@@ -122,6 +149,30 @@ static const struct snd_soc_acpi_link_adr mtl_rvp[] = {
{}
};
+static const struct snd_soc_acpi_link_adr mtl_3_in_1_sdca[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1316_2_group1_adr),
+ .adr_d = rt1316_2_group1_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1316_3_group1_adr),
+ .adr_d = rt1316_3_group1_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt714_1_adr),
+ .adr_d = rt714_1_adr,
+ },
+ {}
+};
+
/* this table is used when there is no I2S codec present */
struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
/* mockup tests need to be first */
@@ -144,6 +195,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.sof_tplg_filename = "sof-mtl-rt715-rt711-rt1308-mono.tplg",
},
{
+ .link_mask = GENMASK(3, 0),
+ .links = mtl_3_in_1_sdca,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l23-rt714-l1.tplg",
+ },
+ {
.link_mask = BIT(0),
.links = mtl_rvp,
.drv_name = "sof_sdw",
diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
index 749d371a86ae..c61d654eb1e2 100644
--- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
@@ -303,6 +303,11 @@ static const struct snd_soc_acpi_codecs rpl_max98360a_amp = {
.codecs = {"MX98360A"},
};
+static const struct snd_soc_acpi_codecs rpl_max98373_amp = {
+ .num_codecs = 1,
+ .codecs = {"MX98373"}
+};
+
struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
{
.comp_ids = &rpl_rt5682_hp,
@@ -311,6 +316,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
.quirk_data = &rpl_max98360a_amp,
.sof_tplg_filename = "sof-rpl-max98360a-rt5682.tplg",
},
+ {
+ .id = "10508825",
+ .drv_name = "rpl_max98373_8825",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &rpl_max98373_amp,
+ .sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines);
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index ff25718ff2e8..4356cc320fea 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -236,6 +236,28 @@ int snd_soc_component_force_enable_pin_unlocked(
}
EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked);
+int snd_soc_component_notify_control(struct snd_soc_component *component,
+ const char * const ctl)
+{
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+ struct snd_kcontrol *kctl;
+
+ if (component->name_prefix)
+ snprintf(name, ARRAY_SIZE(name), "%s %s", component->name_prefix, ctl);
+ else
+ snprintf(name, ARRAY_SIZE(name), "%s", ctl);
+
+ kctl = snd_soc_card_get_kcontrol(component->card, name);
+ if (!kctl)
+ return soc_component_ret(component, -EINVAL);
+
+ snd_ctl_notify(component->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_notify_control);
+
/**
* snd_soc_component_set_jack - configure component jack.
* @component: COMPONENTs
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..5a508e118e3d 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,6 +178,7 @@ 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;
@@ -169,6 +190,8 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp
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,7 +202,7 @@ 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;
@@ -187,7 +210,8 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp
dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
return -EINVAL;
}
-
+out:
+ mutex_unlock(&ipc4_data->pipeline_state_mutex);
return 0;
}
@@ -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.h b/sound/soc/sof/intel/hda.h
index c4befacde23e..65832a38bffa 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -414,7 +414,7 @@
(HDA_DSP_BDL_SIZE / sizeof(struct sof_intel_dsp_bdl))
/* Number of DAIs */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
#define SOF_SKL_NUM_DAIS 15
#else
#define SOF_SKL_NUM_DAIS 8
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-topology.c b/sound/soc/sof/ipc4-topology.c
index 059eebf0a687..f9fa9238f9da 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -2271,11 +2271,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 +2305,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 +2500,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/pcm.c b/sound/soc/sof/pcm.c
index 567db32173a8..d14e7fd2c2ee 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: