ASoC: SOF: ipc4-topology: Modify the reference output valid_bits for copier
[platform/kernel/linux-starfive.git] / sound / soc / sof / ipc4-topology.c
index 310aadd..eff4363 100644 (file)
@@ -1349,6 +1349,31 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
 }
 #endif
 
+static bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
+                                            struct sof_ipc4_pin_format *pin_fmts,
+                                            u32 pin_fmts_size)
+{
+       struct sof_ipc4_audio_format *fmt;
+       u32 valid_bits;
+       int i;
+
+       fmt = &pin_fmts[0].audio_fmt;
+       valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+
+       /* check if all output formats in topology are the same */
+       for (i = 1; i < pin_fmts_size; i++) {
+               u32 _valid_bits;
+
+               fmt = &pin_fmts[i].audio_fmt;
+               _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+
+               if (_valid_bits != valid_bits)
+                       return false;
+       }
+
+       return true;
+}
+
 static int
 sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
                               struct snd_pcm_hw_params *fe_params,
@@ -1371,6 +1396,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
        u32 out_ref_rate, out_ref_channels;
        u32 deep_buffer_dma_ms = 0;
        int output_fmt_index;
+       bool single_output_format;
 
        dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
 
@@ -1504,6 +1530,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
                return ret;
 
        /* set the reference params for output format selection */
+       single_output_format = sof_ipc4_copier_is_single_format(sdev,
+                                                               available_fmt->output_pin_fmts,
+                                                               available_fmt->num_output_formats);
        switch (swidget->id) {
        case snd_soc_dapm_aif_in:
        case snd_soc_dapm_dai_out:
@@ -1514,17 +1543,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
                in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
                out_ref_rate = in_fmt->sampling_frequency;
                out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
-               out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+
+               if (!single_output_format)
+                       out_ref_valid_bits =
+                               SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
                break;
        }
        case snd_soc_dapm_aif_out:
        case snd_soc_dapm_dai_in:
-               out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
-               if (out_ref_valid_bits < 0)
-                       return out_ref_valid_bits;
-
                out_ref_rate = params_rate(fe_params);
                out_ref_channels = params_channels(fe_params);
+               if (!single_output_format) {
+                       out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
+                       if (out_ref_valid_bits < 0)
+                               return out_ref_valid_bits;
+               }
                break;
        default:
                /*
@@ -1534,6 +1567,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
                return -EINVAL;
        }
 
+       /*
+        * if the output format is the same across all available output formats, choose
+        * that as the reference.
+        */
+       if (single_output_format) {
+               struct sof_ipc4_audio_format *out_fmt;
+
+               out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt;
+               out_ref_valid_bits =
+                       SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
+       }
+
+       dev_dbg(sdev->dev, "copier %s: reference output rate %d, channels %d valid_bits %d\n",
+               swidget->widget->name, out_ref_rate, out_ref_channels, out_ref_valid_bits);
+
        output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config,
                                                          available_fmt, out_ref_rate,
                                                          out_ref_channels, out_ref_valid_bits);