mirror of
https://github.com/torvalds/linux.git
synced 2025-01-01 15:51:46 +00:00
ASoC: SOF: sof-audio: Fix broken early bclk feature for SSP
With the removal of widget setup during BE hw_params, the DAI config IPC is never sent with the SOF_DAI_CONFIG_FLAGS_HW_PARAMS. This means that the early bit clock feature required for certain codecs will be broken. Fix this by saving the config flags sent during BE DAI hw_params and reusing it when the DAI_CONFIG IPC is sent after the DAI widget is set up. Also, free the DAI config before the widget is freed. The DAI_CONFIG IPC sent during the sof_widget_free() does not have the DAI index information. So, save the dai_index in the config during hw_params and reuse it during hw_free. For IPC4, do not clear the node ID during hw_free. It will be needed for freeing the group_ida during unprepare. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Rander Wang <rander.wang@intel.com> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com> Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Link: https://lore.kernel.org/r/20230307114639.4553-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
ca09e2a351
commit
b66bfc3a98
@ -2081,7 +2081,9 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
|
||||
break;
|
||||
case SOF_DAI_INTEL_ALH:
|
||||
if (data) {
|
||||
config->dai_index = data->dai_index;
|
||||
/* save the dai_index during hw_params and reuse it for hw_free */
|
||||
if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS)
|
||||
config->dai_index = data->dai_index;
|
||||
config->alh.stream_id = data->dai_data;
|
||||
}
|
||||
break;
|
||||
@ -2089,7 +2091,30 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
|
||||
break;
|
||||
}
|
||||
|
||||
config->flags = flags;
|
||||
/*
|
||||
* The dai_config op is invoked several times and the flags argument varies as below:
|
||||
* BE DAI hw_params: When the op is invoked during the BE DAI hw_params, flags contains
|
||||
* SOF_DAI_CONFIG_FLAGS_HW_PARAMS along with quirks
|
||||
* FE DAI hw_params: When invoked during FE DAI hw_params after the DAI widget has
|
||||
* just been set up in the DSP, flags is set to SOF_DAI_CONFIG_FLAGS_HW_PARAMS with no
|
||||
* quirks
|
||||
* BE DAI trigger: When invoked during the BE DAI trigger, flags is set to
|
||||
* SOF_DAI_CONFIG_FLAGS_PAUSE and contains no quirks
|
||||
* BE DAI hw_free: When invoked during the BE DAI hw_free, flags is set to
|
||||
* SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks
|
||||
* FE DAI hw_free: When invoked during the FE DAI hw_free, flags is set to
|
||||
* SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks
|
||||
*
|
||||
* The DAI_CONFIG IPC is sent to the DSP, only after the widget is set up during the FE
|
||||
* DAI hw_params. But since the BE DAI hw_params precedes the FE DAI hw_params, the quirks
|
||||
* need to be preserved when assigning the flags before sending the IPC.
|
||||
* For the case of PAUSE/HW_FREE, since there are no quirks, flags can be used as is.
|
||||
*/
|
||||
|
||||
if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS)
|
||||
config->flags |= flags;
|
||||
else
|
||||
config->flags = flags;
|
||||
|
||||
/* only send the IPC if the widget is set up in the DSP */
|
||||
if (swidget->use_count > 0) {
|
||||
@ -2097,6 +2122,9 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
|
||||
&reply, sizeof(reply));
|
||||
if (ret < 0)
|
||||
dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name);
|
||||
|
||||
/* clear the flags once the IPC has been sent even if it fails */
|
||||
config->flags = SOF_DAI_CONFIG_FLAGS_NONE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -980,6 +980,7 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
|
||||
|
||||
ipc4_copier = dai->private;
|
||||
if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
|
||||
struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
|
||||
struct sof_ipc4_alh_configuration_blob *blob;
|
||||
unsigned int group_id;
|
||||
|
||||
@ -989,6 +990,9 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
|
||||
ALH_MULTI_GTW_BASE;
|
||||
ida_free(&alh_group_ida, group_id);
|
||||
}
|
||||
|
||||
/* clear the node ID */
|
||||
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1940,8 +1944,15 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
|
||||
pipeline->skip_during_fe_trigger = true;
|
||||
fallthrough;
|
||||
case SOF_DAI_INTEL_ALH:
|
||||
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
|
||||
copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
|
||||
/*
|
||||
* Do not clear the node ID when this op is invoked with
|
||||
* SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during
|
||||
* unprepare.
|
||||
*/
|
||||
if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
|
||||
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
|
||||
copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
|
||||
}
|
||||
break;
|
||||
case SOF_DAI_INTEL_DMIC:
|
||||
case SOF_DAI_INTEL_SSP:
|
||||
|
@ -50,9 +50,27 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
|
||||
/* reset route setup status for all routes that contain this widget */
|
||||
sof_reset_route_setup_status(sdev, swidget);
|
||||
|
||||
/* free DAI config and continue to free widget even if it fails */
|
||||
if (WIDGET_IS_DAI(swidget->id)) {
|
||||
struct snd_sof_dai_config_data data;
|
||||
unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_FREE;
|
||||
|
||||
data.dai_data = DMA_CHAN_INVALID;
|
||||
|
||||
if (tplg_ops && tplg_ops->dai_config) {
|
||||
err = tplg_ops->dai_config(sdev, swidget, flags, &data);
|
||||
if (err < 0)
|
||||
dev_err(sdev->dev, "failed to free config for widget %s\n",
|
||||
swidget->widget->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* continue to disable core even if IPC fails */
|
||||
if (tplg_ops && tplg_ops->widget_free)
|
||||
err = tplg_ops->widget_free(sdev, swidget);
|
||||
if (tplg_ops && tplg_ops->widget_free) {
|
||||
ret = tplg_ops->widget_free(sdev, swidget);
|
||||
if (ret < 0 && !err)
|
||||
err = ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* disable widget core. continue to route setup status and complete flag
|
||||
@ -151,8 +169,12 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
|
||||
|
||||
/* send config for DAI components */
|
||||
if (WIDGET_IS_DAI(swidget->id)) {
|
||||
unsigned int flags = SOF_DAI_CONFIG_FLAGS_NONE;
|
||||
unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
|
||||
|
||||
/*
|
||||
* The config flags saved during BE DAI hw_params will be used for IPC3. IPC4 does
|
||||
* not use the flags argument.
|
||||
*/
|
||||
if (tplg_ops && tplg_ops->dai_config) {
|
||||
ret = tplg_ops->dai_config(sdev, swidget, flags, NULL);
|
||||
if (ret < 0)
|
||||
|
Loading…
Reference in New Issue
Block a user