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: diff --git a/include/sound/intel-nhlt.h b/include/sound/intel-nhlt.h index 53470d6a28d659..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 { @@ -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/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/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/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 2c4dfc0b7e342c..7d4f0ae8a39837 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; @@ -55,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; @@ -188,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 @@ -240,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; 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, + }, }, {}, }; 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; diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 3e6141d03770fc..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; @@ -362,6 +368,19 @@ 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); + /* 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", @@ -375,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/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); 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", 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", 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); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 7ea83cfb19ed6c..5c5564b17a657c 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; @@ -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 d4615d8cf674f3..e317ac96d5a0a6 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; @@ -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 @@ -155,7 +160,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 +184,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; @@ -192,6 +197,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,10 +214,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 +282,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) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 9b09b5599ec477..8e951531fefec1 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,12 +169,11 @@ 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; 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 (tplg_ops && tplg_ops->route_setup) { + int ret = tplg_ops->route_setup(sdev, sroute); + + if (ret < 0) + return ret; + } sroute->setup = true; return 0; @@ -275,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) + if (!swidget || !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); @@ -309,13 +312,17 @@ 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; - if (!widget_ops[widget->id].ipc_prepare || swidget->prepared) + widget_ops = tplg_ops ? tplg_ops->widget : NULL; + if (!widget_ops) + return 0; + + if (!swidget || !widget_ops[widget->id].ipc_prepare || swidget->prepared) goto sink_prepare; /* prepare the source widget */ @@ -524,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; @@ -578,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; @@ -670,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; @@ -804,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; 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; 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/sof-priv.h b/sound/soc/sof/sof-priv.h index eb1192dbdfb61c..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) @@ -70,14 +71,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 @@ -444,7 +437,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 @@ -502,6 +495,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. */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 0160d2cf0b7e55..a57438d8283dc3 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); } @@ -1165,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); @@ -1198,12 +1207,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 +1386,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 +1451,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 +1539,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 +1579,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 +1640,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 +1669,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 +1698,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 +1782,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 +1793,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 +1813,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 +1827,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 +1874,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 +2112,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 +2137,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 +2169,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 +2188,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 +2199,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; } @@ -2236,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); @@ -2253,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); diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 6f662642d61159..b2ab51e5214a93 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -6,19 +6,21 @@ 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) { - 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)