summaryrefslogtreecommitdiff
path: root/sound/soc/sof
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof')
-rw-r--r--sound/soc/sof/Kconfig2
-rw-r--r--sound/soc/sof/amd/pci-acp70.c1
-rw-r--r--sound/soc/sof/control.c1
-rw-r--r--sound/soc/sof/debug.c1
-rw-r--r--sound/soc/sof/imx/imx-common.c36
-rw-r--r--sound/soc/sof/intel/hda-loader.c7
-rw-r--r--sound/soc/sof/intel/hda.c5
-rw-r--r--sound/soc/sof/intel/ptl.c1
-rw-r--r--sound/soc/sof/ipc3-dtrace.c1
-rw-r--r--sound/soc/sof/ipc4-loader.c7
-rw-r--r--sound/soc/sof/ipc4-pcm.c137
-rw-r--r--sound/soc/sof/ipc4-priv.h6
-rw-r--r--sound/soc/sof/ipc4-topology.c94
-rw-r--r--sound/soc/sof/ipc4-topology.h25
-rw-r--r--sound/soc/sof/ipc4.c39
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186.c11
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195.c11
-rw-r--r--sound/soc/sof/pcm.c27
-rw-r--r--sound/soc/sof/sof-client-ipc-flood-test.c1
-rw-r--r--sound/soc/sof/sof-client-ipc-kernel-injector.c1
-rw-r--r--sound/soc/sof/sof-client-ipc-msg-injector.c1
-rw-r--r--sound/soc/sof/sof-client-probes.c3
-rw-r--r--sound/soc/sof/topology.c15
23 files changed, 322 insertions, 111 deletions
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig
index 32ffd345e07f..a487ab0b51c7 100644
--- a/sound/soc/sof/Kconfig
+++ b/sound/soc/sof/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig SND_SOC_SOF_TOPLEVEL
- bool "Sound Open Firmware Support"
+ bool "Sound Open Firmware (SOF) platforms"
help
This adds support for Sound Open Firmware (SOF). SOF is free and
generic open source audio DSP firmware for multiple devices.
diff --git a/sound/soc/sof/amd/pci-acp70.c b/sound/soc/sof/amd/pci-acp70.c
index c4db21668252..51d36d43c42b 100644
--- a/sound/soc/sof/amd/pci-acp70.c
+++ b/sound/soc/sof/amd/pci-acp70.c
@@ -48,6 +48,7 @@ static const struct sof_amd_acp_desc acp70_chip_info = {
static const struct sof_dev_desc acp70_desc = {
.machines = snd_soc_acpi_amd_acp70_sof_machines,
+ .alt_machines = snd_soc_acpi_amd_acp70_sof_sdw_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = -1,
.resindex_imr_base = -1,
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c
index 463d418e7200..a3fd1d523c09 100644
--- a/sound/soc/sof/control.c
+++ b/sound/soc/sof/control.c
@@ -196,7 +196,6 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
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);
err = pm_runtime_put_autosuspend(scomp->dev);
if (err < 0)
dev_err_ratelimited(scomp->dev, "%s: failed to idle %d\n", __func__, err);
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index d0ffa1d71145..b24943a65c89 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -217,7 +217,6 @@ static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_s
}
ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
- pm_runtime_mark_last_busy(sdev->dev);
pm_runtime_put_autosuspend(sdev->dev);
if (ret < 0 || reply->rhdr.error < 0) {
ret = min(ret, reply->rhdr.error);
diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c
index 62bf707aa909..f00b381cec3b 100644
--- a/sound/soc/sof/imx/imx-common.c
+++ b/sound/soc/sof/imx/imx-common.c
@@ -282,11 +282,8 @@ static int imx_region_name_to_blk_type(const char *region_name)
static int imx_parse_ioremap_memory(struct snd_sof_dev *sdev)
{
const struct imx_chip_info *chip_info;
- struct reserved_mem *reserved;
struct platform_device *pdev;
- struct device_node *res_np;
- phys_addr_t base, size;
- struct resource *res;
+ struct resource *res, _res;
int i, blk_type, ret;
pdev = to_platform_device(sdev->dev);
@@ -307,37 +304,18 @@ static int imx_parse_ioremap_memory(struct snd_sof_dev *sdev)
"failed to fetch %s resource\n",
chip_info->memory[i].name);
- base = res->start;
- size = resource_size(res);
} else {
- ret = of_property_match_string(pdev->dev.of_node,
- "memory-region-names",
- chip_info->memory[i].name);
+ ret = of_reserved_mem_region_to_resource_byname(pdev->dev.of_node,
+ chip_info->memory[i].name,
+ &_res);
if (ret < 0)
return dev_err_probe(sdev->dev, ret,
- "no valid index for %s\n",
+ "no valid entry for %s\n",
chip_info->memory[i].name);
-
- res_np = of_parse_phandle(pdev->dev.of_node,
- "memory-region",
- ret);
- if (!res_np)
- return dev_err_probe(sdev->dev, -ENODEV,
- "failed to parse phandle %s\n",
- chip_info->memory[i].name);
-
- reserved = of_reserved_mem_lookup(res_np);
- of_node_put(res_np);
- if (!reserved)
- return dev_err_probe(sdev->dev, -ENODEV,
- "failed to get %s reserved\n",
- chip_info->memory[i].name);
-
- base = reserved->base;
- size = reserved->size;
+ res = &_res;
}
- sdev->bar[blk_type] = devm_ioremap(sdev->dev, base, size);
+ sdev->bar[blk_type] = devm_ioremap_resource(sdev->dev, res);
if (!sdev->bar[blk_type])
return dev_err_probe(sdev->dev,
-ENOMEM,
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 49085ca7b46b..2cc11d8b0f70 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -579,8 +579,11 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
struct sof_ipc4_msg msg = {};
int ret, ret1;
- /* if IMR booting is enabled and fw context is saved for D3 state, skip the loading */
- if (reload && hda->booted_from_imr && ipc4_data->fw_context_save)
+ /*
+ * if IMR booting is enabled and libraries have been restored during fw
+ * boot, skip the loading
+ */
+ if (reload && hda->booted_from_imr && ipc4_data->libraries_restored)
return 0;
/* the fw_lib has been verified during loading, we can trust the validity here */
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 3b47191ea7a5..c387efec41e9 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -629,6 +629,11 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
goto skip_soundwire;
+ /* Skip SoundWire in nocodec mode */
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ goto skip_soundwire;
+
/* scan SoundWire capabilities exposed by DSDT */
ret = hda_sdw_acpi_scan(sdev);
if (ret < 0) {
diff --git a/sound/soc/sof/intel/ptl.c b/sound/soc/sof/intel/ptl.c
index 875d18193b05..1bc1f54c470d 100644
--- a/sound/soc/sof/intel/ptl.c
+++ b/sound/soc/sof/intel/ptl.c
@@ -117,6 +117,7 @@ const struct sof_intel_dsp_desc ptl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_ext,
.check_sdw_irq = lnl_dsp_check_sdw_irq,
.check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
.check_ipc_irq = mtl_dsp_check_ipc_irq,
.check_mic_privacy_irq = sof_ptl_check_mic_privacy_irq,
.process_mic_privacy = sof_ptl_process_mic_privacy,
diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c
index 744a91a150bc..e5c8fec173c4 100644
--- a/sound/soc/sof/ipc3-dtrace.c
+++ b/sound/soc/sof/ipc3-dtrace.c
@@ -172,7 +172,6 @@ static int ipc3_trace_update_filter(struct snd_sof_dev *sdev, int num_elems,
goto error;
}
ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, msg->hdr.size);
- pm_runtime_mark_last_busy(sdev->dev);
pm_runtime_put_autosuspend(sdev->dev);
error:
diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c
index d2f534d65edf..b0d293f62d1c 100644
--- a/sound/soc/sof/ipc4-loader.c
+++ b/sound/soc/sof/ipc4-loader.c
@@ -236,7 +236,6 @@ static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long lib_id,
ret = ipc4_data->load_library(sdev, fw_lib, false);
- pm_runtime_mark_last_busy(sdev->dev);
err = pm_runtime_put_autosuspend(sdev->dev);
if (err < 0)
dev_err_ratelimited(sdev->dev, "%s: pm_runtime idle failed: %d\n",
@@ -494,6 +493,12 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
break;
case SOF_IPC4_FW_CONTEXT_SAVE:
ipc4_data->fw_context_save = *tuple->value;
+ /*
+ * Set the default libraries_restored value - if full
+ * context save is supported then it means that
+ * libraries are restored
+ */
+ ipc4_data->libraries_restored = ipc4_data->fw_context_save;
break;
default:
break;
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index 8eee3e1aadf9..374dc10d10fd 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -56,17 +56,41 @@ sof_ipc4_sps_to_time_info(struct snd_sof_pcm_stream *sps)
return stream_priv->time_info;
}
+static
+char *sof_ipc4_set_multi_pipeline_state_debug(struct snd_sof_dev *sdev, char *buf, size_t size,
+ struct ipc4_pipeline_set_state_data *trigger_list)
+{
+ int i, offset = 0;
+
+ for (i = 0; i < trigger_list->count; i++) {
+ offset += snprintf(buf + offset, size - offset, " %d",
+ trigger_list->pipeline_instance_ids[i]);
+
+ if (offset >= size - 1) {
+ buf[size - 1] = '\0';
+ break;
+ }
+ }
+ return buf;
+}
+
static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state,
struct ipc4_pipeline_set_state_data *trigger_list)
{
struct sof_ipc4_msg msg = {{ 0 }};
u32 primary, ipc_size;
+ char debug_buf[32];
/* trigger a single pipeline */
if (trigger_list->count == 1)
return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0],
state);
+ dev_dbg(sdev->dev, "Set pipelines %s to state %d%s",
+ sof_ipc4_set_multi_pipeline_state_debug(sdev, debug_buf, sizeof(debug_buf),
+ trigger_list),
+ state, sof_ipc4_pipeline_state_str(state));
+
primary = state;
primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
@@ -89,7 +113,8 @@ int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 s
struct sof_ipc4_msg msg = {{ 0 }};
u32 primary;
- dev_dbg(sdev->dev, "ipc4 set pipeline instance %d state %d", instance_id, state);
+ dev_dbg(sdev->dev, "Set pipeline %d to state %d%s", instance_id, state,
+ sof_ipc4_pipeline_state_str(state));
primary = state;
primary |= SOF_IPC4_GLB_PIPE_STATE_ID(instance_id);
@@ -409,9 +434,33 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
* If use_chain_dma attribute is set we proceed to chained DMA
* trigger function that handles the rest for the substream.
*/
- if (pipeline->use_chain_dma)
- return sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream,
- pipeline_list, state, cmd);
+ if (pipeline->use_chain_dma) {
+ struct sof_ipc4_timestamp_info *time_info;
+
+ time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]);
+
+ ret = sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream,
+ pipeline_list, state, cmd);
+ if (ret || !time_info)
+ return ret;
+
+ if (state == SOF_IPC4_PIPE_PAUSED) {
+ /*
+ * Record the DAI position for delay reporting
+ * To handle multiple pause/resume/xrun we need to add
+ * the positions to simulate how the firmware behaves
+ */
+ u64 pos = snd_sof_pcm_get_dai_frame_counter(sdev, component,
+ substream);
+
+ time_info->stream_end_offset += pos;
+ } else if (state == SOF_IPC4_PIPE_RESET) {
+ /* Reset the end offset as the stream is stopped */
+ time_info->stream_end_offset = 0;
+ }
+
+ return 0;
+ }
/* allocate memory for the pipeline data */
trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids,
@@ -557,12 +606,15 @@ static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component,
return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET, 0);
}
-static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name,
- struct snd_pcm_hw_params *params)
+static int ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev,
+ const char *link_name,
+ struct snd_pcm_hw_params *params)
{
struct snd_sof_dai_link *slink;
struct snd_sof_dai *dai;
bool dai_link_found = false;
+ int current_config = -1;
+ bool partial_match;
int i;
list_for_each_entry(slink, &sdev->dai_link_list, list) {
@@ -573,19 +625,50 @@ static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const
}
if (!dai_link_found)
- return;
+ return 0;
+ /*
+ * Find the first best matching hardware config:
+ * rate + format + channels are matching
+ * rate + channel are matching
+ *
+ * The copier cannot do rate and/or channel conversion.
+ */
for (i = 0; i < slink->num_hw_configs; i++) {
struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i];
- if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) {
- /* set current config for all DAI's with matching name */
- list_for_each_entry(dai, &sdev->dai_list, list)
- if (!strcmp(slink->link->name, dai->name))
- dai->current_config = le32_to_cpu(hw_config->id);
+ if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate) &&
+ params_width(params) == le32_to_cpu(hw_config->tdm_slot_width) &&
+ params_channels(params) == le32_to_cpu(hw_config->tdm_slots)) {
+ current_config = le32_to_cpu(hw_config->id);
+ partial_match = false;
+ /* best match found */
break;
+ } else if (current_config < 0 &&
+ params_rate(params) == le32_to_cpu(hw_config->fsync_rate) &&
+ params_channels(params) == le32_to_cpu(hw_config->tdm_slots)) {
+ current_config = le32_to_cpu(hw_config->id);
+ partial_match = true;
+ /* keep looking for better match */
}
}
+
+ if (current_config < 0) {
+ dev_err(sdev->dev,
+ "%s: No suitable hw_config found for %s (num_hw_configs: %d)\n",
+ __func__, slink->link->name, slink->num_hw_configs);
+ return -EINVAL;
+ }
+
+ dev_dbg(sdev->dev,
+ "hw_config for %s: %d (num_hw_configs: %d) with %s match\n",
+ slink->link->name, current_config, slink->num_hw_configs,
+ partial_match ? "partial" : "full");
+ list_for_each_entry(dai, &sdev->dai_list, list)
+ if (!strcmp(slink->link->name, dai->name))
+ dai->current_config = current_config;
+
+ return 0;
}
/*
@@ -728,13 +811,10 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
break;
}
- switch (ipc4_copier->dai_type) {
- case SOF_DAI_INTEL_SSP:
- ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params);
- break;
- default:
- break;
- }
+ if (ipc4_copier->dai_type == SOF_DAI_INTEL_SSP)
+ return ipc4_ssp_dai_config_pcm_params_match(sdev,
+ (char *)rtd->dai_link->name,
+ params);
return 0;
}
@@ -928,8 +1008,24 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
if (!host_copier || !dai_copier)
return -EINVAL;
- if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID)
+ if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) {
return -EINVAL;
+ } else if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_CHAIN_DMA_NODE_ID) {
+ /*
+ * While the firmware does not supports time_info reporting for
+ * streams using ChainDMA, it is granted that ChainDMA can only
+ * be used on Host+Link pairs where the link position is
+ * accessible from the host side.
+ *
+ * Enable delay calculation in case of ChainDMA via host
+ * accessible registers.
+ *
+ * The ChainDMA uses 2x 1ms ping-pong buffer, dai side starts
+ * when 1ms data is available
+ */
+ time_info->stream_start_offset = substream->runtime->rate / MSEC_PER_SEC;
+ goto out;
+ }
node_index = SOF_IPC4_NODE_INDEX(host_copier->data.gtw_cfg.node_id);
offset = offsetof(struct sof_ipc4_fw_registers, pipeline_regs) + node_index * sizeof(ppl_reg);
@@ -947,6 +1043,7 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
time_info->stream_end_offset = ppl_reg.stream_end_offset;
do_div(time_info->stream_end_offset, dai_sample_size);
+out:
/*
* Calculate the wrap boundary need to be used for delay calculation
* The host counter is in bytes, it will wrap earlier than the frames
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index 58b032820683..a8cdf9bc750b 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -72,6 +72,8 @@ struct sof_ipc4_fw_library {
* @max_num_pipelines: max number of pipelines
* @max_libs_count: Maximum number of libraries support by the FW including the
* base firmware
+ * @fw_context_save: Firmware supports full context save and restore
+ * @libraries_restored: The libraries have been retained during firmware boot
*
* @load_library: Callback function for platform dependent library loading
* @pipeline_state_mutex: Mutex to protect pipeline triggers, ref counts, states and deletion
@@ -87,6 +89,7 @@ struct sof_ipc4_fw_data {
int max_num_pipelines;
u32 max_libs_count;
bool fw_context_save;
+ bool libraries_restored;
int (*load_library)(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_library *fw_lib, bool reload);
@@ -123,4 +126,7 @@ size_t sof_ipc4_find_debug_slot_offset_by_type(struct snd_sof_dev *sdev,
void sof_ipc4_mic_privacy_state_change(struct snd_sof_dev *sdev, bool state);
+enum sof_ipc4_pipeline_state;
+const char *sof_ipc4_pipeline_state_str(enum sof_ipc4_pipeline_state state);
+
#endif
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 540ba140e155..591ee30551ba 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -145,6 +145,14 @@ static const struct sof_topology_token src_tokens[] = {
offsetof(struct sof_ipc4_src_data, sink_rate)},
};
+/* ASRC */
+static const struct sof_topology_token asrc_tokens[] = {
+ {SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_asrc_data, out_freq)},
+ {SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_asrc_data, asrc_mode)},
+};
+
static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
@@ -166,6 +174,7 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
[SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)},
[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
+ [SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)},
};
struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev,
@@ -1045,6 +1054,50 @@ err:
return ret;
}
+static int sof_ipc4_widget_setup_comp_asrc(struct snd_sof_widget *swidget)
+{
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_pipeline *spipe = swidget->spipe;
+ struct sof_ipc4_asrc *asrc;
+ int ret;
+
+ dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+ asrc = kzalloc(sizeof(*asrc), GFP_KERNEL);
+ if (!asrc)
+ return -ENOMEM;
+
+ swidget->private = asrc;
+
+ ret = sof_ipc4_get_audio_fmt(scomp, swidget, &asrc->available_fmt,
+ &asrc->data.base_config);
+ if (ret)
+ goto err;
+
+ ret = sof_update_ipc_object(scomp, &asrc->data, SOF_ASRC_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(*asrc), 1);
+ if (ret) {
+ dev_err(scomp->dev, "Parsing ASRC tokens failed\n");
+ goto err;
+ }
+
+ spipe->core_mask |= BIT(swidget->core);
+
+ dev_dbg(scomp->dev, "ASRC sink rate %d, mode 0x%08x\n",
+ asrc->data.out_freq, asrc->data.asrc_mode);
+
+ ret = sof_ipc4_widget_setup_msg(swidget, &asrc->msg);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ sof_ipc4_free_audio_fmt(&asrc->available_fmt);
+ kfree(asrc);
+ swidget->private = NULL;
+ return ret;
+}
+
static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
{
struct sof_ipc4_src *src = swidget->private;
@@ -1057,6 +1110,18 @@ static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
swidget->private = NULL;
}
+static void sof_ipc4_widget_free_comp_asrc(struct snd_sof_widget *swidget)
+{
+ struct sof_ipc4_asrc *asrc = swidget->private;
+
+ if (!asrc)
+ return;
+
+ sof_ipc4_free_audio_fmt(&asrc->available_fmt);
+ kfree(swidget->private);
+ swidget->private = NULL;
+}
+
static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
{
struct sof_ipc4_mixer *mixer = swidget->private;
@@ -1873,10 +1938,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size);
/*
- * Chain DMA does not support stream timestamping, set node_id to invalid
- * to skip the code in sof_ipc4_get_stream_start_offset().
+ * Chain DMA does not support stream timestamping, but it
+ * can use the host side registers for delay calculation.
*/
- copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID;
+ copier_data->gtw_cfg.node_id = SOF_IPC4_CHAIN_DMA_NODE_ID;
return 0;
}
@@ -2817,6 +2882,16 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
msg = &src->msg;
break;
}
+ case snd_soc_dapm_asrc:
+ {
+ struct sof_ipc4_asrc *asrc = swidget->private;
+
+ ipc_size = sizeof(asrc->data);
+ ipc_data = &asrc->data;
+
+ msg = &asrc->msg;
+ break;
+ }
case snd_soc_dapm_effect:
{
struct sof_ipc4_process *process = swidget->private;
@@ -3503,6 +3578,15 @@ static enum sof_tokens src_token_list[] = {
SOF_COMP_EXT_TOKENS,
};
+static enum sof_tokens asrc_token_list[] = {
+ SOF_COMP_TOKENS,
+ SOF_ASRC_TOKENS,
+ SOF_AUDIO_FMT_NUM_TOKENS,
+ SOF_IN_AUDIO_FORMAT_TOKENS,
+ SOF_OUT_AUDIO_FORMAT_TOKENS,
+ SOF_COMP_EXT_TOKENS,
+};
+
static enum sof_tokens process_token_list[] = {
SOF_COMP_TOKENS,
SOF_AUDIO_FMT_NUM_TOKENS,
@@ -3548,6 +3632,10 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY
src_token_list, ARRAY_SIZE(src_token_list),
NULL, sof_ipc4_prepare_src_module,
NULL},
+ [snd_soc_dapm_asrc] = {sof_ipc4_widget_setup_comp_asrc, sof_ipc4_widget_free_comp_asrc,
+ asrc_token_list, ARRAY_SIZE(asrc_token_list),
+ NULL, sof_ipc4_prepare_src_module, /* Common prepare with SRC */
+ NULL},
[snd_soc_dapm_effect] = {sof_ipc4_widget_setup_comp_process,
sof_ipc4_widget_free_comp_process,
process_token_list, ARRAY_SIZE(process_token_list),
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index f4dc499c0ffe..14ba58d2be03 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -58,6 +58,7 @@
#define SOF_IPC4_DMA_DEVICE_MAX_COUNT 16
+#define SOF_IPC4_CHAIN_DMA_NODE_ID 0x7fffffff
#define SOF_IPC4_INVALID_NODE_ID 0xffffffff
/* FW requires minimum 2ms DMA buffer size */
@@ -435,6 +436,30 @@ struct sof_ipc4_src {
struct sof_ipc4_msg msg;
};
+/*
+ * struct sof_ipc4_asrc_data - IPC data for ASRC
+ * @base_config: IPC base config data
+ * @out_freq: Output rate for sink module, passed as such from topology to FW.
+ * @asrc_mode: Control for ASRC features with bit-fields, passed as such from topolgy to FW.
+ */
+struct sof_ipc4_asrc_data {
+ struct sof_ipc4_base_module_cfg base_config;
+ uint32_t out_freq;
+ uint32_t asrc_mode;
+} __packed __aligned(4);
+
+/**
+ * struct sof_ipc4_asrc - ASRC config data
+ * @data: IPC base config data
+ * @available_fmt: Available audio format
+ * @msg: IPC4 message struct containing header and data info
+ */
+struct sof_ipc4_asrc {
+ struct sof_ipc4_asrc_data data;
+ struct sof_ipc4_available_audio_format available_fmt;
+ struct sof_ipc4_msg msg;
+};
+
/**
* struct sof_ipc4_base_module_cfg_ext - base module config extension containing the pin format
* information for the module. Both @num_input_pin_fmts and @num_output_pin_fmts cannot be 0 for a
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index 37e837b22ac8..a4a090e6724a 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -237,6 +237,26 @@ static void sof_ipc4_log_header(struct device *dev, u8 *text, struct sof_ipc4_ms
msg->extension, str);
}
}
+
+const char *sof_ipc4_pipeline_state_str(enum sof_ipc4_pipeline_state state)
+{
+ switch (state) {
+ case SOF_IPC4_PIPE_INVALID_STATE:
+ return " (INVALID_STATE)";
+ case SOF_IPC4_PIPE_UNINITIALIZED:
+ return " (UNINITIALIZED)";
+ case SOF_IPC4_PIPE_RESET:
+ return " (RESET)";
+ case SOF_IPC4_PIPE_PAUSED:
+ return " (PAUSED)";
+ case SOF_IPC4_PIPE_RUNNING:
+ return " (RUNNING)";
+ case SOF_IPC4_PIPE_EOS:
+ return " (EOS)";
+ default:
+ return " (<unknown>)";
+ }
+}
#else /* CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC */
static void sof_ipc4_log_header(struct device *dev, u8 *text, struct sof_ipc4_msg *msg,
bool data_size_valid)
@@ -254,6 +274,11 @@ static void sof_ipc4_log_header(struct device *dev, u8 *text, struct sof_ipc4_ms
else
dev_dbg(dev, "%s: %#x|%#x\n", text, msg->primary, msg->extension);
}
+
+const char *sof_ipc4_pipeline_state_str(enum sof_ipc4_pipeline_state state)
+{
+ return "";
+}
#endif
static void sof_ipc4_dump_payload(struct snd_sof_dev *sdev,
@@ -576,9 +601,19 @@ EXPORT_SYMBOL(sof_ipc4_find_debug_slot_offset_by_type);
static int ipc4_fw_ready(struct snd_sof_dev *sdev, struct sof_ipc4_msg *ipc4_msg)
{
- /* no need to re-check version/ABI for subsequent boots */
- if (!sdev->first_boot)
+ if (!sdev->first_boot) {
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
+ /*
+ * After the initial boot only check if the libraries have been
+ * restored when full context save is not enabled
+ */
+ if (!ipc4_data->fw_context_save)
+ ipc4_data->libraries_restored = !!(ipc4_msg->primary &
+ SOF_IPC4_FW_READY_LIB_RESTORED);
+
return 0;
+ }
sof_ipc4_create_exception_debugfs_node(sdev);
diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c
index 7ff080452cbe..c1bea967737d 100644
--- a/sound/soc/sof/mediatek/mt8186/mt8186.c
+++ b/sound/soc/sof/mediatek/mt8186/mt8186.c
@@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/io.h>
-#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
@@ -46,7 +45,6 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
{
struct resource *mmio;
struct resource res;
- struct device_node *mem_region;
struct device *dev = &pdev->dev;
struct mtk_adsp_chip_info *adsp = data;
int ret;
@@ -57,14 +55,7 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
return ret;
}
- mem_region = of_parse_phandle(dev->of_node, "memory-region", 1);
- if (!mem_region) {
- dev_err(dev, "no memory-region sysmem phandle\n");
- return -ENODEV;
- }
-
- ret = of_address_to_resource(mem_region, 0, &res);
- of_node_put(mem_region);
+ ret = of_reserved_mem_region_to_resource(dev->of_node, 1, &res);
if (ret) {
dev_err(dev, "of_address_to_resource sysmem failed\n");
return ret;
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c
index 3b3582d74510..4d6e9300a9c0 100644
--- a/sound/soc/sof/mediatek/mt8195/mt8195.c
+++ b/sound/soc/sof/mediatek/mt8195/mt8195.c
@@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/io.h>
-#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
@@ -46,7 +45,6 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
{
struct resource *mmio;
struct resource res;
- struct device_node *mem_region;
struct device *dev = &pdev->dev;
struct mtk_adsp_chip_info *adsp = data;
int ret;
@@ -57,14 +55,7 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
return ret;
}
- mem_region = of_parse_phandle(dev->of_node, "memory-region", 1);
- if (!mem_region) {
- dev_err(dev, "no memory-region sysmem phandle\n");
- return -ENODEV;
- }
-
- ret = of_address_to_resource(mem_region, 0, &res);
- of_node_put(mem_region);
+ ret = of_reserved_mem_region_to_resource(dev->of_node, 1, &res);
if (ret) {
dev_err(dev, "of_address_to_resource sysmem failed\n");
return ret;
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index d584a72e6f52..fe43de1fe96c 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -20,24 +20,6 @@
#include "sof-utils.h"
#include "ops.h"
-/* Create DMA buffer page table for DSP */
-static int create_page_table(struct snd_soc_component *component,
- struct snd_pcm_substream *substream,
- unsigned char *dma_area, size_t size)
-{
- struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- struct snd_sof_pcm *spcm;
- struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
- int stream = substream->stream;
-
- spcm = snd_sof_find_spcm_dai(component, rtd);
- if (!spcm)
- return -EINVAL;
-
- return snd_sof_create_page_table(component->dev, dmab,
- spcm->stream[stream].page_table.area, size);
-}
-
/*
* sof pcm period elapse work
*/
@@ -144,7 +126,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 && pcm_ops->hw_free && spcm->prepared[substream->stream]) {
+ if (spcm->prepared[substream->stream] && pcm_ops && pcm_ops->hw_free) {
ret = pcm_ops->hw_free(component, substream);
if (ret < 0)
return ret;
@@ -168,9 +150,11 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
/* create compressed page table for audio firmware */
if (runtime->buffer_changed) {
- ret = create_page_table(component, substream, runtime->dma_area,
- runtime->dma_bytes);
+ struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
+ ret = snd_sof_create_page_table(component->dev, dmab,
+ spcm->stream[substream->stream].page_table.area,
+ runtime->dma_bytes);
if (ret < 0)
return ret;
}
@@ -728,7 +712,6 @@ static int sof_pcm_probe(struct snd_soc_component *component)
ret);
pm_error:
- pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
return ret;
diff --git a/sound/soc/sof/sof-client-ipc-flood-test.c b/sound/soc/sof/sof-client-ipc-flood-test.c
index 11b6f7da2882..373f3a125372 100644
--- a/sound/soc/sof/sof-client-ipc-flood-test.c
+++ b/sound/soc/sof/sof-client-ipc-flood-test.c
@@ -223,7 +223,6 @@ static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buf
ret = sof_debug_ipc_flood_test(cdev, flood_duration_test,
ipc_duration_ms, ipc_count);
- pm_runtime_mark_last_busy(dev);
err = pm_runtime_put_autosuspend(dev);
if (err < 0)
dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
diff --git a/sound/soc/sof/sof-client-ipc-kernel-injector.c b/sound/soc/sof/sof-client-ipc-kernel-injector.c
index 8b28c3dc920c..249bd2d6c8d2 100644
--- a/sound/soc/sof/sof-client-ipc-kernel-injector.c
+++ b/sound/soc/sof/sof-client-ipc-kernel-injector.c
@@ -65,7 +65,6 @@ static ssize_t sof_kernel_msg_inject_dfs_write(struct file *file, const char __u
sof_client_ipc_rx_message(cdev, hdr, priv->kernel_buffer);
- pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
if (ret < 0)
dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", ret);
diff --git a/sound/soc/sof/sof-client-ipc-msg-injector.c b/sound/soc/sof/sof-client-ipc-msg-injector.c
index ba7ca1c5027f..9c8a0fbfb8df 100644
--- a/sound/soc/sof/sof-client-ipc-msg-injector.c
+++ b/sound/soc/sof/sof-client-ipc-msg-injector.c
@@ -137,7 +137,6 @@ static int sof_msg_inject_send_message(struct sof_client_dev *cdev)
if (ret)
dev_err(dev, "IPC message send failed: %d\n", ret);
- pm_runtime_mark_last_busy(dev);
err = pm_runtime_put_autosuspend(dev);
if (err < 0)
dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c
index aff9ce980429..663c0d3c314c 100644
--- a/sound/soc/sof/sof-client-probes.c
+++ b/sound/soc/sof/sof-client-probes.c
@@ -238,7 +238,6 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to,
kfree(desc);
pm_error:
- pm_runtime_mark_last_busy(dev);
err = pm_runtime_put_autosuspend(dev);
if (err < 0)
dev_err_ratelimited(dev, "debugfs read failed to idle %d\n", err);
@@ -289,7 +288,6 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from,
if (!ret)
ret = count;
- pm_runtime_mark_last_busy(dev);
err = pm_runtime_put_autosuspend(dev);
if (err < 0)
dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
@@ -337,7 +335,6 @@ sof_probes_dfs_points_remove_write(struct file *file, const char __user *from,
if (!ret)
ret = count;
- pm_runtime_mark_last_busy(dev);
err = pm_runtime_put_autosuspend(dev);
if (err < 0)
dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index d612d693efc3..b6d5c8024f8c 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -2378,14 +2378,25 @@ 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)
{
+ struct snd_soc_tplg_private *priv = &tw->priv;
+ int ret;
+
+ /* for snd_soc_dapm_widget.no_wname_in_kcontrol_name */
+ ret = sof_parse_tokens(scomp, w, dapm_widget_tokens,
+ ARRAY_SIZE(dapm_widget_tokens),
+ priv->array, le32_to_cpu(priv->size));
+ if (ret < 0) {
+ dev_err(scomp->dev, "failed to parse dapm widget tokens for %s\n",
+ w->name);
+ return ret;
+ }
+
if (WIDGET_IS_DAI(w->id)) {
static const struct sof_topology_token dai_tokens[] = {
{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, 0}};
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct snd_soc_tplg_private *priv = &tw->priv;
struct snd_sof_widget *swidget;
struct snd_sof_dai *sdai;
- int ret;
swidget = kzalloc(sizeof(*swidget), GFP_KERNEL);
if (!swidget)