diff options
-rw-r--r-- | sound/soc/intel/skylake/skl-topology.c | 169 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-tplg-interface.h | 74 | ||||
-rw-r--r-- | sound/soc/soc-topology.c | 7 |
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 | */ | ||
2736 | static 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 | |||
2779 | static 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 | |||
2794 | static 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 | |||
2813 | static 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 | |||
174 | struct skl_dfw_v4_module_pin { | ||
175 | u16 module_id; | ||
176 | u16 instance_id; | ||
177 | } __packed; | ||
178 | |||
179 | struct 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 | |||
190 | struct 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 | |||
198 | struct 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 | |||
206 | struct 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"); |