1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2021 Intel Corporation. All rights reserved.
4 //
5 // Author: Jaska Uimonen <jaska.uimonen@linux.intel.com>
6 
7 #include "aconfig.h"
8 #include <stdint.h>
9 #include <errno.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <alsa/input.h>
14 #include <alsa/output.h>
15 #include <alsa/conf.h>
16 #include <alsa/error.h>
17 #include "intel-nhlt.h"
18 #include "ssp-nhlt.h"
19 #include "ssp/ssp-process.h"
20 #include "ssp/ssp-internal.h"
21 
set_mn_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)22 static int set_mn_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
23 {
24 	long m_div;
25 	long n_div;
26 	long ret;
27 
28 	struct dai_values ssp_mn_data[] = {
29 		{"m_div", SND_CONFIG_TYPE_INTEGER, NULL, &m_div, NULL},
30 		{"n_div", SND_CONFIG_TYPE_INTEGER, NULL, &n_div, NULL},
31 	};
32 
33 	ret = find_set_values(&ssp_mn_data[0], ARRAY_SIZE(ssp_mn_data), cfg, top,
34 			      "Class.Base.mn_config");
35 	if (ret < 0)
36 		return ret;
37 
38 	return ssp_mn_set_params(nhlt, m_div, n_div);
39 }
40 
set_clk_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)41 static int set_clk_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
42 {
43 	long clock_warm_up;
44 	long mclk;
45 	long warm_up_ovr;
46 	long clock_stop_delay;
47 	long keep_running;
48 	long clock_stop_ovr;
49 	long ret;
50 
51 	struct dai_values ssp_clk_data[] = {
52 		{"clock_warm_up", SND_CONFIG_TYPE_INTEGER, NULL, &clock_warm_up, NULL},
53 		{"mclk", SND_CONFIG_TYPE_INTEGER, NULL, &mclk, NULL},
54 		{"warm_up_ovr", SND_CONFIG_TYPE_INTEGER, NULL, &warm_up_ovr, NULL},
55 		{"clock_stop_delay", SND_CONFIG_TYPE_INTEGER, NULL, &clock_stop_delay, NULL},
56 		{"keep_running", SND_CONFIG_TYPE_INTEGER, NULL, &keep_running, NULL},
57 		{"clock_stop_ovr", SND_CONFIG_TYPE_INTEGER, NULL, &clock_stop_ovr, NULL},
58 	};
59 
60 	ret = find_set_values(&ssp_clk_data[0], ARRAY_SIZE(ssp_clk_data), cfg, top,
61 			      "Class.Base.clk_config");
62 	if (ret < 0)
63 		return ret;
64 
65 	return ssp_clk_set_params(nhlt, clock_warm_up, mclk, warm_up_ovr, clock_stop_delay,
66 				  keep_running, clock_stop_ovr);
67 }
68 
set_tr_start_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)69 static int set_tr_start_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
70 {
71 	long sampling_frequency;
72 	long bit_depth;
73 	long channel_map;
74 	long channel_config;
75 	long interleaving_style;
76 	long number_of_channels;
77 	long valid_bit_depth;
78 	long sample_type;
79 	long ret;
80 
81 	struct dai_values ssp_tr_data[] = {
82 		{"sampling_frequency", SND_CONFIG_TYPE_INTEGER, NULL, &sampling_frequency, NULL},
83 		{"bit_depth", SND_CONFIG_TYPE_INTEGER, NULL, &bit_depth, NULL},
84 		{"channel_map", SND_CONFIG_TYPE_INTEGER, NULL, &channel_map, NULL},
85 		{"channel_config", SND_CONFIG_TYPE_INTEGER, NULL, &channel_config, NULL},
86 		{"interleaving_style", SND_CONFIG_TYPE_INTEGER, NULL, &interleaving_style, NULL},
87 		{"number_of_channels", SND_CONFIG_TYPE_INTEGER, NULL, &number_of_channels, NULL},
88 		{"valid_bit_depth", SND_CONFIG_TYPE_INTEGER, NULL, &valid_bit_depth, NULL},
89 		{"sample_type", SND_CONFIG_TYPE_INTEGER, NULL, &sample_type, NULL},
90 	};
91 
92 	ret = find_set_values(&ssp_tr_data[0], ARRAY_SIZE(ssp_tr_data), cfg, top,
93 			      "Class.Base.tr_start_config");
94 	if (ret < 0)
95 		return ret;
96 
97 	return ssp_tr_start_set_params(nhlt, sampling_frequency, bit_depth, channel_map,
98 				       channel_config, interleaving_style, number_of_channels,
99 				       valid_bit_depth,sample_type);
100 }
101 
set_tr_stop_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)102 static int set_tr_stop_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
103 {
104 	long sampling_frequency;
105 	long bit_depth;
106 	long channel_map;
107 	long channel_config;
108 	long interleaving_style;
109 	long number_of_channels;
110 	long valid_bit_depth;
111 	long sample_type;
112 	long ret;
113 
114 	struct dai_values ssp_tr_data[] = {
115 		{"sampling_frequency", SND_CONFIG_TYPE_INTEGER, NULL, &sampling_frequency, NULL},
116 		{"bit_depth", SND_CONFIG_TYPE_INTEGER, NULL, &bit_depth, NULL},
117 		{"channel_map", SND_CONFIG_TYPE_INTEGER, NULL, &channel_map, NULL},
118 		{"channel_config", SND_CONFIG_TYPE_INTEGER, NULL, &channel_config, NULL},
119 		{"interleaving_style", SND_CONFIG_TYPE_INTEGER, NULL, &interleaving_style, NULL},
120 		{"number_of_channels", SND_CONFIG_TYPE_INTEGER, NULL, &number_of_channels, NULL},
121 		{"valid_bit_depth", SND_CONFIG_TYPE_INTEGER, NULL, &valid_bit_depth, NULL},
122 		{"sample_type", SND_CONFIG_TYPE_INTEGER, NULL, &sample_type, NULL},
123 	};
124 
125 	ret = find_set_values(&ssp_tr_data[0], ARRAY_SIZE(ssp_tr_data), cfg, top,
126 			      "Class.Base.tr_stop_config");
127 	if (ret < 0)
128 		return ret;
129 
130 	return ssp_tr_stop_set_params(nhlt, sampling_frequency, bit_depth, channel_map,
131 				      channel_config, interleaving_style, number_of_channels,
132 				      valid_bit_depth,sample_type);
133 }
134 
set_run_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)135 static int set_run_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
136 {
137 	long always_run;
138 	long ret;
139 
140 	struct dai_values ssp_run_data[] = {
141 		{"always_run", SND_CONFIG_TYPE_INTEGER, NULL, &always_run, NULL},
142 	};
143 
144 	ret = find_set_values(&ssp_run_data[0], ARRAY_SIZE(ssp_run_data), cfg, top,
145 			      "Class.Base.run_config");
146 	if (ret < 0)
147 		return ret;
148 
149 	return ssp_run_set_params(nhlt, always_run);
150 }
151 
set_node_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)152 static int set_node_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
153 {
154 	long sampling_rate;
155 	long node_id;
156 	long ret;
157 
158 	struct dai_values ssp_node_data[] = {
159 		{"node_id", SND_CONFIG_TYPE_INTEGER, NULL, &node_id, NULL},
160 		{"sampling_rate", SND_CONFIG_TYPE_INTEGER, NULL, &sampling_rate, NULL},
161 	};
162 
163 	ret = find_set_values(&ssp_node_data[0], ARRAY_SIZE(ssp_node_data), cfg, top,
164 			      "Class.Base.node_config");
165 	if (ret < 0)
166 		return ret;
167 
168 	return ssp_node_set_params(nhlt, node_id, sampling_rate);
169 }
170 
set_sync_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)171 static int set_sync_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
172 {
173 	long sync_denominator;
174 	long ret;
175 
176 	struct dai_values ssp_sync_data[] = {
177 		{"sync_denominator", SND_CONFIG_TYPE_INTEGER, NULL, &sync_denominator, NULL},
178 	};
179 
180 	ret = find_set_values(&ssp_sync_data[0], ARRAY_SIZE(ssp_sync_data), cfg, top,
181 			      "Class.Base.sync_config");
182 	if (ret < 0)
183 		return ret;
184 
185 	return ssp_sync_set_params(nhlt, sync_denominator);
186 }
187 
set_ext_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)188 static int set_ext_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
189 {
190 	long mclk_policy_override;
191 	long mclk_always_running;
192 	long mclk_starts_on_gtw_init;
193 	long mclk_starts_on_run;
194 	long mclk_starts_on_pause;
195 	long mclk_stops_on_pause;
196 	long mclk_stops_on_reset;
197 
198 	long bclk_policy_override;
199 	long bclk_always_running;
200 	long bclk_starts_on_gtw_init;
201 	long bclk_starts_on_run;
202 	long bclk_starts_on_pause;
203 	long bclk_stops_on_pause;
204 	long bclk_stops_on_reset;
205 
206 	long sync_policy_override;
207 	long sync_always_running;
208 	long sync_starts_on_gtw_init;
209 	long sync_starts_on_run;
210 	long sync_starts_on_pause;
211 	long sync_stops_on_pause;
212 	long sync_stops_on_reset;
213 	long ret;
214 
215 	struct dai_values ssp_ext_data[] = {
216 		{"mclk_policy_override", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_policy_override, NULL},
217 		{"mclk_always_running", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_always_running, NULL},
218 		{"mclk_starts_on_gtw_init", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_starts_on_gtw_init, NULL},
219 		{"mclk_starts_on_run", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_starts_on_run, NULL},
220 		{"mclk_starts_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_starts_on_pause, NULL},
221 		{"mclk_stops_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_stops_on_pause, NULL},
222 		{"mclk_stops_on_reset", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_stops_on_reset, NULL},
223 		{"bclk_policy_override", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_policy_override, NULL},
224 		{"bclk_always_running", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_always_running, NULL},
225 		{"bclk_starts_on_gtw_init", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_starts_on_gtw_init, NULL},
226 		{"bclk_starts_on_run", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_starts_on_run, NULL},
227 		{"bclk_starts_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_starts_on_pause, NULL},
228 		{"bclk_stops_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_stops_on_pause, NULL},
229 		{"bclk_stops_on_reset", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_stops_on_reset, NULL},
230 		{"sync_policy_override", SND_CONFIG_TYPE_INTEGER, NULL, &sync_policy_override, NULL},
231 		{"sync_always_running", SND_CONFIG_TYPE_INTEGER, NULL, &sync_always_running, NULL},
232 		{"sync_starts_on_gtw_init", SND_CONFIG_TYPE_INTEGER, NULL, &sync_starts_on_gtw_init, NULL},
233 		{"sync_starts_on_run", SND_CONFIG_TYPE_INTEGER, NULL, &sync_starts_on_run, NULL},
234 		{"sync_starts_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &sync_starts_on_pause, NULL},
235 		{"sync_stops_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &sync_stops_on_pause, NULL},
236 		{"sync_stops_on_reset", SND_CONFIG_TYPE_INTEGER, NULL, &sync_stops_on_reset, NULL},
237 	};
238 
239 	ret = find_set_values(&ssp_ext_data[0], ARRAY_SIZE(ssp_ext_data), cfg, top,
240 			      "Class.Base.ext_config");
241 	if (ret < 0)
242 		return ret;
243 
244 	return ssp_ext_set_params(nhlt, mclk_policy_override, mclk_always_running,
245 				  mclk_starts_on_gtw_init, mclk_starts_on_run, mclk_starts_on_pause,
246 				  mclk_stops_on_pause, mclk_stops_on_reset,
247 				  bclk_policy_override, bclk_always_running,
248 				  bclk_starts_on_gtw_init, bclk_starts_on_run, bclk_starts_on_pause,
249 				  bclk_stops_on_pause, bclk_stops_on_reset,
250 				  sync_policy_override, sync_always_running,
251 				  sync_starts_on_gtw_init, sync_starts_on_run, sync_starts_on_pause,
252 				  sync_stops_on_pause, sync_stops_on_reset);
253 }
254 
set_link_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)255 static int set_link_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
256 {
257 	long clock_source;
258 	long ret;
259 
260 	struct dai_values ssp_link_data[] = {
261 		{"clock_source", SND_CONFIG_TYPE_INTEGER, NULL, &clock_source, NULL},
262 	};
263 
264 	ret = find_set_values(&ssp_link_data[0], ARRAY_SIZE(ssp_link_data), cfg, top,
265 			      "Class.Base.link_config");
266 	if (ret < 0)
267 		return ret;
268 
269 	return ssp_link_set_params(nhlt, clock_source);
270 }
271 
set_aux_params(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)272 static int set_aux_params(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
273 {
274 	struct aux_map {
275 		const char *name;
276 		int id;
277 	};
278 
279 	struct aux_map aux_maps[] = {
280 		{ "Object.Base.mn_config", SSP_MN_DIVIDER_CONTROLS },
281 		{"Object.Base.clk_config", SSP_DMA_CLK_CONTROLS },
282 		{"Object.Base.tr_start_config", SSP_DMA_TRANSMISSION_START },
283 		{"Object.Base.tr_stop_config", SSP_DMA_TRANSMISSION_STOP },
284 		{"Object.Base.run_config", SSP_DMA_ALWAYS_RUNNING_MODE} ,
285 		{"Object.Base.sync_config", SSP_DMA_SYNC_DATA },
286 		{"Object.Base.ext_config", SSP_DMA_CLK_CONTROLS_EXT },
287 		{"Object.Base.link_config", SSP_LINK_CLK_SOURCE },
288 		{"Object.Base.node_config", SSP_DMA_SYNC_NODE },
289 	};
290 
291 	snd_config_iterator_t iter, next;
292 	snd_config_t *items, *n;
293 	const char *id;
294 	unsigned int i;
295 	int ret = 0;
296 
297 	for (i = 0; i < ARRAY_SIZE(aux_maps); i++) {
298 		if (snd_config_search(cfg, aux_maps[i].name, &items) < 0)
299 			continue;
300 
301 		snd_config_for_each(iter, next, items) {
302 			n = snd_config_iterator_entry(iter);
303 
304 			if (snd_config_get_id(n, &id) < 0)
305 				continue;
306 
307 			switch(aux_maps[i].id) {
308 			case SSP_MN_DIVIDER_CONTROLS:
309 				ret = set_mn_config(nhlt, n, top);
310 				break;
311 			case SSP_DMA_CLK_CONTROLS:
312 				ret = set_clk_config(nhlt, n, top);
313 				break;
314 			case SSP_DMA_TRANSMISSION_START:
315 				ret = set_tr_start_config(nhlt, n, top);
316 				break;
317 			case SSP_DMA_TRANSMISSION_STOP:
318 				ret = set_tr_stop_config(nhlt, n, top);
319 				break;
320 			case SSP_DMA_ALWAYS_RUNNING_MODE:
321 				ret = set_run_config(nhlt, n, top);
322 				break;
323 			case SSP_DMA_SYNC_DATA:
324 				ret = set_sync_config(nhlt, n, top);
325 				break;
326 			case SSP_DMA_CLK_CONTROLS_EXT:
327 				ret = set_ext_config(nhlt, n, top);
328 				break;
329 			case SSP_LINK_CLK_SOURCE:
330 				ret = set_link_config(nhlt, n, top);
331 				break;
332 			case SSP_DMA_SYNC_NODE:
333 				ret = set_node_config(nhlt, n, top);
334 				break;
335 			default:
336 				ret = -EINVAL;
337 			}
338 
339 			if (ret < 0)
340 				return ret;
341 		}
342 	}
343 
344 	return ret;
345 }
346 
set_hw_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)347 static int set_hw_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
348 {
349 	const char *format = NULL;
350 	const char *mclk = NULL;
351 	const char *bclk = NULL;
352 	const char *bclk_invert = NULL;
353 	const char *fsync = NULL;
354 	const char *fsync_invert = NULL;
355 	long mclk_freq = 0;
356 	long bclk_freq = 0;
357 	long fsync_freq = 0;
358 	long tdm_slots = 0;
359 	long tdm_slot_width = 0;
360 	long tx_slots = 0;
361 	long rx_slots = 0;
362 	long ret;
363 
364 	struct dai_values ssp_hw_data[] = {
365 		{"format", SND_CONFIG_TYPE_STRING, NULL, NULL, &format},
366 		{"mclk", SND_CONFIG_TYPE_STRING, NULL, NULL, &mclk},
367 		{"bclk", SND_CONFIG_TYPE_STRING, NULL, NULL, &bclk},
368 		{"fsync", SND_CONFIG_TYPE_STRING, NULL, NULL, &fsync},
369 		{"bclk_invert", SND_CONFIG_TYPE_STRING, NULL, NULL, &bclk_invert},
370 		{"fsync_invert", SND_CONFIG_TYPE_STRING, NULL, NULL, &fsync_invert},
371 		{"fsync_freq", SND_CONFIG_TYPE_INTEGER, NULL, &fsync_freq, NULL},
372 		{"bclk_freq", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_freq, NULL},
373 		{"mclk_freq", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_freq, NULL},
374 		{"tdm_slots", SND_CONFIG_TYPE_INTEGER, NULL, &tdm_slots, NULL},
375 		{"tdm_slot_width", SND_CONFIG_TYPE_INTEGER, NULL, &tdm_slot_width, NULL},
376 		{"tx_slots", SND_CONFIG_TYPE_INTEGER, NULL, &tx_slots, NULL},
377 		{"rx_slots", SND_CONFIG_TYPE_INTEGER, NULL, &rx_slots, NULL},
378 	};
379 
380 	ret = find_set_values(&ssp_hw_data[0], ARRAY_SIZE(ssp_hw_data), cfg, top,
381 			      "Class.Base.hw_config");
382 	if (ret < 0)
383 		return ret;
384 
385 	ret = set_aux_params(nhlt, cfg, top);
386 	if (ret < 0)
387 		return ret;
388 
389 	return ssp_hw_set_params(nhlt, format, mclk, bclk, bclk_invert, fsync, fsync_invert,
390 				 mclk_freq, bclk_freq, fsync_freq, tdm_slots, tdm_slot_width,
391 				 tx_slots, rx_slots);
392 }
393 
set_ssp_data(struct intel_nhlt_params *nhlt, snd_config_t *dai_cfg, snd_config_t *top)394 static int set_ssp_data(struct intel_nhlt_params *nhlt, snd_config_t *dai_cfg, snd_config_t *top)
395 {
396 	const char *tdm_padding_per_slot = NULL;
397 	const char *direction = NULL;
398 	const char *quirks = NULL;
399 	long frame_pulse_width = 0;
400 	long clks_control = 0;
401 	long sample_bits = 0;
402 	long bclk_delay = 0;
403 	long version = 0;
404 	long dai_index = 0;
405 	long mclk_id = 0;
406 	long io_clk = 0;
407 	int ret;
408 
409 	struct dai_values ssp_data[] = {
410 		{ "io_clk",  SND_CONFIG_TYPE_INTEGER, NULL, &io_clk, NULL},
411 		{ "direction", SND_CONFIG_TYPE_STRING, NULL, NULL, &direction},
412 		{ "quirks", SND_CONFIG_TYPE_STRING, NULL, NULL, &quirks},
413 		{ "dai_index", SND_CONFIG_TYPE_INTEGER, NULL, &dai_index, NULL},
414 		{ "sample_bits", SND_CONFIG_TYPE_INTEGER, NULL, &sample_bits, NULL},
415 		{ "bclk_delay", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_delay, NULL},
416 		{ "mclk_id", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_id, NULL},
417 		{ "clks_control", SND_CONFIG_TYPE_INTEGER, NULL, &clks_control, NULL},
418 		{ "frame_pulse_width", SND_CONFIG_TYPE_INTEGER, NULL, &frame_pulse_width, NULL},
419 		{ "tdm_padding_per_slot", SND_CONFIG_TYPE_STRING, NULL, NULL,
420 		  &tdm_padding_per_slot},
421 		{ "version", SND_CONFIG_TYPE_INTEGER, NULL, &version, NULL},
422 	};
423 
424 	ret = find_set_values(&ssp_data[0], ARRAY_SIZE(ssp_data), dai_cfg, top, "Class.Dai.SSP");
425 	if (ret < 0)
426 		return ret;
427 
428 	return ssp_set_params(nhlt, direction, dai_index, io_clk, bclk_delay, sample_bits, mclk_id,
429 			      clks_control, frame_pulse_width, tdm_padding_per_slot, quirks,
430 			      version);
431 }
432 
433 /* init ssp parameters, should be called before parsing dais */
nhlt_ssp_init_params(struct intel_nhlt_params *nhlt)434 int nhlt_ssp_init_params(struct intel_nhlt_params *nhlt)
435 {
436 	return ssp_init_params(nhlt);
437 }
438 
nhlt_ssp_get_ep_count(struct intel_nhlt_params *nhlt)439 int nhlt_ssp_get_ep_count(struct intel_nhlt_params *nhlt)
440 {
441 	return ssp_get_vendor_blob_count(nhlt);
442 }
443 
nhlt_ssp_get_dir(struct intel_nhlt_params *nhlt, int dai_index, uint8_t *dir)444 int nhlt_ssp_get_dir(struct intel_nhlt_params *nhlt, int dai_index, uint8_t *dir)
445 {
446 	return ssp_get_dir(nhlt, dai_index, dir);
447 }
448 
nhlt_ssp_get_ep(struct intel_nhlt_params *nhlt, struct endpoint_descriptor **eps, int dai_index, uint8_t dir)449 int nhlt_ssp_get_ep(struct intel_nhlt_params *nhlt, struct endpoint_descriptor **eps,
450 		    int dai_index, uint8_t dir)
451 {
452 	struct endpoint_descriptor ep;
453 	struct ssp_device_specific_config ssp_conf;
454 	struct formats_config f_conf;
455 	struct format_config f_conf1[8];
456 	uint32_t sample_rate;
457 	uint16_t channel_count;
458 	uint32_t bits_per_sample;
459 	uint32_t virtualbus_id;
460 	uint32_t formats_count;
461 	uint32_t device_type;
462 	uint32_t direction = dir;
463 	uint8_t *ep_target;
464 	size_t blob_size;
465 	int ret;
466 	int i;
467 
468 	/*
469 	 * nhlt ssp structure:
470 	 *
471 	 * endpoint_descriptor, sizeof(struct endpoint_descriptor)
472 	 * device_specific_config (headset), sizeof(struct ssp_device_specific_config)
473 	 * formats_config (formats_count), sizeof(struct formats_config)
474 	 * format_config (waveex), sizeof(struct format_config)
475 	 * vendor_blob sizeof(vendor_blob)
476 	 */
477 
478 	ret = ssp_get_params(nhlt, dai_index, &virtualbus_id, &formats_count,
479 			     &device_type, &direction);
480 	if (ret < 0) {
481 		fprintf(stderr, "nhlt_ssp_get_ep: ssp_get_params failed\n");
482 		return ret;
483 	}
484 
485 	ep.link_type = NHLT_LINK_TYPE_SSP;
486 	ep.instance_id = 0;
487 	ep.vendor_id = NHLT_VENDOR_ID_INTEL;
488 	ep.device_id = NHLT_DEVICE_ID_INTEL_I2S_TDM;
489 	ep.revision_id = 0;
490 	ep.subsystem_id = 0;
491 	ep.device_type = device_type;
492 
493 	ep.direction = direction;
494 	/* ssp device index */
495 	ep.virtualbus_id = virtualbus_id;
496 	/* ssp config */
497 	ssp_conf.config.capabilities_size = 2;
498 	ssp_conf.device_config.virtual_slot = 0;
499 	ssp_conf.device_config.config_type = 0;
500 
501 	/* formats_config */
502 	f_conf.formats_count = formats_count;
503 
504 	for (i = 0; i < f_conf.formats_count; i++) {
505 		/* fill in wave format extensible types */
506 		f_conf1[i].format.wFormatTag = 0xFFFE;
507 
508 		ret = ssp_get_hw_params(nhlt, dai_index, i, &sample_rate, &channel_count,
509 					&bits_per_sample);
510 
511 		if (ret < 0) {
512 			fprintf(stderr, "nhlt_ssp_get_ep: ssp_get_hw_params failed\n");
513 			return ret;
514 		}
515 
516 		f_conf1[i].format.nChannels = channel_count;
517 		f_conf1[i].format.nSamplesPerSec = sample_rate;
518 		f_conf1[i].format.wBitsPerSample = bits_per_sample;
519 		f_conf1[i].format.nBlockAlign = channel_count * bits_per_sample / 8;
520 		f_conf1[i].format.nAvgBytesPerSec = sample_rate * f_conf1[i].format.nBlockAlign;
521 
522 		/* bytes after this value in this struct */
523 		f_conf1[i].format.cbSize = 22;
524 		/* actual bits in container */
525 		f_conf1[i].format.wValidBitsPerSample = bits_per_sample;
526 		/* channel map not used at this time */
527 		f_conf1[i].format.dwChannelMask = 0;
528 		/* WAVE_FORMAT_PCM guid (0x0001) ? */
529 		f_conf1[i].format.SubFormat[0] = 0;
530 		f_conf1[i].format.SubFormat[1] = 0;
531 		f_conf1[i].format.SubFormat[2] = 0;
532 		f_conf1[i].format.SubFormat[3] = 0;
533 
534 		ret = ssp_get_vendor_blob_size(nhlt, dai_index, i, &blob_size);
535 		if (ret < 0) {
536 			fprintf(stderr, "nhlt_ssp_get_ep: dmic_get_vendor_blob_size failed\n");
537 			return ret;
538 		}
539 		f_conf1[i].vendor_blob.capabilities_size = blob_size;
540 	}
541 
542 	ep.length = sizeof(struct endpoint_descriptor) +
543 		sizeof(struct ssp_device_specific_config) +
544 		sizeof(struct formats_config) +
545 		sizeof(struct format_config) * f_conf.formats_count +
546 		blob_size * f_conf.formats_count;
547 
548 	/* allocate the final variable length ep struct */
549 	ep_target = calloc(ep.length, sizeof(uint8_t));
550 	if (!ep_target)
551 		return -ENOMEM;
552 
553 	*eps = (struct endpoint_descriptor *)ep_target;
554 
555 	/* copy all parsed sub arrays into the top level array */
556 	memcpy(ep_target, &ep, sizeof(struct endpoint_descriptor));
557 
558 	ep_target += sizeof(struct endpoint_descriptor);
559 
560 	memcpy(ep_target, &ssp_conf, sizeof(struct ssp_device_specific_config));
561 	ep_target += sizeof(struct ssp_device_specific_config);
562 
563 	memcpy(ep_target, &f_conf, sizeof(struct formats_config));
564 	ep_target += sizeof(struct formats_config);
565 
566 	/* copy all hw configs */
567 	for (i = 0; i < f_conf.formats_count; i++) {
568 		memcpy(ep_target, &f_conf1[i], sizeof(struct format_config));
569 		ep_target += sizeof(struct format_config);
570 		ret = ssp_get_vendor_blob(nhlt, ep_target, dai_index, i);
571 		if (ret < 0) {
572 			fprintf(stderr, "nhlt_sso_get_ep: ssp_get_vendor_blob failed\n");
573 			return ret;
574 		}
575 		ep_target += blob_size;
576 	}
577 
578 	return 0;
579 }
580 
581 /* Set ssp parameters from topology for ssp coefficient calculation.
582  *
583  * You can see an example of topology v2 config of ssp below. In this example the default
584  * object parameters are spelled out for clarity. General parameters like sample_bits are parsed
585  * with set_ssp_data and hw_config object data with set_hw_data. Ssp can have multiple hw_configs.
586  * Values are saved into intermediate structs and the vendor specific blob is calculated at the end
587  * of parsing with ssp_calculate.
588  *
589  * 	SSP."0" {
590  *		id 			0
591  *		direction		"duplex"
592  *		name			NoCodec-0
593  *		io_clk			38400000
594  *		default_hw_conf_id	0
595  *		sample_bits		16
596  *		quirks			"lbm_mode"
597  *		bclk_delay		0
598  *		mclk_id 		0
599  *		clks_control 		0
600  *		frame_pulse_width	0
601  *		tdm_padding_per_slot	false
602  *
603  *		Object.Base.hw_config."SSP0" {
604  *			id	0
605  *			mclk_freq	24576000
606  *			bclk_freq	3072000
607  *			tdm_slot_width	32
608  *			format		"I2S"
609  *			mclk		"codec_mclk_in"
610  *			bclk		"codec_consumer"
611  *			fsync		"codec_consumer"
612  *			fsync_freq	48000
613  *			tdm_slots	2
614  *			tx_slots	3
615  *			rx_slots	3
616  *		}
617  *	}
618  */
nhlt_ssp_set_params(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)619 int nhlt_ssp_set_params(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
620 {
621 	snd_config_iterator_t i, next;
622 	snd_config_t *items;
623 	snd_config_t *n;
624 	const char *id;
625 	int ret;
626 
627 	ret = set_ssp_data(nhlt, cfg, top);
628 	if (ret < 0)
629 		return ret;
630 
631 	ret = snd_config_search(cfg, "Object.Base.hw_config", &items);
632 	if (ret < 0)
633 		return ret;
634 
635 	snd_config_for_each(i, next, items) {
636 		n = snd_config_iterator_entry(i);
637 
638 		if (snd_config_get_id(n, &id) < 0)
639 			continue;
640 
641 		ret = set_hw_config(nhlt, n, top);
642 		if (ret < 0)
643 			return ret;
644 	}
645 
646 	ret = ssp_calculate(nhlt);
647 
648 	return ret;
649 }
650