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/global.h>
14 #include <alsa/input.h>
15 #include <alsa/output.h>
16 #include <alsa/conf.h>
17 #include <alsa/error.h>
18 #include "dmic-nhlt.h"
19 #include "dmic/dmic-process.h"
20 
set_dmic_data(struct intel_nhlt_params *nhlt, snd_config_t *dai_cfg, snd_config_t *top)21 static int set_dmic_data(struct intel_nhlt_params *nhlt, snd_config_t *dai_cfg, snd_config_t *top)
22 {
23 	long unmute_ramp_time_ms = 0;
24 	long fifo_word_length = 0;
25 	long driver_version = 0;
26 	long num_pdm_active = 0;
27 	long sample_rate = 0;
28 	long dai_index_t = 0;
29 	long duty_min = 0;
30 	long duty_max = 0;
31 	long clk_min = 0;
32 	long clk_max = 0;
33 	long io_clk = 0;
34 	int ret;
35 
36 	struct dai_values dmic_data[] = {
37 		{ "driver_version", SND_CONFIG_TYPE_INTEGER, NULL, &driver_version, NULL},
38 		{ "io_clk", SND_CONFIG_TYPE_INTEGER, NULL, &io_clk, NULL},
39 		{ "dai_index", SND_CONFIG_TYPE_INTEGER, NULL, &dai_index_t, NULL},
40 		{ "num_pdm_active", SND_CONFIG_TYPE_INTEGER, NULL, &num_pdm_active, NULL},
41 		{ "fifo_word_length", SND_CONFIG_TYPE_INTEGER, NULL, &fifo_word_length, NULL},
42 		{ "clk_min", SND_CONFIG_TYPE_INTEGER, NULL, &clk_min, NULL},
43 		{ "clk_max", SND_CONFIG_TYPE_INTEGER, NULL, &clk_max, NULL},
44 		{ "duty_min", SND_CONFIG_TYPE_INTEGER, NULL, &duty_min, NULL},
45 		{ "duty_max", SND_CONFIG_TYPE_INTEGER, NULL, &duty_max, NULL},
46 		{ "sample_rate", SND_CONFIG_TYPE_INTEGER, NULL, &sample_rate, NULL},
47 		{ "unmute_ramp_time_ms", SND_CONFIG_TYPE_INTEGER, NULL, &unmute_ramp_time_ms, NULL},
48 	};
49 
50 	ret = find_set_values(&dmic_data[0], ARRAY_SIZE(dmic_data), dai_cfg, top, "Class.Dai.DMIC");
51 	if (ret < 0)
52 		return ret;
53 
54 	return dmic_set_params(nhlt, dai_index_t, driver_version, io_clk, num_pdm_active,
55 			       fifo_word_length, clk_min, clk_max, duty_min, duty_max, sample_rate,
56 			       unmute_ramp_time_ms);
57 }
58 
set_pdm_data(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)59 static int set_pdm_data(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
60 {
61 	long mic_a_enable = 0;
62 	long mic_b_enable = 0;
63 	long polarity_a = 0;
64 	long polarity_b = 0;
65 	long clk_edge = 0;
66 	long ctrl_id = 0;
67 	long skew = 0;
68 	int ret;
69 
70 	struct dai_values dmic_pdm_data[] = {
71 		{ "mic_a_enable", SND_CONFIG_TYPE_INTEGER, NULL, &mic_a_enable, NULL},
72 		{ "mic_b_enable", SND_CONFIG_TYPE_INTEGER, NULL, &mic_b_enable, NULL},
73 		{ "polarity_a", SND_CONFIG_TYPE_INTEGER, NULL, &polarity_a, NULL},
74 		{ "polarity_b", SND_CONFIG_TYPE_INTEGER, NULL, &polarity_b, NULL},
75 		{ "clk_edge", SND_CONFIG_TYPE_INTEGER, NULL, &clk_edge, NULL},
76 		{ "ctrl_id", SND_CONFIG_TYPE_INTEGER, NULL, &ctrl_id, NULL},
77 		{ "skew", SND_CONFIG_TYPE_INTEGER, NULL, &skew, NULL},
78 	};
79 
80 	ret = find_set_values(&dmic_pdm_data[0], ARRAY_SIZE(dmic_pdm_data), cfg, top,
81 			      "Class.Base.pdm_config");
82 	if (ret < 0)
83 		return ret;
84 
85 	return dmic_set_pdm_params(nhlt, ctrl_id, mic_a_enable, mic_b_enable, polarity_a,
86 				   polarity_b, clk_edge, skew);
87 }
88 
set_mic_data(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)89 static int set_mic_data(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
90 {
91 	long sensitivity = 0;
92 	long snr = 0;
93 	int ret;
94 
95 	struct dai_values dmic_mic_data[] = {
96 		{ "snr", SND_CONFIG_TYPE_INTEGER, NULL, &snr, NULL},
97 		{ "sensitivity", SND_CONFIG_TYPE_INTEGER, NULL, &snr, NULL},
98 	};
99 
100 	ret = find_set_values(&dmic_mic_data[0], ARRAY_SIZE(dmic_mic_data), cfg, top,
101 			      "Class.Base.mic_extension");
102 	if (ret < 0)
103 		return ret;
104 
105 	return dmic_set_ext_params(nhlt, snr, sensitivity);
106 }
107 
set_vendor_mic_data(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)108 static int set_vendor_mic_data(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
109 {
110 	long speaker_position_distance = 0;
111 	long horizontal_angle_begin = 0;
112 	long horizontal_angle_end = 0;
113 	long vertical_angle_begin = 0;
114 	long vertical_angle_end = 0;
115 	long frequency_high_band = 0;
116 	long frequency_low_band = 0;
117 	long horizontal_offset = 0;
118 	long vertical_offset = 0;
119 	long direction_angle = 0;
120 	long elevation_angle = 0;
121 	long mic_type = 0;
122 	long location = 0;
123 	long mic_id = 0;
124 	int ret;
125 
126 	struct dai_values dmic_vendor_data[] = {
127 		{ "mic_id", SND_CONFIG_TYPE_INTEGER, NULL, &mic_id, NULL},
128 		{ "mic_type", SND_CONFIG_TYPE_INTEGER, NULL, &mic_type, NULL},
129 		{ "location", SND_CONFIG_TYPE_INTEGER, NULL, &location, NULL},
130 		{ "speaker_position_distance", SND_CONFIG_TYPE_INTEGER, NULL,
131 		  &speaker_position_distance, NULL},
132 		{ "horizontal_offset", SND_CONFIG_TYPE_INTEGER, NULL, &horizontal_offset, NULL},
133 		{ "vertical_offset", SND_CONFIG_TYPE_INTEGER, NULL, &vertical_offset, NULL},
134 		{ "frequency_low_band", SND_CONFIG_TYPE_INTEGER, NULL, &frequency_low_band, NULL},
135 		{ "frequency_high_band", SND_CONFIG_TYPE_INTEGER, NULL, &frequency_high_band, NULL},
136 		{ "direction_angle", SND_CONFIG_TYPE_INTEGER, NULL, &direction_angle, NULL},
137 		{ "elevation_angle", SND_CONFIG_TYPE_INTEGER, NULL, &elevation_angle, NULL},
138 		{ "vertical_angle_begin", SND_CONFIG_TYPE_INTEGER, NULL, &vertical_angle_begin,
139 		  NULL},
140 		{ "vertical_angle_end", SND_CONFIG_TYPE_INTEGER, NULL, &vertical_angle_end, NULL},
141 		{ "horizontal_angle_begin", SND_CONFIG_TYPE_INTEGER, NULL, &horizontal_angle_begin,
142 		  NULL},
143 		{ "horizontal_angle_end", SND_CONFIG_TYPE_INTEGER, NULL, &horizontal_angle_end,
144 		  NULL},
145 	};
146 
147 	ret = find_set_values(&dmic_vendor_data[0], ARRAY_SIZE(dmic_vendor_data), cfg, top,
148 			      "Class.Base.vendor_mic_config");
149 	if (ret < 0)
150 		return ret;
151 
152 	return dmic_set_mic_params(nhlt, mic_id, mic_type, location, speaker_position_distance,
153 				   horizontal_offset, vertical_offset, frequency_low_band,
154 				   frequency_high_band, direction_angle, elevation_angle,
155 				   vertical_angle_begin, vertical_angle_end, horizontal_angle_begin,
156 				   horizontal_angle_end);
157 }
158 
set_bytes_data(struct intel_nhlt_params *nhlt ATTRIBUTE_UNUSED, snd_config_t *cfg)159 static int set_bytes_data(struct intel_nhlt_params *nhlt ATTRIBUTE_UNUSED, snd_config_t *cfg)
160 {
161 	snd_config_iterator_t i, next;
162 	snd_config_t *n;
163 	const char *bytes;
164 	const char *id;
165 
166 	if (snd_config_get_id(cfg, &id) < 0)
167 		return -EINVAL;
168 
169 	if (strcmp(id, "fir_coeffs"))
170 		return 0;
171 
172 	snd_config_for_each(i, next, cfg) {
173 		n = snd_config_iterator_entry(i);
174 
175 		if (snd_config_get_string(n, &bytes))
176 			return -EINVAL;
177 	}
178 
179 	return 0;
180 }
181 
182 /* init dmic parameters, should be called before parsing dais */
nhlt_dmic_init_params(struct intel_nhlt_params *nhlt)183 int nhlt_dmic_init_params(struct intel_nhlt_params *nhlt)
184 {
185 	return dmic_init_params(nhlt);
186 }
187 
188 /* get dmic endpoint count */
nhlt_dmic_get_ep_count(struct intel_nhlt_params *nhlt)189 int nhlt_dmic_get_ep_count(struct intel_nhlt_params *nhlt)
190 {
191 	return dmic_get_vendor_blob_count(nhlt);
192 }
193 
nhlt_dmic_get_ep(struct intel_nhlt_params *nhlt, struct endpoint_descriptor **eps, int index)194 int nhlt_dmic_get_ep(struct intel_nhlt_params *nhlt, struct endpoint_descriptor **eps,
195 		     int index)
196 {
197 	struct endpoint_descriptor ep;
198 	struct mic_array_device_specific_config mic_s_conf;
199 	struct mic_array_device_specific_vendor_config mic_v_conf;
200 	struct mic_snr_sensitivity_extension mic_ext;
201 	struct mic_vendor_config mic_conf;
202 	struct formats_config f_conf;
203 	struct format_config f_conf1;
204 	uint8_t *ep_target;
205 	size_t blob_size;
206 	int ret;
207 	int i;
208 
209 	size_t mic_config_size;
210 	uint32_t sample_rate;
211 	uint16_t channel_count;
212 	uint32_t bits_per_sample;
213 	uint8_t array_type;
214 	uint8_t extension;
215 	uint8_t num_mics;
216 	uint32_t snr;
217 	uint32_t sensitivity;
218 
219 	uint8_t type;
220 	uint8_t panel;
221 	uint32_t speaker_position_distance;
222 	uint32_t horizontal_offset;
223 	uint32_t vertical_offset;
224 	uint8_t frequency_low_band;
225 	uint8_t frequency_high_band;
226 	uint16_t direction_angle;
227 	uint16_t elevation_angle;
228 	uint16_t vertical_angle_begin;
229 	uint16_t vertical_angle_end;
230 	uint16_t horizontal_angle_begin;
231 	uint16_t horizontal_angle_end;
232 
233 	/*
234 	 * nhlt dmic structure:
235 	 *
236 	 * endpoint_descriptor, sizeof(struct endpoint_descriptor)
237 	 *
238 	 * device_specific_config (mic), sizeof(mic_array_device_specific_config)
239 	 * or
240 	 * device_specific_config (mic), sizeof(mic_array_device_specific_vendor_config)
241 	 *
242 	 * formats_config (formats_count), sizeof(struct formats_config)
243 	 * format_config (waveex), sizeof(struct format_config)
244 	 * vendor_blob sizeof(vendor_blob)
245 	 */
246 
247 	/* dmic ep */
248 	ep.link_type = NHLT_LINK_TYPE_PDM;
249 	ep.instance_id = 0;
250 	ep.vendor_id = NHLT_VENDOR_ID_INTEL;
251 	ep.device_id = NHLT_DEVICE_ID_INTEL_PDM_DMIC;
252 	ep.revision_id = 0;
253 	ep.subsystem_id = 0;
254 	ep.device_type = 0;
255 	ep.direction = NHLT_ENDPOINT_DIRECTION_CAPTURE;
256 	ep.virtualbus_id = index;
257 
258 	ret = dmic_get_params(nhlt, index, &sample_rate, &channel_count, &bits_per_sample,
259 			      &array_type, &num_mics, &extension, &snr, &sensitivity);
260 
261 	if (ret) {
262 		fprintf(stderr, "nhlt_dmic_get_ep: dmic_get_params failed\n");
263 		return ret;
264 	}
265 
266 	if (array_type == NHLT_MIC_ARRAY_TYPE_VENDOR_DEFINED) {
267 		mic_v_conf.config.capabilities_size = 4 + num_mics *
268 			sizeof(struct mic_vendor_config);
269 		mic_v_conf.device_config.virtual_slot = 0; /* always 0 for dmic */
270 		mic_v_conf.device_config.config_type = NHLT_DEVICE_CONFIG_TYPE_MICARRAY;
271 		mic_v_conf.number_of_microphones = num_mics;
272 		mic_v_conf.array_type_ex = array_type;
273 		/* precense of extension struct is coded into lower 4 bits of array_type */
274 		if (extension) {
275 			mic_v_conf.array_type_ex = (array_type & ~0x0F) | (0x01 & 0x0F);
276 			mic_v_conf.config.capabilities_size +=
277 				sizeof(struct mic_snr_sensitivity_extension);
278 		}
279 	} else {
280 		mic_s_conf.config.capabilities_size = 3;
281 		mic_s_conf.device_config.virtual_slot = 0; /* always 0 for dmic */
282 		mic_s_conf.device_config.config_type = NHLT_DEVICE_CONFIG_TYPE_MICARRAY;
283 		mic_s_conf.array_type_ex = array_type;
284 		/* presense of extension struct coded into lower 4 bits of array_type */
285 		if (extension) {
286 			mic_s_conf.array_type_ex = (array_type & ~0x0F) | (0x01 & 0x0F);
287 			mic_s_conf.config.capabilities_size +=
288 				sizeof(struct mic_snr_sensitivity_extension);
289 		}
290 	}
291 
292 	/* formats_config */
293 	f_conf.formats_count = 1;
294 
295 	/* fill in wave format extensible types */
296 	f_conf1.format.wFormatTag = 0xFFFE;
297 	f_conf1.format.nSamplesPerSec = sample_rate;
298 	f_conf1.format.nChannels = channel_count;
299 	f_conf1.format.wBitsPerSample = bits_per_sample;
300 	f_conf1.format.nBlockAlign = channel_count * bits_per_sample / 8;
301 	f_conf1.format.nAvgBytesPerSec = f_conf1.format.nSamplesPerSec * f_conf1.format.nBlockAlign;
302 
303 	/* bytes after this value in this struct */
304 	f_conf1.format.cbSize = 22;
305 	/* actual bits in container */
306 	f_conf1.format.wValidBitsPerSample = bits_per_sample;
307 	/* channel map not used at this time */
308 	f_conf1.format.dwChannelMask = 0;
309 	/* WAVE_FORMAT_PCM guid (0x0001) ? */
310 	f_conf1.format.SubFormat[0] = 0;
311 	f_conf1.format.SubFormat[1] = 0;
312 	f_conf1.format.SubFormat[2] = 0;
313 	f_conf1.format.SubFormat[3] = 0;
314 
315 	ret = dmic_get_vendor_blob_size(nhlt, &blob_size);
316 	if (ret) {
317 		fprintf(stderr, "nhlt_dmic_get_ep: dmic_get_vendor_blob_size failed\n");
318 		return ret;
319 	}
320 
321 	f_conf1.vendor_blob.capabilities_size = blob_size;
322 
323 	if (array_type == NHLT_MIC_ARRAY_TYPE_VENDOR_DEFINED)
324 		mic_config_size = sizeof(struct mic_array_device_specific_vendor_config) +
325 			num_mics * sizeof(struct mic_vendor_config);
326 	else
327 		mic_config_size = sizeof(struct mic_array_device_specific_config);
328 
329 	if (extension)
330 		mic_config_size = sizeof(struct mic_snr_sensitivity_extension);
331 
332 	ep.length = sizeof(struct endpoint_descriptor) +
333 		mic_config_size +
334 		sizeof(struct formats_config) +
335 		sizeof(struct format_config) +
336 		blob_size;
337 
338 	/* allocate the final variable length ep struct */
339 	ep_target = calloc(ep.length, sizeof(uint8_t));
340 	if (!ep_target)
341 		return -ENOMEM;
342 
343 	*eps = (struct endpoint_descriptor *)ep_target;
344 
345 	/* copy all parsed sub arrays into the top level array */
346 	memcpy(ep_target, &ep, sizeof(struct endpoint_descriptor));
347 
348 	ep_target += sizeof(struct endpoint_descriptor);
349 
350 	if (array_type == NHLT_MIC_ARRAY_TYPE_VENDOR_DEFINED) {
351 		memcpy(ep_target, &mic_v_conf,
352 		       sizeof(struct mic_array_device_specific_vendor_config));
353 		ep_target += sizeof(struct mic_array_device_specific_vendor_config);
354 		for (i = 0; i < num_mics; i++) {
355 			ret = dmic_get_mic_params(nhlt, i, &type,
356 						  &panel, &speaker_position_distance,
357 						  &horizontal_offset, &vertical_offset,
358 						  &frequency_low_band, &frequency_high_band,
359 						  &direction_angle, &elevation_angle,
360 						  &vertical_angle_begin, &vertical_angle_end,
361 						  &horizontal_angle_begin, &horizontal_angle_end);
362 
363 			if (ret) {
364 				fprintf(stderr, "nhlt_dmic_get_ep: dmic_get_mic_params failed\n");
365 				return ret;
366 			}
367 
368 			mic_conf.type = type;
369 			mic_conf.panel = panel;
370 			mic_conf.speaker_position_distance = speaker_position_distance;
371 			mic_conf.horizontal_offset = horizontal_offset;
372 			mic_conf.vertical_offset = vertical_offset;
373 			mic_conf.frequency_low_band = frequency_low_band;
374 			mic_conf.frequency_high_band = frequency_high_band;
375 			mic_conf.direction_angle = direction_angle;
376 			mic_conf.elevation_angle = elevation_angle;
377 			mic_conf.vertical_angle_begin = vertical_angle_begin;
378 			mic_conf.vertical_angle_end = vertical_angle_end;
379 			mic_conf.horizontal_angle_begin = horizontal_angle_begin;
380 			mic_conf.horizontal_angle_end = horizontal_angle_end;
381 
382 			memcpy(ep_target, &mic_conf, sizeof(struct mic_vendor_config));
383 			ep_target += sizeof(struct mic_vendor_config);
384 		}
385 	} else {
386 		memcpy(ep_target, &mic_s_conf, sizeof(struct mic_array_device_specific_config));
387 		ep_target += sizeof(struct mic_array_device_specific_config);
388 	}
389 
390 	if (extension) {
391 		mic_ext.snr = snr;
392 		mic_ext.sensitivity = sensitivity;
393 		memcpy(ep_target, &mic_ext, sizeof(struct mic_snr_sensitivity_extension));
394 		ep_target += sizeof(struct mic_snr_sensitivity_extension);
395 	}
396 
397 	memcpy(ep_target, &f_conf, sizeof(struct formats_config));
398 	ep_target += sizeof(struct formats_config);
399 
400 	memcpy(ep_target, &f_conf1, sizeof(struct format_config));
401 	ep_target += sizeof(struct format_config);
402 
403 	ret = dmic_get_vendor_blob(nhlt, ep_target);
404 	if (ret) {
405 		fprintf(stderr, "nhlt_dmic_get_ep: dmic_get_vendor_blob failed\n");
406 		return ret;
407 	}
408 
409 	return 0;
410 }
411 
412 /*
413  * Set dmic parameters from topology for dmic coefficient calculation.
414  *
415  * Coefficients are recalculated in case of multiple DAIs in topology and might affect each other.
416  *
417  * You can see an example of topology v2 config of dmic below. In this example the default
418  * object parameters are spelled out for clarity. General parameters like clk_min are parsed with
419  * set_dmic_data and pdm object data with set_pdm_data. Number of pdm's can vary from 1 to 2. Values
420  * are saved into intermediate structs and the vendor specific blob is calculated at the end of
421  * parsing with dmic_calculate.
422  *
423  *	DMIC."0" {
424  *		name NoCodec-6
425  *		id 6
426  *		index 0
427  *		driver_version		1
428  *		io_clk                  38400000
429  *		clk_min			500000
430  *		clk_max			4800000
431  *		duty_min		40
432  *		duty_max		60
433  *		sample_rate		48000
434  *		fifo_word_length	16
435  *		unmute_ramp_time_ms	200
436  *		num_pdm_active          2
437  *
438  *		# PDM controller config
439  *		Object.Base.pdm_config."0" {
440  *			ctrl_id	0
441  *			mic_a_enable	1
442  *			mic_b_enable	1
443  *			polarity_a	0
444  *			polarity_b	0
445  *			clk_edge	0
446  *			skew		0
447  *		}
448  *      }
449  */
nhlt_dmic_set_params(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)450 int nhlt_dmic_set_params(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
451 {
452 	snd_config_t *items;
453 	int ret;
454 	snd_config_iterator_t i, next;
455 	snd_config_t *n;
456 	const char *id;
457 
458 	/* set basic dmic data */
459 	ret = set_dmic_data(nhlt, cfg, top);
460 	if (ret < 0)
461 		return ret;
462 
463 	/* we need to have at least one pdm object */
464 	ret = snd_config_search(cfg, "Object.Base.pdm_config", &items);
465 	if (ret < 0)
466 		return ret;
467 
468 	snd_config_for_each(i, next, items) {
469 		n = snd_config_iterator_entry(i);
470 
471 		if (snd_config_get_id(n, &id) < 0)
472 			continue;
473 
474 		ret = set_pdm_data(nhlt, n, top);
475 		if (ret < 0)
476 			return ret;
477 	}
478 
479 	/* check for microphone parameter configuration */
480 	ret = snd_config_search(cfg, "Object.Base.mic_extension", &items);
481 	if (!ret) {
482 		snd_config_for_each(i, next, items) {
483 			n = snd_config_iterator_entry(i);
484 
485 			if (snd_config_get_id(n, &id) < 0)
486 				continue;
487 
488 			ret = set_mic_data(nhlt, n, top);
489 			if (ret < 0)
490 				return ret;
491 		}
492 	}
493 
494 	/* check for microphone parameter configuration */
495 	ret = snd_config_search(cfg, "Object.Base.vendor_mic_config", &items);
496 	if (!ret) {
497 		snd_config_for_each(i, next, items) {
498 			n = snd_config_iterator_entry(i);
499 
500 			if (snd_config_get_id(n, &id) < 0)
501 				continue;
502 
503 			set_vendor_mic_data(nhlt, n, top);
504 		}
505 	}
506 
507 	/* check for optional filter coeffs */
508 	ret = snd_config_search(cfg, "Object.Base.data", &items);
509 	if (!ret) {
510 		snd_config_for_each(i, next, items) {
511 			n = snd_config_iterator_entry(i);
512 
513 			if (snd_config_get_id(n, &id) < 0)
514 				continue;
515 
516 			set_bytes_data(nhlt, n);
517 		}
518 	}
519 
520 	ret = dmic_calculate(nhlt);
521 
522 	return ret;
523 }
524