aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuenter Roeck <groeck@chromium.org>2018-05-24 15:49:21 -0400
committerMark Brown <broonie@kernel.org>2018-06-01 13:09:09 -0400
commitac9391daac004e12dc4e4c62e130b09f245ece2b (patch)
treec17ab4ccf2c27f3892c57d64b48364908b9337de
parent0e725b483bbed3c6178c3928fd9b62dadc2eb240 (diff)
ASoC: topology: Improve backwards compatibility with v4 topology files
Commit dc31e741db49 ("ASoC: topology: ABI - Add the types for BE DAI") introduced sound topology files version 5. Initially, this change made the topology code incompatible with v4 topology files. Backwards compatibility with v4 configuration files was subsequently added with commit 288b8da7e992 ("ASoC: topology: Support topology file of ABI v4"). Unfortunately, backwards compatibility was never fully implemented. First, the manifest size in (Skylake) v4 configuration files is set to 0, which causes manifest_new_ver() to bail out with error messages similar to the following. snd_soc_skl 0000:00:1f.3: ASoC: invalid manifest size snd_soc_skl 0000:00:1f.3: tplg component load failed-22 snd_soc_skl 0000:00:1f.3: Failed to init topology! snd_soc_skl 0000:00:1f.3: ASoC: failed to probe component -22 skl_n88l25_m98357a skl_n88l25_m98357a: ASoC: failed to instantiate card -22 skl_n88l25_m98357a: probe of skl_n88l25_m98357a failed with error -22 After this problem is fixed, the following error message is seen instead. snd_soc_skl 0000:00:1f.3: ASoC: old version of manifest snd_soc_skl 0000:00:1f.3: Invalid descriptor token 1093938482 snd_soc_skl 0000:00:1f.3: ASoC: failed to load widget media0_in cpr 0 snd_soc_skl 0000:00:1f.3: tPlg component load failed-22 This message is seen because backwards compatibility for loading widgets was never implemented. The lack of audio support when running the upstream kernel on recent Chromebooks has been reported in various forums, and can be traced back to this problem. Attempts to fix the problem, usually by providing v5 configuration files, were only partially successful. Let's implement backward compatibility properly to solve the problem for good. Signed-off-by: Guenter Roeck <groeck@chromium.org> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/intel/skylake/skl-topology.c169
-rw-r--r--sound/soc/intel/skylake/skl-tplg-interface.h74
-rw-r--r--sound/soc/soc-topology.c7
3 files changed, 248 insertions, 2 deletions
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 3b1dca419883..9e4c2cb88dea 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -19,6 +19,7 @@
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/types.h> 20#include <linux/types.h>
21#include <linux/firmware.h> 21#include <linux/firmware.h>
22#include <linux/uuid.h>
22#include <sound/soc.h> 23#include <sound/soc.h>
23#include <sound/soc-topology.h> 24#include <sound/soc-topology.h>
24#include <uapi/sound/snd_sst_tokens.h> 25#include <uapi/sound/snd_sst_tokens.h>
@@ -2724,6 +2725,167 @@ static int skl_tplg_get_desc_blocks(struct device *dev,
2724 return -EINVAL; 2725 return -EINVAL;
2725} 2726}
2726 2727
2728/* Functions to parse private data from configuration file format v4 */
2729
2730/*
2731 * Add pipeline from topology binary into driver pipeline list
2732 *
2733 * If already added we return that instance
2734 * Otherwise we create a new instance and add into driver list
2735 */
2736static int skl_tplg_add_pipe_v4(struct device *dev,
2737 struct skl_module_cfg *mconfig, struct skl *skl,
2738 struct skl_dfw_v4_pipe *dfw_pipe)
2739{
2740 struct skl_pipeline *ppl;
2741 struct skl_pipe *pipe;
2742 struct skl_pipe_params *params;
2743
2744 list_for_each_entry(ppl, &skl->ppl_list, node) {
2745 if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) {
2746 mconfig->pipe = ppl->pipe;
2747 return 0;
2748 }
2749 }
2750
2751 ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
2752 if (!ppl)
2753 return -ENOMEM;
2754
2755 pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
2756 if (!pipe)
2757 return -ENOMEM;
2758
2759 params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
2760 if (!params)
2761 return -ENOMEM;
2762
2763 pipe->ppl_id = dfw_pipe->pipe_id;
2764 pipe->memory_pages = dfw_pipe->memory_pages;
2765 pipe->pipe_priority = dfw_pipe->pipe_priority;
2766 pipe->conn_type = dfw_pipe->conn_type;
2767 pipe->state = SKL_PIPE_INVALID;
2768 pipe->p_params = params;
2769 INIT_LIST_HEAD(&pipe->w_list);
2770
2771 ppl->pipe = pipe;
2772 list_add(&ppl->node, &skl->ppl_list);
2773
2774 mconfig->pipe = pipe;
2775
2776 return 0;
2777}
2778
2779static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin,
2780 struct skl_module_pin *m_pin,
2781 bool is_dynamic, int max_pin)
2782{
2783 int i;
2784
2785 for (i = 0; i < max_pin; i++) {
2786 m_pin[i].id.module_id = dfw_pin[i].module_id;
2787 m_pin[i].id.instance_id = dfw_pin[i].instance_id;
2788 m_pin[i].in_use = false;
2789 m_pin[i].is_dynamic = is_dynamic;
2790 m_pin[i].pin_state = SKL_PIN_UNBIND;
2791 }
2792}
2793
2794static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt,
2795 struct skl_dfw_v4_module_fmt *src_fmt,
2796 int pins)
2797{
2798 int i;
2799
2800 for (i = 0; i < pins; i++) {
2801 dst_fmt[i].fmt.channels = src_fmt[i].channels;
2802 dst_fmt[i].fmt.s_freq = src_fmt[i].freq;
2803 dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth;
2804 dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth;
2805 dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg;
2806 dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map;
2807 dst_fmt[i].fmt.interleaving_style =
2808 src_fmt[i].interleaving_style;
2809 dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type;
2810 }
2811}
2812
2813static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w,
2814 struct skl *skl, struct device *dev,
2815 struct skl_module_cfg *mconfig)
2816{
2817 struct skl_dfw_v4_module *dfw =
2818 (struct skl_dfw_v4_module *)tplg_w->priv.data;
2819 int ret;
2820
2821 dev_dbg(dev, "Parsing Skylake v4 widget topology data\n");
2822
2823 ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid);
2824 if (ret)
2825 return ret;
2826 mconfig->id.module_id = -1;
2827 mconfig->id.instance_id = dfw->instance_id;
2828 mconfig->module->resources[0].cps = dfw->max_mcps;
2829 mconfig->module->resources[0].ibs = dfw->ibs;
2830 mconfig->module->resources[0].obs = dfw->obs;
2831 mconfig->core_id = dfw->core_id;
2832 mconfig->module->max_input_pins = dfw->max_in_queue;
2833 mconfig->module->max_output_pins = dfw->max_out_queue;
2834 mconfig->module->loadable = dfw->is_loadable;
2835 skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt,
2836 MAX_IN_QUEUE);
2837 skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt,
2838 MAX_OUT_QUEUE);
2839
2840 mconfig->params_fixup = dfw->params_fixup;
2841 mconfig->converter = dfw->converter;
2842 mconfig->m_type = dfw->module_type;
2843 mconfig->vbus_id = dfw->vbus_id;
2844 mconfig->module->resources[0].is_pages = dfw->mem_pages;
2845
2846 ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe);
2847 if (ret)
2848 return ret;
2849
2850 mconfig->dev_type = dfw->dev_type;
2851 mconfig->hw_conn_type = dfw->hw_conn_type;
2852 mconfig->time_slot = dfw->time_slot;
2853 mconfig->formats_config.caps_size = dfw->caps.caps_size;
2854
2855 mconfig->m_in_pin = devm_kzalloc(dev,
2856 MAX_IN_QUEUE * sizeof(*mconfig->m_in_pin),
2857 GFP_KERNEL);
2858 if (!mconfig->m_in_pin)
2859 return -ENOMEM;
2860
2861 mconfig->m_out_pin = devm_kzalloc(dev,
2862 MAX_OUT_QUEUE * sizeof(*mconfig->m_out_pin),
2863 GFP_KERNEL);
2864 if (!mconfig->m_out_pin)
2865 return -ENOMEM;
2866
2867 skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin,
2868 dfw->is_dynamic_in_pin,
2869 mconfig->module->max_input_pins);
2870 skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin,
2871 dfw->is_dynamic_out_pin,
2872 mconfig->module->max_output_pins);
2873
2874 if (mconfig->formats_config.caps_size) {
2875 mconfig->formats_config.set_params = dfw->caps.set_params;
2876 mconfig->formats_config.param_id = dfw->caps.param_id;
2877 mconfig->formats_config.caps =
2878 devm_kzalloc(dev, mconfig->formats_config.caps_size,
2879 GFP_KERNEL);
2880 if (!mconfig->formats_config.caps)
2881 return -ENOMEM;
2882 memcpy(mconfig->formats_config.caps, dfw->caps.caps,
2883 dfw->caps.caps_size);
2884 }
2885
2886 return 0;
2887}
2888
2727/* 2889/*
2728 * Parse the private data for the token and corresponding value. 2890 * Parse the private data for the token and corresponding value.
2729 * The private data can have multiple data blocks. So, a data block 2891 * The private data can have multiple data blocks. So, a data block
@@ -2739,6 +2901,13 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
2739 char *data; 2901 char *data;
2740 int ret; 2902 int ret;
2741 2903
2904 /*
2905 * v4 configuration files have a valid UUID at the start of
2906 * the widget's private data.
2907 */
2908 if (uuid_is_valid((char *)tplg_w->priv.data))
2909 return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig);
2910
2742 /* Read the NUM_DATA_BLOCKS descriptor */ 2911 /* Read the NUM_DATA_BLOCKS descriptor */
2743 array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data; 2912 array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
2744 ret = skl_tplg_get_desc_blocks(dev, array); 2913 ret = skl_tplg_get_desc_blocks(dev, array);
diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h
index f8d1749a2e0c..b0e3d376594c 100644
--- a/sound/soc/intel/skylake/skl-tplg-interface.h
+++ b/sound/soc/intel/skylake/skl-tplg-interface.h
@@ -169,4 +169,78 @@ enum skl_tuple_type {
169 SKL_TYPE_DATA 169 SKL_TYPE_DATA
170}; 170};
171 171
172/* v4 configuration data */
173
174struct skl_dfw_v4_module_pin {
175 u16 module_id;
176 u16 instance_id;
177} __packed;
178
179struct skl_dfw_v4_module_fmt {
180 u32 channels;
181 u32 freq;
182 u32 bit_depth;
183 u32 valid_bit_depth;
184 u32 ch_cfg;
185 u32 interleaving_style;
186 u32 sample_type;
187 u32 ch_map;
188} __packed;
189
190struct skl_dfw_v4_module_caps {
191 u32 set_params:2;
192 u32 rsvd:30;
193 u32 param_id;
194 u32 caps_size;
195 u32 caps[HDA_SST_CFG_MAX];
196} __packed;
197
198struct skl_dfw_v4_pipe {
199 u8 pipe_id;
200 u8 pipe_priority;
201 u16 conn_type:4;
202 u16 rsvd:4;
203 u16 memory_pages:8;
204} __packed;
205
206struct skl_dfw_v4_module {
207 char uuid[SKL_UUID_STR_SZ];
208
209 u16 module_id;
210 u16 instance_id;
211 u32 max_mcps;
212 u32 mem_pages;
213 u32 obs;
214 u32 ibs;
215 u32 vbus_id;
216
217 u32 max_in_queue:8;
218 u32 max_out_queue:8;
219 u32 time_slot:8;
220 u32 core_id:4;
221 u32 rsvd1:4;
222
223 u32 module_type:8;
224 u32 conn_type:4;
225 u32 dev_type:4;
226 u32 hw_conn_type:4;
227 u32 rsvd2:12;
228
229 u32 params_fixup:8;
230 u32 converter:8;
231 u32 input_pin_type:1;
232 u32 output_pin_type:1;
233 u32 is_dynamic_in_pin:1;
234 u32 is_dynamic_out_pin:1;
235 u32 is_loadable:1;
236 u32 rsvd3:11;
237
238 struct skl_dfw_v4_pipe pipe;
239 struct skl_dfw_v4_module_fmt in_fmt[MAX_IN_QUEUE];
240 struct skl_dfw_v4_module_fmt out_fmt[MAX_OUT_QUEUE];
241 struct skl_dfw_v4_module_pin in_pin[MAX_IN_QUEUE];
242 struct skl_dfw_v4_module_pin out_pin[MAX_OUT_QUEUE];
243 struct skl_dfw_v4_module_caps caps;
244} __packed;
245
172#endif 246#endif
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index f25ea9aab235..3d04fa297677 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -2313,8 +2313,11 @@ static int manifest_new_ver(struct soc_tplg *tplg,
2313 *manifest = NULL; 2313 *manifest = NULL;
2314 2314
2315 if (src->size != sizeof(*src_v4)) { 2315 if (src->size != sizeof(*src_v4)) {
2316 dev_err(tplg->dev, "ASoC: invalid manifest size\n"); 2316 dev_warn(tplg->dev, "ASoC: invalid manifest size %d\n",
2317 return -EINVAL; 2317 src->size);
2318 if (src->size)
2319 return -EINVAL;
2320 src->size = sizeof(*src_v4);
2318 } 2321 }
2319 2322
2320 dev_warn(tplg->dev, "ASoC: old version of manifest\n"); 2323 dev_warn(tplg->dev, "ASoC: old version of manifest\n");