Skip to content

Commit

Permalink
ASoC: SOF: sof-audio: Fix broken early bclk feature for SSP
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Pierre-Louis Bossart <[email protected]>
Reviewed-by: Rander Wang <[email protected]>
Reviewed-by: Bard Liao <[email protected]>
Reviewed-by: Péter Ujfalusi <[email protected]>
Signed-off-by: Peter Ujfalusi <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Mark Brown <[email protected]>
  • Loading branch information
ranj063 authored and broonie committed Mar 7, 2023
1 parent ca09e2a commit b66bfc3
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 7 deletions.
32 changes: 30 additions & 2 deletions sound/soc/sof/ipc3-topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -2081,22 +2081,50 @@ 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;
default:
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) {
ret = sof_ipc_tx_message(sdev->ipc, config, config->hdr.size,
&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;
Expand Down
15 changes: 13 additions & 2 deletions sound/soc/sof/ipc4-topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
}

Expand Down Expand Up @@ -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:
Expand Down
28 changes: 25 additions & 3 deletions sound/soc/sof/sof-audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit b66bfc3

Please sign in to comment.