OSDN Git Service

ASoC: SOF: Add dai_link_fixup PCM op for IPC3
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Thu, 17 Mar 2022 17:50:41 +0000 (10:50 -0700)
committerMark Brown <broonie@kernel.org>
Fri, 18 Mar 2022 16:04:50 +0000 (16:04 +0000)
Define the dai_link_fixup PCM op for IPC3 and use it

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20220317175044.1752400-17-ranjani.sridharan@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/ipc3-pcm.c
sound/soc/sof/pcm.c

index d83d545..58b7594 100644 (file)
@@ -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,
 };
index dc55a04..658cd89 100644 (file)
@@ -556,33 +556,6 @@ capture:
        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;
 }