diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/ak4118.c | 11 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 20 | ||||
-rw-r--r-- | sound/soc/intel/boards/sof_nau8825.c | 10 | ||||
-rw-r--r-- | sound/soc/intel/boards/sof_sdw.c | 49 | ||||
-rw-r--r-- | sound/soc/intel/common/Makefile | 1 | ||||
-rw-r--r-- | sound/soc/intel/common/soc-acpi-intel-lnl-match.c | 72 | ||||
-rw-r--r-- | sound/soc/intel/common/soc-acpi-intel-mtl-match.c | 57 | ||||
-rw-r--r-- | sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 12 | ||||
-rw-r--r-- | sound/soc/soc-component.c | 22 | ||||
-rw-r--r-- | sound/soc/sof/intel/Kconfig | 3 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-bus.c | 11 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-dai-ops.c | 73 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-dai.c | 104 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda.h | 2 | ||||
-rw-r--r-- | sound/soc/sof/ipc4-pcm.c | 4 | ||||
-rw-r--r-- | sound/soc/sof/ipc4-topology.c | 22 | ||||
-rw-r--r-- | sound/soc/sof/pcm.c | 2 |
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: |