@@ -179,8 +179,194 @@ static int sof_ipc3_pcm_trigger(struct snd_soc_component *component,
sizeof(stream), &reply, sizeof(reply));
}
+static void ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name,
+ struct snd_pcm_hw_params *params)
+{
+ struct sof_ipc_dai_config *config;
+ struct snd_sof_dai *dai;
+ int i;
+
+ /*
+ * Search for all matching DAIs as we can have both playback and capture DAI
+ * associated with the same link.
+ */
+ list_for_each_entry(dai, &sdev->dai_list, list) {
+ if (!dai->name || strcmp(link_name, dai->name))
+ continue;
+ for (i = 0; i < dai->number_configs; i++) {
+ struct sof_dai_private_data *private = dai->private;
+
+ config = &private->dai_config[i];
+ if (config->ssp.fsync_rate == params_rate(params)) {
+ dev_dbg(sdev->dev, "DAI config %d matches pcm hw params\n", i);
+ dai->current_config = i;
+ break;
+ }
+ }
+ }
+}
+
+static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
+ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name);
+ struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+ struct sof_dai_private_data *private;
+ struct snd_soc_dpcm *dpcm;
+
+ if (!dai) {
+ dev_err(component->dev, "%s: No DAI found with name %s\n", __func__,
+ rtd->dai_link->name);
+ return -EINVAL;
+ }
+
+ private = dai->private;
+ if (!private) {
+ dev_err(component->dev, "%s: No private data found for DAI %s\n", __func__,
+ rtd->dai_link->name);
+ return -EINVAL;
+ }
+
+ /* read format from topology */
+ snd_mask_none(fmt);
+
+ switch (private->comp_dai->config.frame_fmt) {
+ case SOF_IPC_FRAME_S16_LE:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ break;
+ case SOF_IPC_FRAME_S24_4LE:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ break;
+ case SOF_IPC_FRAME_S32_LE:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+ break;
+ default:
+ dev_err(component->dev, "No available DAI format!\n");
+ return -EINVAL;
+ }
+
+ /* read rate and channels from topology */
+ switch (private->dai_config->type) {
+ case SOF_DAI_INTEL_SSP:
+ /* search for config to pcm params match, if not found use default */
+ ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params);
+
+ rate->min = private->dai_config[dai->current_config].ssp.fsync_rate;
+ rate->max = private->dai_config[dai->current_config].ssp.fsync_rate;
+ channels->min = private->dai_config[dai->current_config].ssp.tdm_slots;
+ channels->max = private->dai_config[dai->current_config].ssp.tdm_slots;
+
+ dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
+ dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+
+ break;
+ case SOF_DAI_INTEL_DMIC:
+ /* DMIC only supports 16 or 32 bit formats */
+ if (private->comp_dai->config.frame_fmt == SOF_IPC_FRAME_S24_4LE) {
+ dev_err(component->dev, "Invalid fmt %d for DAI type %d\n",
+ private->comp_dai->config.frame_fmt,
+ private->dai_config->type);
+ }
+ break;
+ case SOF_DAI_INTEL_HDA:
+ /*
+ * HDAudio does not follow the default trigger
+ * sequence due to firmware implementation
+ */
+ for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
+ struct snd_soc_pcm_runtime *fe = dpcm->fe;
+
+ fe->dai_link->trigger[SNDRV_PCM_STREAM_PLAYBACK] =
+ SND_SOC_DPCM_TRIGGER_POST;
+ }
+ break;
+ case SOF_DAI_INTEL_ALH:
+ /*
+ * Dai could run with different channel count compared with
+ * front end, so get dai channel count from topology
+ */
+ channels->min = private->dai_config->alh.channels;
+ channels->max = private->dai_config->alh.channels;
+ break;
+ case SOF_DAI_IMX_ESAI:
+ rate->min = private->dai_config->esai.fsync_rate;
+ rate->max = private->dai_config->esai.fsync_rate;
+ channels->min = private->dai_config->esai.tdm_slots;
+ channels->max = private->dai_config->esai.tdm_slots;
+
+ dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
+ dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+ break;
+ case SOF_DAI_MEDIATEK_AFE:
+ rate->min = private->dai_config->afe.rate;
+ rate->max = private->dai_config->afe.rate;
+ channels->min = private->dai_config->afe.channels;
+ channels->max = private->dai_config->afe.channels;
+
+ dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
+ dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+ break;
+ case SOF_DAI_IMX_SAI:
+ rate->min = private->dai_config->sai.fsync_rate;
+ rate->max = private->dai_config->sai.fsync_rate;
+ channels->min = private->dai_config->sai.tdm_slots;
+ channels->max = private->dai_config->sai.tdm_slots;
+
+ dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
+ dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+ break;
+ case SOF_DAI_AMD_BT:
+ rate->min = private->dai_config->acpbt.fsync_rate;
+ rate->max = private->dai_config->acpbt.fsync_rate;
+ channels->min = private->dai_config->acpbt.tdm_slots;
+ channels->max = private->dai_config->acpbt.tdm_slots;
+
+ dev_dbg(component->dev,
+ "AMD_BT rate_min: %d rate_max: %d\n", rate->min, rate->max);
+ dev_dbg(component->dev, "AMD_BT channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+ break;
+ case SOF_DAI_AMD_SP:
+ rate->min = private->dai_config->acpsp.fsync_rate;
+ rate->max = private->dai_config->acpsp.fsync_rate;
+ channels->min = private->dai_config->acpsp.tdm_slots;
+ channels->max = private->dai_config->acpsp.tdm_slots;
+
+ dev_dbg(component->dev,
+ "AMD_SP rate_min: %d rate_max: %d\n", rate->min, rate->max);
+ dev_dbg(component->dev, "AMD_SP channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+ break;
+ case SOF_DAI_AMD_DMIC:
+ rate->min = private->dai_config->acpdmic.fsync_rate;
+ rate->max = private->dai_config->acpdmic.fsync_rate;
+ channels->min = private->dai_config->acpdmic.tdm_slots;
+ channels->max = private->dai_config->acpdmic.tdm_slots;
+
+ dev_dbg(component->dev,
+ "AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max);
+ dev_dbg(component->dev, "AMD_DMIC channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+ break;
+ default:
+ dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type);
+ break;
+ }
+
+ return 0;
+}
+
const struct sof_ipc_pcm_ops ipc3_pcm_ops = {
.hw_params = sof_ipc3_pcm_hw_params,
.hw_free = sof_ipc3_pcm_hw_free,
.trigger = sof_ipc3_pcm_trigger,
+ .dai_link_fixup = sof_ipc3_pcm_dai_link_fixup,
};
@@ -556,33 +556,6 @@ static int sof_pcm_new(struct snd_soc_component *component,
return 0;
}
-static void ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name,
- struct snd_pcm_hw_params *params)
-{
- struct sof_ipc_dai_config *config;
- struct snd_sof_dai *dai;
- int i;
-
- /*
- * Search for all matching DAIs as we can have both playback and capture DAI
- * associated with the same link.
- */
- list_for_each_entry(dai, &sdev->dai_list, list) {
- if (!dai->name || strcmp(link_name, dai->name))
- continue;
- for (i = 0; i < dai->number_configs; i++) {
- struct sof_dai_private_data *private = dai->private;
-
- config = &private->dai_config[i];
- if (config->ssp.fsync_rate == params_rate(params)) {
- dev_dbg(sdev->dev, "DAI config %d matches pcm hw params\n", i);
- dai->current_config = i;
- break;
- }
- }
- }
-}
-
/* fixup the BE DAI link to match any values from topology */
int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params)
{
@@ -596,8 +569,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);
- struct sof_dai_private_data *private = dai->private;
- struct snd_soc_dpcm *dpcm;
+ const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
/* no topology exists for this BE, try a common configuration */
if (!dai) {
@@ -618,148 +590,8 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa
return 0;
}
- /* read format from topology */
- snd_mask_none(fmt);
-
- switch (private->comp_dai->config.frame_fmt) {
- case SOF_IPC_FRAME_S16_LE:
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
- break;
- case SOF_IPC_FRAME_S24_4LE:
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
- break;
- case SOF_IPC_FRAME_S32_LE:
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
- break;
- default:
- dev_err(component->dev, "error: No available DAI format!\n");
- return -EINVAL;
- }
-
- /* read rate and channels from topology */
- switch (private->dai_config->type) {
- case SOF_DAI_INTEL_SSP:
- /* search for config to pcm params match, if not found use default */
- ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params);
-
- rate->min = private->dai_config[dai->current_config].ssp.fsync_rate;
- rate->max = private->dai_config[dai->current_config].ssp.fsync_rate;
- channels->min = private->dai_config[dai->current_config].ssp.tdm_slots;
- channels->max = private->dai_config[dai->current_config].ssp.tdm_slots;
-
- dev_dbg(component->dev,
- "rate_min: %d rate_max: %d\n", rate->min, rate->max);
- dev_dbg(component->dev,
- "channels_min: %d channels_max: %d\n",
- channels->min, channels->max);
-
- break;
- case SOF_DAI_INTEL_DMIC:
- /* DMIC only supports 16 or 32 bit formats */
- if (private->comp_dai->config.frame_fmt == SOF_IPC_FRAME_S24_4LE) {
- dev_err(component->dev,
- "error: invalid fmt %d for DAI type %d\n",
- private->comp_dai->config.frame_fmt,
- private->dai_config->type);
- }
- break;
- case SOF_DAI_INTEL_HDA:
- /*
- * HDAudio does not follow the default trigger
- * sequence due to firmware implementation
- */
- for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
- struct snd_soc_pcm_runtime *fe = dpcm->fe;
-
- fe->dai_link->trigger[SNDRV_PCM_STREAM_PLAYBACK] =
- SND_SOC_DPCM_TRIGGER_POST;
- }
- break;
- case SOF_DAI_INTEL_ALH:
- /*
- * Dai could run with different channel count compared with
- * front end, so get dai channel count from topology
- */
- channels->min = private->dai_config->alh.channels;
- channels->max = private->dai_config->alh.channels;
- break;
- case SOF_DAI_IMX_ESAI:
- rate->min = private->dai_config->esai.fsync_rate;
- rate->max = private->dai_config->esai.fsync_rate;
- channels->min = private->dai_config->esai.tdm_slots;
- channels->max = private->dai_config->esai.tdm_slots;
-
- dev_dbg(component->dev,
- "rate_min: %d rate_max: %d\n", rate->min, rate->max);
- dev_dbg(component->dev,
- "channels_min: %d channels_max: %d\n",
- channels->min, channels->max);
- break;
- case SOF_DAI_MEDIATEK_AFE:
- rate->min = private->dai_config->afe.rate;
- rate->max = private->dai_config->afe.rate;
- channels->min = private->dai_config->afe.channels;
- channels->max = private->dai_config->afe.channels;
-
- dev_dbg(component->dev,
- "rate_min: %d rate_max: %d\n", rate->min, rate->max);
- dev_dbg(component->dev,
- "channels_min: %d channels_max: %d\n",
- channels->min, channels->max);
- break;
- case SOF_DAI_IMX_SAI:
- rate->min = private->dai_config->sai.fsync_rate;
- rate->max = private->dai_config->sai.fsync_rate;
- channels->min = private->dai_config->sai.tdm_slots;
- channels->max = private->dai_config->sai.tdm_slots;
-
- dev_dbg(component->dev,
- "rate_min: %d rate_max: %d\n", rate->min, rate->max);
- dev_dbg(component->dev,
- "channels_min: %d channels_max: %d\n",
- channels->min, channels->max);
- break;
- case SOF_DAI_AMD_BT:
- rate->min = private->dai_config->acpbt.fsync_rate;
- rate->max = private->dai_config->acpbt.fsync_rate;
- channels->min = private->dai_config->acpbt.tdm_slots;
- channels->max = private->dai_config->acpbt.tdm_slots;
-
- dev_dbg(component->dev,
- "AMD_BT rate_min: %d rate_max: %d\n", rate->min, rate->max);
- dev_dbg(component->dev,
- "AMD_BT channels_min: %d channels_max: %d\n",
- channels->min, channels->max);
- break;
- case SOF_DAI_AMD_SP:
- rate->min = private->dai_config->acpsp.fsync_rate;
- rate->max = private->dai_config->acpsp.fsync_rate;
- channels->min = private->dai_config->acpsp.tdm_slots;
- channels->max = private->dai_config->acpsp.tdm_slots;
-
- dev_dbg(component->dev,
- "AMD_SP rate_min: %d rate_max: %d\n", rate->min, rate->max);
- dev_dbg(component->dev,
- "AMD_SP channels_min: %d channels_max: %d\n",
- channels->min, channels->max);
- break;
- case SOF_DAI_AMD_DMIC:
- rate->min = private->dai_config->acpdmic.fsync_rate;
- rate->max = private->dai_config->acpdmic.fsync_rate;
- channels->min = private->dai_config->acpdmic.tdm_slots;
- channels->max = private->dai_config->acpdmic.tdm_slots;
-
- dev_dbg(component->dev,
- "AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max);
- dev_dbg(component->dev,
- "AMD_DMIC channels_min: %d channels_max: %d\n",
- channels->min, channels->max);
- break;
- default:
- dev_err(component->dev, "error: invalid DAI type %d\n",
- private->dai_config->type);
- break;
- }
+ if (pcm_ops->dai_link_fixup)
+ return pcm_ops->dai_link_fixup(rtd, params);
return 0;
}