From b19259f6f444dc1353915385b9033072fbf9699e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 14 May 2021 15:51:44 +0300 Subject: [PATCH 01/30] acpi: HACK: silence the Found %d idle state Signed-off-by: Peter Ujfalusi --- drivers/acpi/acpi_processor.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 6737b1cbf6d69f..d0bcedd81effe5 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -880,8 +880,6 @@ int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu, memcpy(&info->states[++last_index], &cx, sizeof(cx)); } - acpi_handle_info(handle, "Found %d idle states\n", last_index); - info->count = last_index; end: From b5dd83bd1d165fdc7658367aa677ab26b499cbed Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 6 May 2022 15:18:59 +0300 Subject: [PATCH 02/30] [WIP] snd_soc_acpi_mach link_mask to mach_params.link_mask stuff Signed-off-by: Peter Ujfalusi --- .../intel/common/soc-acpi-intel-tgl-match.c | 64 ++++++++++++++++--- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index ef19150e7b2e9a..ad7aaeddbb99a5 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -422,59 +422,91 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { .links = sdw_mockup_headset_2amps_mic, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt711-rt1308-rt715.tplg", + .mach_params = { + .link_mask = GENMASK(3, 0), + .links = sdw_mockup_headset_2amps_mic, + }, }, { .link_mask = BIT(0) | BIT(1) | BIT(3), .links = sdw_mockup_headset_1amp_mic, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt711-rt1308-mono-rt715.tplg", + .mach_params = { + .link_mask = BIT(0) | BIT(1) | BIT(3), + .links = sdw_mockup_headset_1amp_mic, + }, }, { .link_mask = BIT(0) | BIT(1) | BIT(2), .links = sdw_mockup_mic_headset_1amp, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt715-rt711-rt1308-mono.tplg", + .mach_params = { + .link_mask = BIT(0) | BIT(1) | BIT(2), + .links = sdw_mockup_mic_headset_1amp, + }, }, { .link_mask = 0x7, .links = tgl_sdw_rt711_link1_rt1308_link2_rt715_link0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt715-rt711-rt1308-mono.tplg", + .mach_params = { + .link_mask = 0x7, + .links = tgl_sdw_rt711_link1_rt1308_link2_rt715_link0, + }, }, { .link_mask = 0xF, /* 4 active links required */ .links = tgl_3_in_1_default, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt711-rt1308-rt715.tplg", + .mach_params = { + .link_mask = 0xF, /* 4 active links required */ + .links = tgl_3_in_1_default, + }, }, { + .link_mask = 0xF, + .links = tgl_3_in_1_mono_amp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-tgl-rt711-rt1308-mono-rt715.tplg", /* * link_mask should be 0xB, but all links are enabled by BIOS. * This entry will be selected if there is no rt1308 exposed * on link2 since it will fail to match the above entry. */ - .link_mask = 0xF, - .links = tgl_3_in_1_mono_amp, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-tgl-rt711-rt1308-mono-rt715.tplg", + .mach_params = { + .link_mask = 0xF, + .links = tgl_3_in_1_mono_amp, + }, }, { .link_mask = 0xF, /* 4 active links required */ .links = tgl_3_in_1_sdca, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt711-rt1316-rt714.tplg", + .mach_params = { + .link_mask = 0xF, /* 4 active links required */ + .links = tgl_3_in_1_sdca, + }, }, { + .link_mask = 0xF, /* 4 active links required */ + .links = tgl_3_in_1_sdca_mono, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-tgl-rt711-l0-rt1316-l1-mono-rt714-l3.tplg", /* * link_mask should be 0xB, but all links are enabled by BIOS. * This entry will be selected if there is no rt1316 amplifier exposed * on link2 since it will fail to match the above entry. */ - .link_mask = 0xF, /* 4 active links required */ - .links = tgl_3_in_1_sdca_mono, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-tgl-rt711-l0-rt1316-l1-mono-rt714-l3.tplg", + .mach_params = { + .link_mask = 0xF, /* 4 active links required */ + .links = tgl_3_in_1_sdca_mono, + }, }, { @@ -482,24 +514,40 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { .links = tgl_hp, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg", + .mach_params = { + .link_mask = 0x3, /* rt711 on link 0 and 1 rt1308 on link 1 */ + .links = tgl_hp, + }, }, { .link_mask = 0x3, /* rt711 on link 0 and 2 rt1308s on link 1 */ .links = tgl_rvp, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg", + .mach_params = { + .link_mask = 0x3, /* rt711 on link 0 and 2 rt1308s on link 1 */ + .links = tgl_rvp, + }, }, { .link_mask = 0x3, /* rt5682 on link0 & 2xmax98373 on link 1 */ .links = tgl_chromebook_base, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-sdw-max98373-rt5682.tplg", + .mach_params = { + .link_mask = 0x3, /* rt5682 on link0 & 2xmax98373 on link 1 */ + .links = tgl_chromebook_base, + }, }, { .link_mask = 0x1, /* rt711 on link 0 */ .links = tgl_rvp_headset_only, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt711.tplg", + .mach_params = { + .link_mask = 0x1, /* rt711 on link 0 */ + .links = tgl_rvp_headset_only, + }, }, {}, }; From 40b3f91f104b400437f5f0b5e02a813ef7d3b33d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 18 Aug 2022 12:58:23 +0300 Subject: [PATCH 03/30] [HACK] ASoC: SOF: ipc4-topology: Load one library for testing Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-topology.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 7045e858399a52..e97f35e92eeca0 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -286,6 +286,26 @@ static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget) kfree(swidget->private); } +static void sof_ipc4_load_a_hack(struct snd_sof_dev *sdev) +{ +#if 0 + /* ACA: 88881111-2222-3333-4444-555566667777 */ + guid_t uuid = GUID_INIT(0x88881111, 0x2222, 0x3333, + 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77); +#else + /* GDB: 5842A646-15AC-4CA4-BD0B-53D5D40822BB */ + guid_t uuid = GUID_INIT(0x5842A646, 0x15AC, 0x4CA4, + 0xBD, 0x0B, 0x53, 0xD5, 0xD4, 0x08, 0x22, 0xBB); +#endif + struct sof_ipc4_fw_module *fw_module; + + fw_module = sof_ipc4_find_module_by_uuid(sdev, &uuid); + if (fw_module) + pr_warn("%s: got module for UUID %pUL\n", __func__, &uuid); + else + pr_warn("%s: no module for UUID %pUL\n", __func__, &uuid); +} + static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; @@ -293,6 +313,8 @@ static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid); + sof_ipc4_load_a_hack(sdev); + if (swidget->module_info) return 0; From 2577f43f8f77e6d2d8033e31174fddfccd69cdf8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 31 Aug 2022 09:00:48 +0300 Subject: [PATCH 04/30] Revert "[HACK] ASoC: SOF: ipc4-topology: Load one library for testing" This reverts commit 343f1d36f8925206709884a4bd22fa0dabf31d5a. --- sound/soc/sof/ipc4-topology.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index e97f35e92eeca0..7045e858399a52 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -286,26 +286,6 @@ static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget) kfree(swidget->private); } -static void sof_ipc4_load_a_hack(struct snd_sof_dev *sdev) -{ -#if 0 - /* ACA: 88881111-2222-3333-4444-555566667777 */ - guid_t uuid = GUID_INIT(0x88881111, 0x2222, 0x3333, - 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77); -#else - /* GDB: 5842A646-15AC-4CA4-BD0B-53D5D40822BB */ - guid_t uuid = GUID_INIT(0x5842A646, 0x15AC, 0x4CA4, - 0xBD, 0x0B, 0x53, 0xD5, 0xD4, 0x08, 0x22, 0xBB); -#endif - struct sof_ipc4_fw_module *fw_module; - - fw_module = sof_ipc4_find_module_by_uuid(sdev, &uuid); - if (fw_module) - pr_warn("%s: got module for UUID %pUL\n", __func__, &uuid); - else - pr_warn("%s: no module for UUID %pUL\n", __func__, &uuid); -} - static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; @@ -313,8 +293,6 @@ static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid); - sof_ipc4_load_a_hack(sdev); - if (swidget->module_info) return 0; From ff856a5ea46d678dc970a62b1158c56f24c0a588 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 15 Feb 2022 15:39:56 +0200 Subject: [PATCH 05/30] --- Hacks --- From 8490ef1e9050fd0925116fd37189027602bc4ea2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 30 Sep 2022 14:21:52 +0300 Subject: [PATCH 06/30] ASoC: SOF: sof-priv: Remove unused SOF_DAI_STREAM() and SOF_FORMATS The following definitions have no users: SOF_DAI_STREAM() and SOF_FORMATS, they can be dropped from the header file. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-priv.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index eb1192dbdfb61c..0cc5c0174438ac 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -70,14 +70,6 @@ bool sof_debug_check_flag(int mask); #define SOF_IPC_DSP_REPLY 0 #define SOF_IPC_HOST_REPLY 1 -/* convenience constructor for DAI driver streams */ -#define SOF_DAI_STREAM(sname, scmin, scmax, srates, sfmt) \ - {.stream_name = sname, .channels_min = scmin, .channels_max = scmax, \ - .rates = srates, .formats = sfmt} - -#define SOF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT) - /* So far the primary core on all DSPs has ID 0 */ #define SOF_DSP_PRIMARY_CORE 0 From 32d14bc60db9883e958aba049b51aec811d383e8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 28 Sep 2022 15:05:42 +0300 Subject: [PATCH 07/30] -- misc fixes -- From 21bcd0d9c6f57f08b10b06838265035eeb81eb47 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 7 Apr 2022 10:00:15 +0300 Subject: [PATCH 08/30] ALSA: intel-nhlt: Change struct nhlt_acpi_table.desc struct array to u8 The struct nhlt_endpoint is a flexible array, because: struct nhlt_acpi_table { ... struct nhlt_endpoint desc[] { <- This ... struct nhlt_specific_cfg { u32 size; u8 caps[]; <- Because of this }; }; }; This causes several notes from sparse as well: note: in included file: include/sound/intel-nhlt.h:83:34: warning: array of flexible structures To help the compiler to understand this, we should convert it to u8 array. Signed-off-by: Peter Ujfalusi --- include/sound/intel-nhlt.h | 2 +- sound/hda/intel-nhlt.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/sound/intel-nhlt.h b/include/sound/intel-nhlt.h index 53470d6a28d659..ea01b0df8d5e16 100644 --- a/include/sound/intel-nhlt.h +++ b/include/sound/intel-nhlt.h @@ -78,7 +78,7 @@ struct nhlt_endpoint { struct nhlt_acpi_table { struct acpi_table_header header; u8 endpoint_count; - struct nhlt_endpoint desc[]; + u8 desc[]; /* flexible array of 'struct nhlt_endpoint' */ } __packed; struct nhlt_resource_desc { diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 2c4dfc0b7e342c..673f8724811f97 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -44,8 +44,9 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) return 0; } - for (j = 0, epnt = nhlt->desc; j < nhlt->endpoint_count; j++, - epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length)) { + for (j = 0, epnt = (struct nhlt_endpoint *)nhlt->desc; + j < nhlt->endpoint_count; + j++, epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length)) { if (epnt->linktype != NHLT_LINK_DMIC) continue; From 17452770830911d781de20c40102ce54af975981 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 7 Apr 2022 14:08:33 +0300 Subject: [PATCH 09/30] ALSA: intel-nhlt: Change struct nhlt_fmt.fmt_config struct array to u8 The struct nhlt_fmt_cfg is a flexible array, because: struct nhlt_fmt { ... struct nhlt_fmt_cfg fmt_config[] { <- This ... struct nhlt_specific_cfg { ... u8 caps[]; <- Because of this }; }; }; Strangely sparse did not complain about this, but it was misused by drivers, treating it as a normal array and not a flexible one. Signed-off-by: Peter Ujfalusi --- include/sound/intel-nhlt.h | 2 +- sound/hda/intel-nhlt.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/sound/intel-nhlt.h b/include/sound/intel-nhlt.h index ea01b0df8d5e16..e0e2700c619c84 100644 --- a/include/sound/intel-nhlt.h +++ b/include/sound/intel-nhlt.h @@ -58,7 +58,7 @@ struct nhlt_fmt_cfg { struct nhlt_fmt { u8 fmt_count; - struct nhlt_fmt_cfg fmt_config[]; + u8 fmt_config[]; /* flexible array of 'struct nhlt_fmt_cfg' */ } __packed; struct nhlt_endpoint { diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 673f8724811f97..7d4f0ae8a39837 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -56,11 +56,12 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) /* find max number of channels based on format_configuration */ if (fmt_configs->fmt_count) { - struct nhlt_fmt_cfg *fmt_cfg = fmt_configs->fmt_config; + struct nhlt_fmt_cfg *fmt_cfg; dev_dbg(dev, "found %d format definitions\n", fmt_configs->fmt_count); + fmt_cfg = (struct nhlt_fmt_cfg *)fmt_configs->fmt_config; for (i = 0; i < fmt_configs->fmt_count; i++) { struct wav_fmt_ext *fmt_ext; @@ -189,7 +190,7 @@ int intel_nhlt_ssp_mclk_mask(struct nhlt_acpi_table *nhlt, int ssp_num) epnt->virtual_bus_id == ssp_num) { fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size); - cfg = fmt->fmt_config; + cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; /* * In theory all formats should use the same MCLK but it doesn't hurt to @@ -241,7 +242,7 @@ static struct nhlt_specific_cfg * nhlt_get_specific_cfg(struct device *dev, struct nhlt_fmt *fmt, u8 num_ch, u32 rate, u8 vbps, u8 bps) { - struct nhlt_fmt_cfg *cfg = fmt->fmt_config; + struct nhlt_fmt_cfg *cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; struct wav_fmt *wfmt; u16 _bps, _vbps; int i; From 47da3749561d227655fd7e1e1dede6302b640834 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 7 Apr 2022 10:17:52 +0300 Subject: [PATCH 10/30] ASoC: SOF: uapi: header: Convert struct sof_manifest.items[] to u8 array The items array member of truct sof_manifest is a flexible array, because: struct sof_manifest { ... struct sof_manifest_tlv items[] { <- This ... __u8 data[]; << Because of this } }; This causes notes from sparse as well: note: in included file: include/uapi/sound/sof/header.h:56:38: warning: array of flexible structures To help the compiler to understand this, we should convert it to u8 array. Signed-off-by: Peter Ujfalusi --- include/uapi/sound/sof/header.h | 4 ++-- sound/soc/sof/ipc4-topology.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/uapi/sound/sof/header.h b/include/uapi/sound/sof/header.h index 687325eda5ad94..e2e760c94f0184 100644 --- a/include/uapi/sound/sof/header.h +++ b/include/uapi/sound/sof/header.h @@ -68,14 +68,14 @@ struct sof_manifest_tlv { * @abi_minor: Minor ABI version * @abi_patch: ABI patch * @count: count of tlv items - * @items: consecutive variable size tlv items + * @items: consecutive variable size tlv items (struct sof_manifest_tlv) */ struct sof_manifest { __le16 abi_major; __le16 abi_minor; __le16 abi_patch; __le16 count; - struct sof_manifest_tlv items[]; + __u8 items[]; }; #endif diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 7045e858399a52..093e799fa00630 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1920,7 +1920,7 @@ static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, if (size <= SOF_IPC4_TPLG_ABI_SIZE) return 0; - manifest_tlv = manifest->items; + manifest_tlv = (struct sof_manifest_tlv *)manifest->items; len_check = sizeof(struct sof_manifest); for (i = 0; i < le16_to_cpu(manifest->count); i++) { len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); From 43a23bc4bdc932958ea5ff7931c14a815e943eaf Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 17 Oct 2022 10:09:40 +0300 Subject: [PATCH 11/30] ASoC: SOF: core: Print out the value of sof_debug if it is set The sof_debug value is set by the user, developer intentionally. To save time on figuring out what value has been passed to the kernel by the user, developer, print it out if it is not 0. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 3e6141d03770fc..8d128d152cecd6 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -362,6 +362,9 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sdev->first_boot = true; dev_set_drvdata(dev, sdev); + if (sof_core_debug) + dev_info(dev, "sof_debug value: %#x\n", sof_core_debug); + /* check IPC support */ if (!(BIT(plat_data->ipc_type) & plat_data->desc->ipc_supported_mask)) { dev_err(dev, "ipc_type %d is not supported on this platform, mask is %#x\n", From 1710f435e0838f47d88cb0cdc948aaef27073564 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 30 Jun 2022 09:47:00 +0300 Subject: [PATCH 12/30] -- flex to u8 -- From abcfcee649993c466b27a7e8cba986684962ed6f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 7 Oct 2022 12:18:23 +0300 Subject: [PATCH 13/30] ASoC: SOF: sof-audio: Treat tplg_ops->route_setup() as optional Other topology ops have been treated as optional, including the route_free. Handle the route_setup in a conforming way as optional callback. Note: we do not have checks for the callbacks itself which makes them all optional in practice. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-audio.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 9b09b5599ec477..7cb9f1d3afacde 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -174,7 +174,6 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc struct snd_sof_widget *sink_widget = wsink->dobj.private; struct snd_sof_route *sroute; bool route_found = false; - int ret; /* ignore routes involving virtual widgets in topology */ switch (src_widget->id) { @@ -212,9 +211,12 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc if (sroute->setup) return 0; - ret = ipc_tplg_ops->route_setup(sdev, sroute); - if (ret < 0) - return ret; + if (ipc_tplg_ops->route_setup) { + int ret = ipc_tplg_ops->route_setup(sdev, sroute); + + if (ret < 0) + return ret; + } sroute->setup = true; return 0; From 8dc818203b77a9cefbab8c9daeacab8c2e032fcf Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 12 Oct 2022 12:23:33 +0300 Subject: [PATCH 14/30] ASoC: SOF: sof-audio: Update documentation for sof_ipc_tplg_ops The core treats all function pointer in sof_ipc_tplg_ops as optional. Update the documentation to reflect this. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-audio.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 636b9e0909d5a6..9a918bf7744c2c 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -173,7 +173,7 @@ struct sof_ipc_tplg_widget_ops { * initialized to 0. * @control: Pointer to the IPC-specific ops for topology kcontrol IO * @route_setup: Function pointer for setting up pipeline connections - * @route_free: Optional op for freeing pipeline connections. + * @route_free: Function pointer for freeing pipeline connections. * @token_list: List of all tokens supported by the IPC version. The size of the token_list * array should be SOF_TOKEN_COUNT. The unused elements in the array will be * initialized to 0. @@ -186,8 +186,10 @@ struct sof_ipc_tplg_widget_ops { * @dai_get_clk: Function pointer for getting the DAI clock setting * @set_up_all_pipelines: Function pointer for setting up all topology pipelines * @tear_down_all_pipelines: Function pointer for tearing down all topology pipelines - * @parse_manifest: Optional function pointer for ipc4 specific parsing of topology manifest - * @link_setup: Optional function pointer for IPC-specific DAI link set up + * @parse_manifest: Function pointer for ipc4 specific parsing of topology manifest + * @link_setup: Function pointer for IPC-specific DAI link set up + * + * Note: function pointers (ops) are optional */ struct sof_ipc_tplg_ops { const struct sof_ipc_tplg_widget_ops *widget; From aa79f1493a5a9bd76ce1e6535b750295aeb19dbf Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 11 Oct 2022 11:29:32 +0300 Subject: [PATCH 15/30] ASoC: SOF: Add helper macro to be used to get an IPC ops In preparation to a case when the DSP is not used. In this case the IPC communication itself has no meaning and we might not even have sdev->ipc allocated at all. The sof_ipc_get_ops() macro can be used to get a named IPC ops struct or return NULL if the sdev->ipc is not allocated. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-priv.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 0cc5c0174438ac..977a514cf32e12 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -494,6 +494,10 @@ struct snd_sof_ipc { const struct sof_ipc_ops *ops; }; +/* Helper to retrieve the IPC ops */ +#define sof_ipc_get_ops(sdev, ops_name) \ + (((sdev)->ipc && (sdev)->ipc->ops) ? (sdev)->ipc->ops->ops_name : NULL) + /* * SOF Device Level. */ From 41c89c02d29aab146b75d99c4841fe7fa0bb814c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 11 Oct 2022 11:54:28 +0300 Subject: [PATCH 16/30] ASoC: SOF: pcm: Extend the optionality of IPC ops to IPC as well The IPC ops are optional, but they require that the ops struct is to be allocated with all callbacks set to NULL. Update the code to extend the optionality to: sdev->ipc == NULL sdev->ipc->ops == NULL sdev->ipc->ops->[pcm] == NULL sdev->ipc->ops->[pcm]->ops == NULL (treated optional currently) Signed-off-by: Peter Ujfalusi --- sound/soc/sof/pcm.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 7ea83cfb19ed6c..34d40c5c629a2b 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -125,8 +125,8 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_platform_stream_params platform_params = { 0 }; - const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_sof_pcm *spcm; int ret; @@ -143,7 +143,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, * Handle repeated calls to hw_params() without free_pcm() in * between. At least ALSA OSS emulation depends on this. */ - if (pcm_ops->hw_free && spcm->prepared[substream->stream]) { + if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) { ret = pcm_ops->hw_free(component, substream); if (ret < 0) return ret; @@ -177,7 +177,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, return ret; } - if (pcm_ops->hw_params) { + if (pcm_ops && pcm_ops->hw_params) { ret = pcm_ops->hw_params(component, substream, params, &platform_params); if (ret < 0) return ret; @@ -196,7 +196,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm; + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm; int ret, err = 0; @@ -212,7 +212,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, spcm->pcm.pcm_id, substream->stream); /* free PCM in the DSP */ - if (pcm_ops->hw_free && spcm->prepared[substream->stream]) { + if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) { ret = pcm_ops->hw_free(component, substream); if (ret < 0) err = ret; @@ -279,7 +279,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm; + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm; bool reset_hw_params = false; bool ipc_first = false; @@ -342,7 +342,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, if (!ipc_first) snd_sof_pcm_platform_trigger(sdev, substream, cmd); - if (pcm_ops->trigger) + if (pcm_ops && pcm_ops->trigger) ret = pcm_ops->trigger(component, substream, cmd); /* need to STOP DMA even if trigger IPC failed */ @@ -566,7 +566,7 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm; + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); /* no topology exists for this BE, try a common configuration */ if (!dai) { @@ -587,7 +587,7 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa return 0; } - if (pcm_ops->dai_link_fixup) + if (pcm_ops && pcm_ops->dai_link_fixup) return pcm_ops->dai_link_fixup(rtd, params); return 0; From a73d53de4775d8a835eacc31acc3e34a428ee4cc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 11 Oct 2022 12:08:36 +0300 Subject: [PATCH 17/30] ASoC: SOF: control: Extend the optionality of IPC ops to IPC as well The IPC ops are optional, but they require that the ops struct is to be allocated with all callbacks set to NULL. Update the code to extend the optionality to: sdev->ipc == NULL sdev->ipc->ops == NULL sdev->ipc->ops->[tplg] == NULL sdev->ipc->ops->[tplg]->control == NULL sdev->ipc->ops->[tplg]->control->ops == NULL (treated optional currently) Signed-off-by: Peter Ujfalusi --- sound/soc/sof/control.c | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index e0e9efd25d34e2..75e13f4fd1eb81 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -22,9 +22,9 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->volume_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->volume_get) return tplg_ops->control->volume_get(scontrol, ucontrol); return 0; @@ -37,9 +37,9 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->volume_put) + if (tplg_ops && tplg_ops->control && tplg_ops->control->volume_put) return tplg_ops->control->volume_put(scontrol, ucontrol); return false; @@ -74,9 +74,9 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->switch_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->switch_get) return tplg_ops->control->switch_get(scontrol, ucontrol); return 0; @@ -89,9 +89,9 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->switch_put) + if (tplg_ops && tplg_ops->control && tplg_ops->control->switch_put) return tplg_ops->control->switch_put(scontrol, ucontrol); return false; @@ -104,9 +104,9 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = se->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->enum_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->enum_get) return tplg_ops->control->enum_get(scontrol, ucontrol); return 0; @@ -119,9 +119,9 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = se->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->enum_put) + if (tplg_ops && tplg_ops->control && tplg_ops->control->enum_put) return tplg_ops->control->enum_put(scontrol, ucontrol); return false; @@ -134,9 +134,9 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->bytes_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_get) return tplg_ops->control->bytes_get(scontrol, ucontrol); return 0; @@ -149,9 +149,9 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->bytes_put) + if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_put) return tplg_ops->control->bytes_put(scontrol, ucontrol); return 0; @@ -165,13 +165,13 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); /* make sure we have at least a header */ if (size < sizeof(struct snd_ctl_tlv)) return -EINVAL; - if (tplg_ops->control->bytes_ext_put) + if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_put) return tplg_ops->control->bytes_ext_put(scontrol, binary_data, size); return 0; @@ -184,7 +184,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); int ret, err; ret = pm_runtime_resume_and_get(scomp->dev); @@ -193,7 +193,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ return ret; } - if (tplg_ops->control->bytes_ext_volatile_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_volatile_get) ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size); pm_runtime_mark_last_busy(scomp->dev); @@ -212,9 +212,9 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->bytes_ext_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_get) return tplg_ops->control->bytes_ext_get(scontrol, binary_data, size); return 0; From 8e6b09b572949fe8e8cb6ae40e442cebe6af68c0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 11 Oct 2022 12:12:34 +0300 Subject: [PATCH 18/30] ASoC: SOF: sof-audio: Extend the optionality of IPC ops to IPC as well The IPC ops are optional, but they require that the ops struct is to be allocated with all callbacks set to NULL. Update the code to extend the optionality to: sdev->ipc == NULL sdev->ipc->ops == NULL sdev->ipc->ops->[ops_group] == NULL sdev->ipc->ops->[pcmops_group]->ops == NULL (treated optional currently) Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-audio.c | 51 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 7cb9f1d3afacde..3798f627094b87 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -16,12 +16,12 @@ static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget) { - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_route *sroute; list_for_each_entry(sroute, &sdev->route_list, list) if (sroute->src_widget == widget || sroute->sink_widget == widget) { - if (sroute->setup && tplg_ops->route_free) + if (sroute->setup && tplg_ops && tplg_ops->route_free) tplg_ops->route_free(sdev, sroute); sroute->setup = false; @@ -30,7 +30,7 @@ static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_so int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); int err = 0; int ret; @@ -47,7 +47,7 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) sof_reset_route_setup_status(sdev, swidget); /* continue to disable core even if IPC fails */ - if (tplg_ops->widget_free) + if (tplg_ops && tplg_ops->widget_free) err = tplg_ops->widget_free(sdev, swidget); /* @@ -82,7 +82,7 @@ EXPORT_SYMBOL(sof_widget_free); int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); int ret; /* skip if there is no private data */ @@ -124,7 +124,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) } /* setup widget in the DSP */ - if (tplg_ops->widget_setup) { + if (tplg_ops && tplg_ops->widget_setup) { ret = tplg_ops->widget_setup(sdev, swidget); if (ret < 0) goto core_put; @@ -134,7 +134,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) if (WIDGET_IS_DAI(swidget->id)) { unsigned int flags = SOF_DAI_CONFIG_FLAGS_NONE; - if (tplg_ops->dai_config) { + if (tplg_ops && tplg_ops->dai_config) { ret = tplg_ops->dai_config(sdev, swidget, flags, NULL); if (ret < 0) goto widget_free; @@ -142,7 +142,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) } /* restore kcontrols for widget */ - if (tplg_ops->control->widget_kcontrol_setup) { + if (tplg_ops && tplg_ops->control && tplg_ops->control->widget_kcontrol_setup) { ret = tplg_ops->control->widget_kcontrol_setup(sdev, swidget); if (ret < 0) goto widget_free; @@ -169,7 +169,7 @@ EXPORT_SYMBOL(sof_widget_setup); int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink) { - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_widget *src_widget = wsource->dobj.private; struct snd_sof_widget *sink_widget = wsink->dobj.private; struct snd_sof_route *sroute; @@ -211,8 +211,8 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc if (sroute->setup) return 0; - if (ipc_tplg_ops->route_setup) { - int ret = ipc_tplg_ops->route_setup(sdev, sroute); + if (tplg_ops && tplg_ops->route_setup) { + int ret = tplg_ops->route_setup(sdev, sroute); if (ret < 0) return ret; @@ -277,16 +277,17 @@ static void sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, struct snd_soc_dapm_widget_list *list) { - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_widget *swidget = widget->dobj.private; + const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_soc_dapm_path *p; /* return if the widget is in use or if it is already unprepared */ if (!swidget->prepared || swidget->use_count > 1) return; - if (widget_ops[widget->id].ipc_unprepare) + widget_ops = tplg_ops ? tplg_ops->widget : NULL; + if (widget_ops && widget_ops[widget->id].ipc_unprepare) /* unprepare the source widget */ widget_ops[widget->id].ipc_unprepare(swidget); @@ -311,12 +312,16 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget struct snd_pcm_hw_params *pipeline_params, int dir, struct snd_soc_dapm_widget_list *list) { - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_widget *swidget = widget->dobj.private; + const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_soc_dapm_path *p; int ret; + widget_ops = tplg_ops ? tplg_ops->widget : NULL; + if (!widget_ops) + return 0; + if (!widget_ops[widget->id].ipc_prepare || swidget->prepared) goto sink_prepare; @@ -526,7 +531,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, struct snd_sof_platform_stream_params *platform_params, int dir) { - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; struct snd_soc_dapm_widget *widget; int i, ret; @@ -580,8 +585,8 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, if (pipe_widget->complete) continue; - if (ipc_tplg_ops->pipeline_complete) { - pipe_widget->complete = ipc_tplg_ops->pipeline_complete(sdev, pipe_widget); + if (tplg_ops && tplg_ops->pipeline_complete) { + pipe_widget->complete = tplg_ops->pipeline_complete(sdev, pipe_widget); if (pipe_widget->complete < 0) { ret = pipe_widget->complete; goto widget_free; @@ -672,11 +677,11 @@ bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev) int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, struct snd_sof_pcm *spcm, int dir, bool free_widget_list) { - const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm; + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); int ret; /* Send PCM_FREE IPC to reset pipeline */ - if (pcm_ops->hw_free && spcm->prepared[substream->stream]) { + if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) { ret = pcm_ops->hw_free(sdev->component, substream); if (ret < 0) return ret; @@ -806,13 +811,13 @@ static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type) struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); /* use the tplg configured mclk if existed */ if (!dai) return 0; - if (tplg_ops->dai_get_clk) + if (tplg_ops && tplg_ops->dai_get_clk) return tplg_ops->dai_get_clk(sdev, dai, clk_type); return 0; From 9535a0706dc9690f77c19e97152f5c3011a62eb6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 11 Oct 2022 12:38:15 +0300 Subject: [PATCH 19/30] ASoC: SOF: topology: Extend the optionality of IPC ops to IPC as well The IPC ops are optional, but they require that the ops struct is to be allocated with all callbacks set to NULL. Update the code to extend the optionality to: sdev->ipc == NULL sdev->ipc->ops == NULL sdev->ipc->ops->[tplg] == NULL sdev->ipc->ops->[tplg]->ops == NULL (treated optional currently) At the same time standardize the naming of the ops pointer to tplg_ops Signed-off-by: Peter Ujfalusi --- sound/soc/sof/topology.c | 103 +++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 0160d2cf0b7e55..4c34bb3e87b753 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -54,11 +54,16 @@ int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum so size_t object_size, int token_instance_num) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_token_info *token_list = ipc_tplg_ops->token_list; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); + const struct sof_token_info *token_list; const struct sof_topology_token *tokens; int i, j; + token_list = tplg_ops ? tplg_ops->token_list : NULL; + /* nothing to do if token_list is NULL */ + if (!token_list) + return 0; + if (token_list[token_id].count < 0) { dev_err(scomp->dev, "Invalid token count for token ID: %d\n", token_id); return -EINVAL; @@ -263,9 +268,9 @@ static int set_up_volume_table(struct snd_sof_control *scontrol, { struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->set_up_volume_table) + if (tplg_ops && tplg_ops->control && tplg_ops->control->set_up_volume_table) return tplg_ops->control->set_up_volume_table(scontrol, tlv, size); dev_err(scomp->dev, "Mandatory op %s not set\n", __func__); @@ -487,13 +492,14 @@ static int sof_copy_tuples(struct snd_sof_dev *sdev, struct snd_soc_tplg_vendor_ int array_size, u32 token_id, int token_instance_num, struct snd_sof_tuple *tuples, int tuples_size, int *num_copied_tuples) { - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_token_info *token_list = ipc_tplg_ops->token_list; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); + const struct sof_token_info *token_list; const struct sof_topology_token *tokens; int found = 0; int num_tokens, asize; int i, j; + token_list = tplg_ops ? tplg_ops->token_list : NULL; /* nothing to do if token_list is NULL */ if (!token_list) return 0; @@ -1012,14 +1018,14 @@ static int sof_control_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_control *scontrol = dobj->private; int ret = 0; dev_dbg(scomp->dev, "tplg: unload control name : %s\n", scontrol->name); - if (ipc_tplg_ops->control_free) { - ret = ipc_tplg_ops->control_free(sdev, scontrol); + if (tplg_ops && tplg_ops->control_free) { + ret = tplg_ops->control_free(sdev, scontrol); if (ret < 0) dev_err(scomp->dev, "failed to free control: %s\n", scontrol->name); } @@ -1198,12 +1204,17 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s enum sof_tokens *object_token_list, int count) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_token_info *token_list = ipc_tplg_ops->token_list; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_soc_tplg_private *private = &tw->priv; + const struct sof_token_info *token_list; int num_tuples = 0; int ret, i; + token_list = tplg_ops ? tplg_ops->token_list : NULL; + /* nothing to do if token_list is NULL */ + if (!token_list) + return 0; + if (count > 0 && !object_token_list) { dev_err(scomp->dev, "No token list for widget %s\n", swidget->widget->name); return -EINVAL; @@ -1372,13 +1383,13 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_dapm_widget *tw) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); + const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_soc_tplg_private *priv = &tw->priv; + enum sof_tokens *token_list = NULL; struct snd_sof_widget *swidget; struct snd_sof_dai *dai; - enum sof_tokens *token_list; - int token_list_size; + int token_list_size = 0; int ret = 0; swidget = kzalloc(sizeof(*swidget), GFP_KERNEL); @@ -1437,8 +1448,11 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, swidget->num_sink_pins, swidget->num_source_pins, strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? w->sname : "none"); - token_list = widget_ops[w->id].token_list; - token_list_size = widget_ops[w->id].token_list_size; + widget_ops = tplg_ops ? tplg_ops->widget : NULL; + if (widget_ops) { + token_list = widget_ops[w->id].token_list; + token_list_size = widget_ops[w->id].token_list_size; + } /* handle any special case widgets */ switch (w->id) { @@ -1522,7 +1536,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, /* bind widget to external event */ if (tw->event_type) { - if (widget_ops[w->id].bind_event) { + if (widget_ops && widget_ops[w->id].bind_event) { ret = widget_ops[w->id].bind_event(scomp, swidget, le16_to_cpu(tw->event_type)); if (ret) { @@ -1562,8 +1576,8 @@ static int sof_widget_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); + const struct sof_ipc_tplg_widget_ops *widget_ops; const struct snd_kcontrol_new *kc; struct snd_soc_dapm_widget *widget; struct snd_sof_control *scontrol; @@ -1623,7 +1637,8 @@ static int sof_widget_unload(struct snd_soc_component *scomp, out: /* free IPC related data */ - if (widget_ops[swidget->id].ipc_free) + widget_ops = tplg_ops ? tplg_ops->widget : NULL; + if (widget_ops && widget_ops[swidget->id].ipc_free) widget_ops[swidget->id].ipc_free(swidget); ida_destroy(&swidget->src_queue_ida); @@ -1651,7 +1666,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_pcm_ops *ipc_pcm_ops = sdev->ipc->ops->pcm; + const struct sof_ipc_pcm_ops *ipc_pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_soc_tplg_stream_caps *caps; struct snd_soc_tplg_private *private = &pcm->priv; struct snd_sof_pcm *spcm; @@ -1680,7 +1695,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, dev_dbg(scomp->dev, "tplg: load pcm %s\n", pcm->dai_name); /* perform pcm set op */ - if (ipc_pcm_ops->pcm_setup) { + if (ipc_pcm_ops && ipc_pcm_ops->pcm_setup) { ret = ipc_pcm_ops->pcm_setup(sdev, spcm); if (ret < 0) return ret; @@ -1764,7 +1779,7 @@ static int sof_dai_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_pcm_ops *ipc_pcm_ops = sdev->ipc->ops->pcm; + const struct sof_ipc_pcm_ops *ipc_pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm = dobj->private; /* free PCM DMA pages */ @@ -1775,7 +1790,7 @@ static int sof_dai_unload(struct snd_soc_component *scomp, snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_CAPTURE].page_table); /* perform pcm free op */ - if (ipc_pcm_ops->pcm_free) + if (ipc_pcm_ops && ipc_pcm_ops->pcm_free) ipc_pcm_ops->pcm_free(sdev, spcm); /* remove from list and free spcm */ @@ -1795,9 +1810,9 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ struct snd_soc_tplg_link_config *cfg) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_token_info *token_list = ipc_tplg_ops->token_list; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_soc_tplg_private *private = &cfg->priv; + const struct sof_token_info *token_list; struct snd_sof_dai_link *slink; u32 token_id = 0; int num_tuples = 0; @@ -1809,8 +1824,8 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ } link->platforms->name = dev_name(scomp->dev); - if (ipc_tplg_ops->link_setup) { - ret = ipc_tplg_ops->link_setup(sdev, link); + if (tplg_ops && tplg_ops->link_setup) { + ret = tplg_ops->link_setup(sdev, link); if (ret < 0) return ret; } @@ -1856,6 +1871,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ return ret; } + token_list = tplg_ops ? tplg_ops->token_list : NULL; if (!token_list) goto out; @@ -2093,16 +2109,18 @@ static int sof_set_pipe_widget(struct snd_sof_dev *sdev, struct snd_sof_widget * static int sof_complete(struct snd_soc_component *scomp) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_widget *swidget, *comp_swidget; - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_sof_control *scontrol; int ret; + widget_ops = tplg_ops ? tplg_ops->widget : NULL; + /* first update all control IPC structures based on the IPC version */ - if (ipc_tplg_ops->control_setup) + if (tplg_ops && tplg_ops->control_setup) list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { - ret = ipc_tplg_ops->control_setup(sdev, scontrol); + ret = tplg_ops->control_setup(sdev, scontrol); if (ret < 0) { dev_err(sdev->dev, "failed updating IPC struct for control %s\n", scontrol->name); @@ -2116,7 +2134,7 @@ static int sof_complete(struct snd_soc_component *scomp) * associated memories. */ list_for_each_entry(swidget, &sdev->widget_list, list) { - if (widget_ops[swidget->id].ipc_setup) { + if (widget_ops && widget_ops[swidget->id].ipc_setup) { ret = widget_ops[swidget->id].ipc_setup(swidget); if (ret < 0) { dev_err(sdev->dev, "failed updating IPC struct for %s\n", @@ -2148,15 +2166,16 @@ static int sof_complete(struct snd_soc_component *scomp) /* verify topology components loading including dynamic pipelines */ if (sof_debug_check_flag(SOF_DBG_VERIFY_TPLG)) { - if (ipc_tplg_ops->set_up_all_pipelines && ipc_tplg_ops->tear_down_all_pipelines) { - ret = ipc_tplg_ops->set_up_all_pipelines(sdev, true); + if (tplg_ops && tplg_ops->set_up_all_pipelines && + tplg_ops->tear_down_all_pipelines) { + ret = tplg_ops->set_up_all_pipelines(sdev, true); if (ret < 0) { dev_err(sdev->dev, "Failed to set up all topology pipelines: %d\n", ret); return ret; } - ret = ipc_tplg_ops->tear_down_all_pipelines(sdev, true); + ret = tplg_ops->tear_down_all_pipelines(sdev, true); if (ret < 0) { dev_err(sdev->dev, "Failed to tear down topology pipelines: %d\n", ret); @@ -2166,8 +2185,8 @@ static int sof_complete(struct snd_soc_component *scomp) } /* set up static pipelines */ - if (ipc_tplg_ops->set_up_all_pipelines) - return ipc_tplg_ops->set_up_all_pipelines(sdev, false); + if (tplg_ops && tplg_ops->set_up_all_pipelines) + return tplg_ops->set_up_all_pipelines(sdev, false); return 0; } @@ -2177,10 +2196,10 @@ static int sof_manifest(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_manifest *man) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (ipc_tplg_ops->parse_manifest) - return ipc_tplg_ops->parse_manifest(scomp, index, man); + if (tplg_ops && tplg_ops->parse_manifest) + return tplg_ops->parse_manifest(scomp, index, man); return 0; } From 9817ee9d8155b0cd019ed8670eceb2ff06561012 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 11 Oct 2022 12:42:07 +0300 Subject: [PATCH 20/30] ASoC: SOF: pm: Extend the optionality of IPC ops to IPC as well The IPC ops are optional, but they require that the ops struct is to be allocated with all callbacks set to NULL. Update the code to extend the optionality to: sdev->ipc == NULL sdev->ipc->ops == NULL sdev->ipc->ops->[pm/tplg] == NULL (treated optional for pm currently) sdev->ipc->ops->[pm/tplg]->ops == NULL (treated optional currently) Signed-off-by: Peter Ujfalusi --- sound/soc/sof/pm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index d4615d8cf674f3..fd450eac4f7e07 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -73,8 +73,8 @@ static void sof_cache_debugfs(struct snd_sof_dev *sdev) static int sof_resume(struct device *dev, bool runtime_resume) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); - const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm); + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); u32 old_state = sdev->dsp_power_state.state; int ret; @@ -155,7 +155,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) } /* restore pipelines */ - if (tplg_ops->set_up_all_pipelines) { + if (tplg_ops && tplg_ops->set_up_all_pipelines) { ret = tplg_ops->set_up_all_pipelines(sdev, false); if (ret < 0) { dev_err(sdev->dev, "Failed to restore pipeline after resume %d\n", ret); @@ -179,8 +179,8 @@ static int sof_resume(struct device *dev, bool runtime_resume) static int sof_suspend(struct device *dev, bool runtime_suspend) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); - const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm); + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); pm_message_t pm_state; u32 target_state = 0; int ret; @@ -209,7 +209,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) target_state = snd_sof_dsp_power_target(sdev); pm_state.event = target_state; - if (tplg_ops->tear_down_all_pipelines) + if (tplg_ops && tplg_ops->tear_down_all_pipelines) tplg_ops->tear_down_all_pipelines(sdev, false); /* Skip to platform-specific suspend if DSP is entering D0 */ @@ -277,7 +277,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev) { - const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; + const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm); /* Notify DSP of upcoming power down */ if (sof_ops(sdev)->remove && pm_ops && pm_ops->ctx_save) From 4735c752992bc9f8917e5187b2f58507a9579335 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 12 Oct 2022 12:42:25 +0300 Subject: [PATCH 21/30] ASoC: SOF: sof-priv: Mark fw_tracing ops optional in documentation The code treats the fw_tracing as optional feature but the documentation was not reflecting this. Correct it by explicitly stating that the fw_tracing is optional. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/sof-priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 977a514cf32e12..bd0d910e4ee282 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -436,7 +436,7 @@ struct sof_ipc_pcm_ops; * @pm: Pointer to PM ops * @pcm: Pointer to PCM ops * @fw_loader: Pointer to Firmware Loader ops - * @fw_tracing: Pointer to Firmware tracing ops + * @fw_tracing: Optional pointer to Firmware tracing ops * * @init: Optional pointer for IPC related initialization * @exit: Optional pointer for IPC related cleanup From 5bbe6a56a6209bf7031c80cb0c5301f486e5f971 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 11 Oct 2022 14:46:32 +0300 Subject: [PATCH 22/30] ASoC: SOF: trace: Use sof_ipc_get_ops() in sof_fw_trace_init For the sake of safety use the sof_ipc_get_ops() to fetch the fw_tracing ops to avoid cases when either sdev->ipc or sdev->ipc->ops might be NULL. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/trace.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 6f662642d61159..0e92269c4a003c 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -6,14 +6,16 @@ int sof_fw_trace_init(struct snd_sof_dev *sdev) { - if (!sdev->ipc->ops->fw_tracing) { + const struct sof_ipc_fw_tracing_ops *fw_tracing = sof_ipc_get_ops(sdev, fw_tracing); + + if (!fw_tracing) { dev_info(sdev->dev, "Firmware tracing is not available\n"); sdev->fw_trace_is_supported = false; return 0; } - return sdev->ipc->ops->fw_tracing->init(sdev); + return fw_tracing->init(sdev); } void sof_fw_trace_free(struct snd_sof_dev *sdev) From d9e124c370e5271678d8470aabb57f8ab9e88ca7 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 11 Oct 2022 14:48:34 +0300 Subject: [PATCH 23/30] ASoC: SOF: trace: No need to check for op pointer in sof_fw_trace_free() If the sdev->fw_trace_is_supported is true then we must have the fw_tracing ops set, no need to check again. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 0e92269c4a003c..b2ab51e5214a93 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -20,7 +20,7 @@ int sof_fw_trace_init(struct snd_sof_dev *sdev) void sof_fw_trace_free(struct snd_sof_dev *sdev) { - if (!sdev->fw_trace_is_supported || !sdev->ipc->ops->fw_tracing) + if (!sdev->fw_trace_is_supported) return; if (sdev->ipc->ops->fw_tracing->free) From 123589b3d348f4aa7c61d175dfc335d7a1bb9226 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 7 Oct 2022 15:25:00 +0300 Subject: [PATCH 24/30] ASoC: SOF: pm: Determine the target state earlier on suspend To make sure that a correct target state is determined even if the DSP failed to boot or the firmware crashed or the suspend happens when the fw_state is not SOF_FW_BOOT_COMPLETE we must select the correct target state earlier. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/pm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index fd450eac4f7e07..d60ecdf944b5ef 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -192,6 +192,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) if (runtime_suspend && !sof_ops(sdev)->runtime_suspend) return 0; + target_state = snd_sof_dsp_power_target(sdev); + pm_state.event = target_state; + if (sdev->fw_state != SOF_FW_BOOT_COMPLETE) goto suspend; @@ -206,9 +209,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) } } - target_state = snd_sof_dsp_power_target(sdev); - pm_state.event = target_state; - if (tplg_ops && tplg_ops->tear_down_all_pipelines) tplg_ops->tear_down_all_pipelines(sdev, false); From 05e23b54901a5673d6498cd2f00ad18e0a5c550f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sun, 9 Oct 2022 10:08:02 -0700 Subject: [PATCH 25/30] ASoC: SOF: sof-audio: skip prepapre/unprepare if swidget is NULL Skip preparing/unpreparing widgets if the swidget pointer is NULL. This will be true in the case of virtual widgets in topology that were added for reusing the legacy HDA machine driver with SOF. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/sof-audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 3798f627094b87..8e951531fefec1 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -283,7 +283,7 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg struct snd_soc_dapm_path *p; /* return if the widget is in use or if it is already unprepared */ - if (!swidget->prepared || swidget->use_count > 1) + if (!swidget || !swidget->prepared || swidget->use_count > 1) return; widget_ops = tplg_ops ? tplg_ops->widget : NULL; @@ -322,7 +322,7 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget if (!widget_ops) return 0; - if (!widget_ops[widget->id].ipc_prepare || swidget->prepared) + if (!swidget || !widget_ops[widget->id].ipc_prepare || swidget->prepared) goto sink_prepare; /* prepare the source widget */ From 62de37eccfa0e471ce2dbe454b0d81c5c335e6f2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 11 Oct 2022 16:18:26 +0300 Subject: [PATCH 26/30] ASoC: SOF: Add flag and state which will be used for DSP-less mode The DSPless mode of the ASoC/SOF driver can be used for hardware verification and debug on platforms with HDaudio codecs. The DSP mode is still needed on existing platforms for SSP, DMIC, SoundWire interfaces managed by the GP-DMA. This mode is also helpful to compare the legacy HDaudio driver with the ASoC/SOF driver wrt. codec management and handling. In theory we use the same code but differences are sometimes seen on jack detection and event handling. Signed-off-by: Peter Ujfalusi --- include/sound/sof.h | 5 +++++ sound/soc/sof/core.c | 10 ++++++++++ sound/soc/sof/sof-priv.h | 1 + 3 files changed, 16 insertions(+) diff --git a/include/sound/sof.h b/include/sound/sof.h index 266e66318f9cfd..d3c41f87ac3191 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -21,6 +21,7 @@ struct snd_sof_dev; /** * enum sof_fw_state - DSP firmware state definitions * @SOF_FW_BOOT_NOT_STARTED: firmware boot is not yet started + * @SOF_DSPLESS_MODE: DSP is not used * @SOF_FW_BOOT_PREPARE: preparing for boot (firmware loading for exaqmple) * @SOF_FW_BOOT_IN_PROGRESS: firmware boot is in progress * @SOF_FW_BOOT_FAILED: firmware boot failed @@ -31,6 +32,7 @@ struct snd_sof_dev; */ enum sof_fw_state { SOF_FW_BOOT_NOT_STARTED = 0, + SOF_DSPLESS_MODE, SOF_FW_BOOT_PREPARE, SOF_FW_BOOT_IN_PROGRESS, SOF_FW_BOOT_FAILED, @@ -130,6 +132,9 @@ struct sof_dev_desc { unsigned int ipc_supported_mask; enum sof_ipc_type ipc_default; + /* The platform supports DSPless mode */ + bool dspless_mode_supported; + /* defaults paths for firmware, library and topology files */ const char *default_fw_path[SOF_IPC_TYPE_COUNT]; const char *default_lib_path[SOF_IPC_TYPE_COUNT]; diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 8d128d152cecd6..c8ad729a581e62 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -362,6 +362,16 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sdev->first_boot = true; dev_set_drvdata(dev, sdev); + if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) { + if (plat_data->desc->dspless_mode_supported) { + dev_info(dev, "Switching to DSPless mode\n"); + } else { + dev_info(dev, "DSPless mode is not supported by the platform\n"); + /* Clear the DSPless mode flag, it is not supported */ + sof_core_debug &= ~SOF_DBG_DSPLESS_MODE; + } + } + if (sof_core_debug) dev_info(dev, "sof_debug value: %#x\n", sof_core_debug); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index bd0d910e4ee282..5d35a402be0859 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -46,6 +46,7 @@ #define SOF_DBG_FORCE_NOCODEC BIT(10) /* ignore all codec-related * configurations */ +#define SOF_DBG_DSPLESS_MODE BIT(15) /* Do not initialize and use the DSP */ /* Flag definitions used for controlling the DSP dump behavior */ #define SOF_DBG_DUMP_REGS BIT(0) From 02408551a95b98c644ab07b90cb65e359d2016b2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 14 Jul 2022 15:26:54 +0300 Subject: [PATCH 27/30] ASoC: SOF: Add support for DSPless mode Via the SOF_DBG_DSPLESS_MODE sof_debug flag the SOF stack can be asked to not use the DSP for audio. The core's support for DSPless mode is only going to be enabled if the platform reports that it can be used without DSP. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 20 +++++++-- sound/soc/sof/debug.c | 1 + sound/soc/sof/pcm.c | 3 +- sound/soc/sof/pm.c | 5 +++ sound/soc/sof/sof-client.c | 3 ++ sound/soc/sof/topology.c | 86 +++++++++++++++++++++++++++++++++++++- 6 files changed, 112 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index c8ad729a581e62..142470fd0bfa24 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -208,6 +208,11 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) /* set up platform component driver */ snd_sof_new_platform_drv(sdev); + if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) { + sof_set_fw_state(sdev, SOF_DSPLESS_MODE); + goto skip_dsp_init; + } + /* register any debug/trace capabilities */ ret = snd_sof_dbg_init(sdev); if (ret < 0) { @@ -266,6 +271,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "SOF firmware trace disabled\n"); } +skip_dsp_init: /* hereafter all FW boot flows are for PM reasons */ sdev->first_boot = false; @@ -388,15 +394,21 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) return ret; /* check all mandatory ops */ - if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run || - !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || - !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || - !sof_ops(sdev)->ipc_msg_data) { + if (!sof_ops(sdev) || !sof_ops(sdev)->probe) { sof_ops_free(sdev); dev_err(dev, "error: missing mandatory ops\n"); return -EINVAL; } + if (!sof_debug_check_flag(SOF_DBG_DSPLESS_MODE) && + (!sof_ops(sdev)->run || !sof_ops(sdev)->block_read || + !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg || + !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data)) { + sof_ops_free(sdev); + dev_err(dev, "error: missing mandatory DSP ops\n"); + return -EINVAL; + } + INIT_LIST_HEAD(&sdev->pcm_list); INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index d9a3ce7b69e16c..bbf7202c36facf 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -368,6 +368,7 @@ static const struct soc_fw_state_info { const char *name; } fw_state_dbg[] = { {SOF_FW_BOOT_NOT_STARTED, "SOF_FW_BOOT_NOT_STARTED"}, + {SOF_DSPLESS_MODE, "SOF_DSPLESS_MODE"}, {SOF_FW_BOOT_PREPARE, "SOF_FW_BOOT_PREPARE"}, {SOF_FW_BOOT_IN_PROGRESS, "SOF_FW_BOOT_IN_PROGRESS"}, {SOF_FW_BOOT_FAILED, "SOF_FW_BOOT_FAILED"}, diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 34d40c5c629a2b..5c5564b17a657c 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -677,7 +677,8 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) pd->pcm_construct = sof_pcm_new; pd->ignore_machine = drv_name; - pd->be_hw_params_fixup = sof_pcm_dai_link_fixup; + if (!sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) + pd->be_hw_params_fixup = sof_pcm_dai_link_fixup; pd->be_pcm_base = SOF_BE_PCM_BASE; pd->use_dai_pcm_id = true; pd->topology_name_prefix = "sof"; diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index d60ecdf944b5ef..e317ac96d5a0a6 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -103,6 +103,11 @@ static int sof_resume(struct device *dev, bool runtime_resume) return ret; } + if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) { + sof_set_fw_state(sdev, SOF_DSPLESS_MODE); + return 0; + } + /* * Nothing further to be done for platforms that support the low power * D0 substate. Resume trace and return when resuming from diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 9017f0864cdda3..04bda9de404cd2 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -130,6 +130,9 @@ int sof_register_clients(struct snd_sof_dev *sdev) { int ret; + if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) + return 0; + /* Register platform independent client devices */ ret = sof_register_ipc_flood_test(sdev); if (ret) { diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 4c34bb3e87b753..a57438d8283dc3 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1171,6 +1171,9 @@ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, { struct snd_sof_widget *host_widget; + if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) + return 0; + host_widget = snd_sof_find_swidget_sname(scomp, spcm->pcm.caps[dir].name, dir); @@ -2255,6 +2258,83 @@ static struct snd_soc_tplg_ops sof_tplg_ops = { .bytes_ext_ops_count = ARRAY_SIZE(sof_bytes_ext_ops), }; +static int snd_sof_dspless_kcontrol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +static const struct snd_soc_tplg_kcontrol_ops sof_dspless_io_ops[] = { + {SOF_TPLG_KCTL_VOL_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol}, + {SOF_TPLG_KCTL_BYTES_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol}, + {SOF_TPLG_KCTL_ENUM_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol}, + {SOF_TPLG_KCTL_SWITCH_ID, snd_sof_dspless_kcontrol, snd_sof_dspless_kcontrol}, +}; + +static int snd_sof_dspless_bytes_ext_get(struct snd_kcontrol *kcontrol, + unsigned int __user *binary_data, + unsigned int size) +{ + return 0; +} + +static int snd_sof_dspless_bytes_ext_put(struct snd_kcontrol *kcontrol, + const unsigned int __user *binary_data, + unsigned int size) +{ + return 0; +} + +static const struct snd_soc_tplg_bytes_ext_ops sof_dspless_bytes_ext_ops[] = { + {SOF_TPLG_KCTL_BYTES_ID, snd_sof_dspless_bytes_ext_get, snd_sof_dspless_bytes_ext_put}, + {SOF_TPLG_KCTL_BYTES_VOLATILE_RO, snd_sof_dspless_bytes_ext_get}, +}; + +/* external widget init - used for any driver specific init */ +static int sof_dspless_widget_ready(struct snd_soc_component *scomp, int index, + struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tw) +{ + if (WIDGET_IS_DAI(w->id)) { + struct snd_sof_dai dai; + + memset(&dai, 0, sizeof(dai)); + + return sof_connect_dai_widget(scomp, w, tw, &dai); + } + + return 0; +} + +static int sof_dspless_widget_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj); + + if (WIDGET_IS_DAI(w->id)) + sof_disconnect_dai_widget(scomp, w); + + return 0; +} + +static struct snd_soc_tplg_ops sof_dspless_tplg_ops = { + /* external widget init - used for any driver specific init */ + .widget_ready = sof_dspless_widget_ready, + .widget_unload = sof_dspless_widget_unload, + + /* FE DAI - used for any driver specific init */ + .dai_load = sof_dai_load, + .dai_unload = sof_dai_unload, + + /* vendor specific kcontrol handlers available for binding */ + .io_ops = sof_dspless_io_ops, + .io_ops_count = ARRAY_SIZE(sof_dspless_io_ops), + + /* vendor specific bytes ext handlers available for binding */ + .bytes_ext_ops = sof_dspless_bytes_ext_ops, + .bytes_ext_ops_count = ARRAY_SIZE(sof_dspless_bytes_ext_ops), +}; + int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); @@ -2272,7 +2352,11 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) return ret; } - ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw); + if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) + ret = snd_soc_tplg_component_load(scomp, &sof_dspless_tplg_ops, fw); + else + ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw); + if (ret < 0) { dev_err(scomp->dev, "error: tplg component load failed %d\n", ret); From e6e0315c77b58c39eda4f4875f3fd470ac195483 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 12 Oct 2022 13:54:17 +0300 Subject: [PATCH 28/30] ASoC: SOF: Intel: hda: Add support for DSPless mode Via the SOF_DBG_DSPLESS_MODE sof_debug flag the SOF stack can be asked to not use the DSP for audio. The use of DSPless mode is governed by the SOF_DBG_DSPLESS_MODE flag which is only going to be set if the user sets sof_debg=0x8000 and the platform advertises that the DSPless mode is supported (tested) on them. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda-dai.c | 100 ++++++++++++++++++++++++++++++- sound/soc/sof/intel/hda-pcm.c | 5 +- sound/soc/sof/intel/hda-stream.c | 35 ++++++----- sound/soc/sof/intel/hda.c | 3 + 4 files changed, 126 insertions(+), 17 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 98eebb4b07e6d3..29f65fc7dad7e1 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -603,6 +603,88 @@ static const struct snd_soc_dai_ops ipc4_hda_dai_ops = { .prepare = hda_dai_prepare, }; +static int dspless_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); + 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_bus *bus = hstream->bus; + struct hdac_ext_link *hlink; + int sig_bits; + + hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); + if (!hlink) + return -EINVAL; + + /* set the hdac_stream in the codec dai */ + snd_soc_dai_set_stream(codec_dai, hdac_stream(hext_stream), substream->stream); + + if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) { + snd_hdac_ext_bus_link_set_stream_id(hlink, hstream->stream_tag); + } else { + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + sig_bits = codec_dai->driver->playback.sig_bits; + else + sig_bits = codec_dai->driver->capture.sig_bits; + + /* Save the format required for the codec */ + hstream->format_val = snd_hdac_calc_stream_format(params_rate(params), + params_channels(params), + params_format(params), + sig_bits, 0); + hext_stream->link_prepared = 1; + + return 0; +} + +static int dspless_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); + 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_bus *bus = hstream->bus; + struct hdac_ext_link *hlink; + + hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); + if (!hlink) + return -EINVAL; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_hdac_ext_bus_link_clear_stream_id(hlink, hstream->stream_tag); + + hext_stream->link_prepared = 0; + + return 0; +} + +static const struct snd_soc_dai_ops dspless_hda_dai_ops = { + .hw_params = dspless_hda_dai_hw_params, + .hw_free = dspless_hda_dai_hw_free, +}; + +static int dspless_hda_dai_suspend(struct hdac_bus *bus) +{ + struct hdac_ext_stream *hext_stream; + struct hdac_stream *s; + + /* set internal flag for BE */ + list_for_each_entry(s, &bus->stream_list, list) { + hext_stream = stream_to_hdac_ext_stream(s); + + if (hext_stream->link_substream) + hext_stream->link_prepared = 0; + } + + return 0; +} + #endif /* only one flag used so far to harden hw_params/hw_free/trigger/prepare */ @@ -718,6 +800,18 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) { int i; + if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + for (i = 0; i < ops->num_drv; i++) { + if (strstr(ops->drv[i].name, "iDisp") || + strstr(ops->drv[i].name, "Analog") || + strstr(ops->drv[i].name, "Digital")) + ops->drv[i].ops = &dspless_hda_dai_ops; + } +#endif + return; + } + switch (sdev->pdata->ipc_type) { case SOF_IPC: for (i = 0; i < ops->num_drv; i++) { @@ -929,7 +1023,11 @@ int hda_dsp_dais_suspend(struct snd_sof_dev *sdev) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) int ret; - ret = hda_dai_suspend(sof_to_bus(sdev)); + if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) + ret = dspless_hda_dai_suspend(sof_to_bus(sdev)); + else + ret = hda_dai_suspend(sof_to_bus(sdev)); + if (ret < 0) return ret; #endif diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index dc0b359ed9b6cc..ab0135c661a41b 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -111,7 +111,10 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, dmab = substream->runtime->dma_buffer_p; - hstream->format_val = rate | bits | (params_channels(params) - 1); + /* Use the codec required format val when the DSP is not in use */ + if (!sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) + hstream->format_val = rate | bits | (params_channels(params) - 1); + hstream->bufsize = size; hstream->period_bytes = params_period_bytes(params); hstream->no_period_wakeup = diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 8e3f058576326a..5146c724770de6 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -480,7 +480,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, int sd_offset = SOF_STREAM_SD_OFFSET(hstream); int ret; u32 dma_start = SOF_HDA_SD_CTL_DMA_START; - u32 mask; + u32 mask = 0x1 << hstream->index; u32 run; if (!hext_stream) { @@ -493,10 +493,10 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, return -ENODEV; } - /* decouple host and link DMA */ - mask = 0x1 << hstream->index; - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - mask, mask); + /* decouple host and link DMA if the DSP is used */ + if (!sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + mask, mask); /* clear stream status */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, @@ -597,7 +597,8 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, * enable decoupled mode */ - if (chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK) { + if ((!sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) && + chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK) { /* couple host and link DMA, disable DSP features */ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, mask, 0); @@ -609,7 +610,8 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, SOF_HDA_ADSP_REG_SD_FORMAT, 0xffff, hstream->format_val); - if (chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK) { + if ((!sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) && + chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK) { /* decouple host and link DMA, enable DSP features */ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, mask, mask); @@ -666,20 +668,23 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream = container_of(hstream, struct hdac_ext_stream, hstream); - struct hdac_bus *bus = sof_to_bus(sdev); - u32 mask = 0x1 << hstream->index; int ret; ret = hda_dsp_stream_reset(sdev, hstream); if (ret < 0) return ret; - spin_lock_irq(&bus->reg_lock); - /* couple host and link DMA if link DMA channel is idle */ - if (!hext_stream->link_locked) - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, - SOF_HDA_REG_PP_PPCTL, mask, 0); - spin_unlock_irq(&bus->reg_lock); + if (!sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) { + struct hdac_bus *bus = sof_to_bus(sdev); + u32 mask = 0x1 << hstream->index; + + spin_lock_irq(&bus->reg_lock); + /* couple host and link DMA if link DMA channel is idle */ + if (!hext_stream->link_locked) + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, + SOF_HDA_REG_PP_PPCTL, mask, 0); + spin_unlock_irq(&bus->reg_lock); + } hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 99be5ef7832403..21af9e48eb9fb6 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1046,6 +1046,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) hdev->no_ipc_position = sof_ops(sdev)->pcm_pointer ? 1 : 0; #endif + if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE)) + hdev->no_ipc_position = 1; + /* set up HDA base */ bus = sof_to_bus(sdev); ret = hda_init(sdev); From 6b56063741c7da77bea5abc60205637424c879ed Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 12 Oct 2022 13:55:49 +0300 Subject: [PATCH 29/30] ASoC: SOF: Intel: pci-tgl: Allow DSPless mode set the dspless_mode_supported flag to true for tgl family to allow DSPless mode. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/pci-tgl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index e80c4dfef85a58..932e25e10b40b6 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -30,6 +30,7 @@ static const struct sof_dev_desc tgl_desc = { .chip_info = &tgl_chip_info, .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_default = SOF_IPC, + .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/tgl", @@ -61,6 +62,7 @@ static const struct sof_dev_desc tglh_desc = { .chip_info = &tglh_chip_info, .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_default = SOF_IPC, + .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/tgl-h", @@ -92,6 +94,7 @@ static const struct sof_dev_desc ehl_desc = { .chip_info = &ehl_chip_info, .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_default = SOF_IPC, + .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/ehl", @@ -123,6 +126,7 @@ static const struct sof_dev_desc adls_desc = { .chip_info = &adls_chip_info, .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_default = SOF_IPC, + .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/adl-s", @@ -154,6 +158,7 @@ static const struct sof_dev_desc adl_desc = { .chip_info = &tgl_chip_info, .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_default = SOF_IPC, + .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/adl", @@ -216,6 +221,7 @@ static const struct sof_dev_desc rpls_desc = { .chip_info = &adls_chip_info, .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_default = SOF_IPC, + .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/rpl-s", @@ -247,6 +253,7 @@ static const struct sof_dev_desc rpl_desc = { .chip_info = &tgl_chip_info, .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_default = SOF_IPC, + .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/rpl", From 342120625c898d1204f78919c1040d923e2a7229 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 12 Oct 2022 13:56:03 +0300 Subject: [PATCH 30/30] ASoC: SOF: Intel: pci-apl: Allow DSPless mode set the dspless_mode_supported flag to true for apl family to allow DSPless mode. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/pci-apl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index 69279dcc92dc13..a54be4f7bf24ed 100644 --- a/sound/soc/sof/intel/pci-apl.c +++ b/sound/soc/sof/intel/pci-apl.c @@ -29,6 +29,7 @@ static const struct sof_dev_desc bxt_desc = { .chip_info = &apl_chip_info, .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_default = SOF_IPC, + .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/apl", @@ -60,6 +61,7 @@ static const struct sof_dev_desc glk_desc = { .chip_info = &apl_chip_info, .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), .ipc_default = SOF_IPC, + .dspless_mode_supported = true, /* Only supported for HDaudio */ .default_fw_path = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/glk",