1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause
2c72fcc34Sopenharmony_ci//
3c72fcc34Sopenharmony_ci// Copyright(c) 2021 Intel Corporation. All rights reserved.
4c72fcc34Sopenharmony_ci//
5c72fcc34Sopenharmony_ci// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
6c72fcc34Sopenharmony_ci//         Jaska Uimonen <jaska.uimonen@linux.intel.com>
7c72fcc34Sopenharmony_ci
8c72fcc34Sopenharmony_ci#include "aconfig.h"
9c72fcc34Sopenharmony_ci#include <stdint.h>
10c72fcc34Sopenharmony_ci#include <errno.h>
11c72fcc34Sopenharmony_ci#include <stdio.h>
12c72fcc34Sopenharmony_ci#include <stdlib.h>
13c72fcc34Sopenharmony_ci#include <string.h>
14c72fcc34Sopenharmony_ci#include <alsa/input.h>
15c72fcc34Sopenharmony_ci#include <alsa/output.h>
16c72fcc34Sopenharmony_ci#include <alsa/conf.h>
17c72fcc34Sopenharmony_ci#include <alsa/error.h>
18c72fcc34Sopenharmony_ci#include "../intel-nhlt.h"
19c72fcc34Sopenharmony_ci#include "dmic-process.h"
20c72fcc34Sopenharmony_ci#include "dmic-internal.h"
21c72fcc34Sopenharmony_ci#include "pdm-decim-fir.h"
22c72fcc34Sopenharmony_ci#include "dmic-debug.h"
23c72fcc34Sopenharmony_ci
24c72fcc34Sopenharmony_ci/* Note 1: Higher spec filter must be before lower spec filter if there are multiple filters for a
25c72fcc34Sopenharmony_ci * decimation factor. The first filter is skipped if the length is too much vs. overrun limit. If
26c72fcc34Sopenharmony_ci * other order the better filter would be never selected.
27c72fcc34Sopenharmony_ci *
28c72fcc34Sopenharmony_ci * Note 2: The introduction order of FIR decimation factors is the selection preference order.
29c72fcc34Sopenharmony_ci * The decimation factor 5 and 10 (2*5) cause a often less compatible output sample rate for CIC so
30c72fcc34Sopenharmony_ci * they are not used if there other suitable nearby values.
31c72fcc34Sopenharmony_ci *
32c72fcc34Sopenharmony_ci * The naming scheme of coefficients set is:
33c72fcc34Sopenharmony_ci * <type>_<decim factor>_<rel passband>_<rel stopband>_<ripple>_<attenuation>
34c72fcc34Sopenharmony_ci */
35c72fcc34Sopenharmony_cistruct pdm_decim *fir_list[] = {
36c72fcc34Sopenharmony_ci	&pdm_decim_int32_02_4375_5100_010_095,
37c72fcc34Sopenharmony_ci	&pdm_decim_int32_02_4323_5100_010_095,
38c72fcc34Sopenharmony_ci	&pdm_decim_int32_03_4375_5100_010_095,
39c72fcc34Sopenharmony_ci	&pdm_decim_int32_04_4318_5100_010_095,
40c72fcc34Sopenharmony_ci	&pdm_decim_int32_06_4172_5100_010_095,
41c72fcc34Sopenharmony_ci	&pdm_decim_int32_05_4325_5100_010_095,
42c72fcc34Sopenharmony_ci	&pdm_decim_int32_08_4156_5301_010_090,
43c72fcc34Sopenharmony_ci	&pdm_decim_int32_12_4156_5345_010_090,
44c72fcc34Sopenharmony_ci	&pdm_decim_int32_10_4156_5345_010_090,
45c72fcc34Sopenharmony_ci	NULL, /* This marks the end of coefficients */
46c72fcc34Sopenharmony_ci};
47c72fcc34Sopenharmony_ci
48c72fcc34Sopenharmony_ci/* This is a divide function that returns ceil of the quotient. E.g. ceil_divide(9, 3) returns 3,
49c72fcc34Sopenharmony_ci * ceil_divide(10, 3) returns 4.
50c72fcc34Sopenharmony_ci */
51c72fcc34Sopenharmony_cistatic int ceil_divide(int a, int b)
52c72fcc34Sopenharmony_ci{
53c72fcc34Sopenharmony_ci	int c;
54c72fcc34Sopenharmony_ci
55c72fcc34Sopenharmony_ci	c = a / b;
56c72fcc34Sopenharmony_ci
57c72fcc34Sopenharmony_ci	if (!((a ^ b) & (1U << ((sizeof(int) * 8) - 1))) && c * b != a)
58c72fcc34Sopenharmony_ci		c++;
59c72fcc34Sopenharmony_ci
60c72fcc34Sopenharmony_ci	return c;
61c72fcc34Sopenharmony_ci}
62c72fcc34Sopenharmony_ci
63c72fcc34Sopenharmony_ci/* This function searches from vec[] (of length vec_length) integer values of n. The indices to
64c72fcc34Sopenharmony_ci * equal values is returned in idx[]. The function returns the number of found matches.
65c72fcc34Sopenharmony_ci * The max_results should be set to 0 (or negative) or vec_length to get all matches. The
66c72fcc34Sopenharmony_ci * max_result can be set to 1 to receive only the first match in ascending order. It avoids need for
67c72fcc34Sopenharmony_ci * an array for idx.
68c72fcc34Sopenharmony_ci */
69c72fcc34Sopenharmony_cistatic int find_equal_int16(int16_t idx[], int16_t vec[], int n, int vec_length,
70c72fcc34Sopenharmony_ci			    int max_results)
71c72fcc34Sopenharmony_ci{
72c72fcc34Sopenharmony_ci	int nresults = 0;
73c72fcc34Sopenharmony_ci	int i;
74c72fcc34Sopenharmony_ci
75c72fcc34Sopenharmony_ci	for (i = 0; i < vec_length; i++) {
76c72fcc34Sopenharmony_ci		if (vec[i] == n) {
77c72fcc34Sopenharmony_ci			idx[nresults++] = i;
78c72fcc34Sopenharmony_ci			if (nresults == max_results)
79c72fcc34Sopenharmony_ci				break;
80c72fcc34Sopenharmony_ci		}
81c72fcc34Sopenharmony_ci	}
82c72fcc34Sopenharmony_ci
83c72fcc34Sopenharmony_ci	return nresults;
84c72fcc34Sopenharmony_ci}
85c72fcc34Sopenharmony_ci
86c72fcc34Sopenharmony_ci/* Return the largest absolute value found in the vector. Note that smallest negative value need to
87c72fcc34Sopenharmony_ci * be saturated to preset as int32_t.
88c72fcc34Sopenharmony_ci */
89c72fcc34Sopenharmony_cistatic int32_t find_max_abs_int32(int32_t vec[], int vec_length)
90c72fcc34Sopenharmony_ci{
91c72fcc34Sopenharmony_ci	int i;
92c72fcc34Sopenharmony_ci	int64_t amax = (vec[0] > 0) ? vec[0] : -vec[0];
93c72fcc34Sopenharmony_ci
94c72fcc34Sopenharmony_ci	for (i = 1; i < vec_length; i++) {
95c72fcc34Sopenharmony_ci		amax = (vec[i] > amax) ? vec[i] : amax;
96c72fcc34Sopenharmony_ci		amax = (-vec[i] > amax) ? -vec[i] : amax;
97c72fcc34Sopenharmony_ci	}
98c72fcc34Sopenharmony_ci
99c72fcc34Sopenharmony_ci	return SATP_INT32(amax); /* Amax is always a positive value */
100c72fcc34Sopenharmony_ci}
101c72fcc34Sopenharmony_ci
102c72fcc34Sopenharmony_ci/* Count the left shift amount to normalize a 32 bit signed integer value without causing overflow.
103c72fcc34Sopenharmony_ci * Input value 0 will result to 31.
104c72fcc34Sopenharmony_ci */
105c72fcc34Sopenharmony_cistatic int norm_int32(int32_t val)
106c72fcc34Sopenharmony_ci{
107c72fcc34Sopenharmony_ci	int c = 0;
108c72fcc34Sopenharmony_ci
109c72fcc34Sopenharmony_ci	/* count number of bits c that val can be right-shifted arithmetically
110c72fcc34Sopenharmony_ci	 * until there is -1 (if val is negative) or 0 (if val is positive)
111c72fcc34Sopenharmony_ci	 * norm of val will be 31-c
112c72fcc34Sopenharmony_ci	 */
113c72fcc34Sopenharmony_ci	for (; val != -1 && val != 0; c++)
114c72fcc34Sopenharmony_ci		val >>= 1;
115c72fcc34Sopenharmony_ci
116c72fcc34Sopenharmony_ci	return 31 - c;
117c72fcc34Sopenharmony_ci}
118c72fcc34Sopenharmony_ci
119c72fcc34Sopenharmony_ci/* This function returns a raw list of potential microphone clock and decimation modes for achieving
120c72fcc34Sopenharmony_ci * requested sample rates. The search is constrained by decimation HW capabililies and setup
121c72fcc34Sopenharmony_ci * parameters. The parameters such as microphone clock min/max and duty cycle requirements need be
122c72fcc34Sopenharmony_ci * checked from used microphone component datasheet.
123c72fcc34Sopenharmony_ci */
124c72fcc34Sopenharmony_cistatic void find_modes(struct intel_dmic_params *dmic, struct dmic_calc_decim_modes *modes,
125c72fcc34Sopenharmony_ci		       uint32_t fs)
126c72fcc34Sopenharmony_ci{
127c72fcc34Sopenharmony_ci	int di = dmic->dmic_dai_index;
128c72fcc34Sopenharmony_ci	int clkdiv_min;
129c72fcc34Sopenharmony_ci	int clkdiv_max;
130c72fcc34Sopenharmony_ci	int clkdiv;
131c72fcc34Sopenharmony_ci	int c1;
132c72fcc34Sopenharmony_ci	int du_min;
133c72fcc34Sopenharmony_ci	int du_max;
134c72fcc34Sopenharmony_ci	int pdmclk;
135c72fcc34Sopenharmony_ci	int osr;
136c72fcc34Sopenharmony_ci	int mfir;
137c72fcc34Sopenharmony_ci	int mcic;
138c72fcc34Sopenharmony_ci	unsigned int ioclk_test;
139c72fcc34Sopenharmony_ci	int osr_min = DMIC_MIN_OSR;
140c72fcc34Sopenharmony_ci	int j;
141c72fcc34Sopenharmony_ci	int i = 0;
142c72fcc34Sopenharmony_ci
143c72fcc34Sopenharmony_ci	/* Defaults, empty result */
144c72fcc34Sopenharmony_ci	modes->num_of_modes = 0;
145c72fcc34Sopenharmony_ci
146c72fcc34Sopenharmony_ci	/* The FIFO is not requested if sample rate is set to zero. Just return in such case with
147c72fcc34Sopenharmony_ci	 * num_of_modes as zero.
148c72fcc34Sopenharmony_ci	 */
149c72fcc34Sopenharmony_ci	if (fs == 0) {
150c72fcc34Sopenharmony_ci		return;
151c72fcc34Sopenharmony_ci	}
152c72fcc34Sopenharmony_ci
153c72fcc34Sopenharmony_ci	/* Override DMIC_MIN_OSR for very high sample rates, use as minimum the nominal clock for
154c72fcc34Sopenharmony_ci	 * the high rates.
155c72fcc34Sopenharmony_ci	 */
156c72fcc34Sopenharmony_ci	if (fs >= DMIC_HIGH_RATE_MIN_FS)
157c72fcc34Sopenharmony_ci		osr_min = DMIC_HIGH_RATE_OSR_MIN;
158c72fcc34Sopenharmony_ci
159c72fcc34Sopenharmony_ci	/* Check for sane pdm clock, min 100 kHz, max ioclk/2 */
160c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[di].pdmclk_max < DMIC_HW_PDM_CLK_MIN ||
161c72fcc34Sopenharmony_ci	    dmic->dmic_prm[di].pdmclk_max > dmic->dmic_prm[di].io_clk / 2) {
162c72fcc34Sopenharmony_ci		fprintf(stderr, "find_modes():  pdm clock max not in range\n");
163c72fcc34Sopenharmony_ci		return;
164c72fcc34Sopenharmony_ci	}
165c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[di].pdmclk_min < DMIC_HW_PDM_CLK_MIN ||
166c72fcc34Sopenharmony_ci	    dmic->dmic_prm[di].pdmclk_min > dmic->dmic_prm[di].pdmclk_max) {
167c72fcc34Sopenharmony_ci		fprintf(stderr, "find_modes():  pdm clock min not in range\n");
168c72fcc34Sopenharmony_ci		return;
169c72fcc34Sopenharmony_ci	}
170c72fcc34Sopenharmony_ci
171c72fcc34Sopenharmony_ci	/* Check for sane duty cycle */
172c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[di].duty_min > dmic->dmic_prm[di].duty_max) {
173c72fcc34Sopenharmony_ci		fprintf(stderr, "find_modes(): duty cycle min > max\n");
174c72fcc34Sopenharmony_ci		return;
175c72fcc34Sopenharmony_ci	}
176c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[di].duty_min < DMIC_HW_DUTY_MIN ||
177c72fcc34Sopenharmony_ci	    dmic->dmic_prm[di].duty_min > DMIC_HW_DUTY_MAX) {
178c72fcc34Sopenharmony_ci		fprintf(stderr, "find_modes():  pdm clock min not in range\n");
179c72fcc34Sopenharmony_ci		return;
180c72fcc34Sopenharmony_ci	}
181c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[di].duty_max < DMIC_HW_DUTY_MIN ||
182c72fcc34Sopenharmony_ci	    dmic->dmic_prm[di].duty_max > DMIC_HW_DUTY_MAX) {
183c72fcc34Sopenharmony_ci		fprintf(stderr, "find_modes(): pdm clock max not in range\n");
184c72fcc34Sopenharmony_ci		return;
185c72fcc34Sopenharmony_ci	}
186c72fcc34Sopenharmony_ci
187c72fcc34Sopenharmony_ci	/* Min and max clock dividers */
188c72fcc34Sopenharmony_ci	clkdiv_min = ceil_divide(dmic->dmic_prm[di].io_clk, dmic->dmic_prm[di].pdmclk_max);
189c72fcc34Sopenharmony_ci	clkdiv_min = MAX(clkdiv_min, DMIC_HW_CIC_DECIM_MIN);
190c72fcc34Sopenharmony_ci	clkdiv_max = dmic->dmic_prm[di].io_clk / dmic->dmic_prm[di].pdmclk_min;
191c72fcc34Sopenharmony_ci
192c72fcc34Sopenharmony_ci	/* Loop possible clock dividers and check based on resulting oversampling ratio that CIC and
193c72fcc34Sopenharmony_ci	 * FIR decimation ratios are feasible. The ratios need to be integers. Also the mic clock
194c72fcc34Sopenharmony_ci	 * duty cycle need to be within limits.
195c72fcc34Sopenharmony_ci	 */
196c72fcc34Sopenharmony_ci	for (clkdiv = clkdiv_min; clkdiv <= clkdiv_max; clkdiv++) {
197c72fcc34Sopenharmony_ci		/* Calculate duty cycle for this clock divider. Note that odd dividers cause non-50%
198c72fcc34Sopenharmony_ci		 * duty cycle.
199c72fcc34Sopenharmony_ci		 */
200c72fcc34Sopenharmony_ci		c1 = clkdiv >> 1;
201c72fcc34Sopenharmony_ci		du_min = 100 * c1 / clkdiv;
202c72fcc34Sopenharmony_ci		du_max = 100 - du_min;
203c72fcc34Sopenharmony_ci
204c72fcc34Sopenharmony_ci		/* Calculate PDM clock rate and oversampling ratio. */
205c72fcc34Sopenharmony_ci		pdmclk = dmic->dmic_prm[di].io_clk / clkdiv;
206c72fcc34Sopenharmony_ci		osr = pdmclk / fs;
207c72fcc34Sopenharmony_ci
208c72fcc34Sopenharmony_ci		/* Check that OSR constraints is met and clock duty cycle does not exceed microphone
209c72fcc34Sopenharmony_ci		 * specification. If exceed proceed to next clkdiv.
210c72fcc34Sopenharmony_ci		 */
211c72fcc34Sopenharmony_ci		if (osr < osr_min || du_min < dmic->dmic_prm[di].duty_min ||
212c72fcc34Sopenharmony_ci		    du_max > dmic->dmic_prm[di].duty_max)
213c72fcc34Sopenharmony_ci			continue;
214c72fcc34Sopenharmony_ci
215c72fcc34Sopenharmony_ci		/* Loop FIR decimation factors candidates. If the integer divided decimation factors
216c72fcc34Sopenharmony_ci		 * and clock dividers as multiplied with sample rate match the IO clock rate the
217c72fcc34Sopenharmony_ci		 * division was exact and such decimation mode is possible. Then check that CIC
218c72fcc34Sopenharmony_ci		 * decimation constraints are met. The passed decimation modes are added to array.
219c72fcc34Sopenharmony_ci		 */
220c72fcc34Sopenharmony_ci		for (j = 0; fir_list[j]; j++) {
221c72fcc34Sopenharmony_ci			mfir = fir_list[j]->decim_factor;
222c72fcc34Sopenharmony_ci
223c72fcc34Sopenharmony_ci			/* Skip if previous decimation factor was the same */
224c72fcc34Sopenharmony_ci			if (j > 1 && fir_list[j - 1]->decim_factor == mfir)
225c72fcc34Sopenharmony_ci				continue;
226c72fcc34Sopenharmony_ci
227c72fcc34Sopenharmony_ci			mcic = osr / mfir;
228c72fcc34Sopenharmony_ci			ioclk_test = fs * mfir * mcic * clkdiv;
229c72fcc34Sopenharmony_ci
230c72fcc34Sopenharmony_ci			if (ioclk_test == dmic->dmic_prm[di].io_clk &&
231c72fcc34Sopenharmony_ci			    mcic >= DMIC_HW_CIC_DECIM_MIN &&
232c72fcc34Sopenharmony_ci			    mcic <= DMIC_HW_CIC_DECIM_MAX &&
233c72fcc34Sopenharmony_ci			    i < DMIC_MAX_MODES) {
234c72fcc34Sopenharmony_ci				modes->clkdiv[i] = clkdiv;
235c72fcc34Sopenharmony_ci				modes->mcic[i] = mcic;
236c72fcc34Sopenharmony_ci				modes->mfir[i] = mfir;
237c72fcc34Sopenharmony_ci				i++;
238c72fcc34Sopenharmony_ci			}
239c72fcc34Sopenharmony_ci		}
240c72fcc34Sopenharmony_ci	}
241c72fcc34Sopenharmony_ci
242c72fcc34Sopenharmony_ci	modes->num_of_modes = i;
243c72fcc34Sopenharmony_ci}
244c72fcc34Sopenharmony_ci
245c72fcc34Sopenharmony_ci/* The previous raw modes list contains sane configuration possibilities. When there is request for
246c72fcc34Sopenharmony_ci * both FIFOs A and B operation this function returns list of compatible settings.
247c72fcc34Sopenharmony_ci */
248c72fcc34Sopenharmony_cistatic void match_modes(struct dmic_calc_matched_modes *c, struct dmic_calc_decim_modes *a,
249c72fcc34Sopenharmony_ci			struct dmic_calc_decim_modes *b)
250c72fcc34Sopenharmony_ci{
251c72fcc34Sopenharmony_ci	int16_t idx[DMIC_MAX_MODES];
252c72fcc34Sopenharmony_ci	int idx_length;
253c72fcc34Sopenharmony_ci	int i;
254c72fcc34Sopenharmony_ci	int n;
255c72fcc34Sopenharmony_ci	int m;
256c72fcc34Sopenharmony_ci
257c72fcc34Sopenharmony_ci	/* Check if previous search got results. */
258c72fcc34Sopenharmony_ci	c->num_of_modes = 0;
259c72fcc34Sopenharmony_ci	if (a->num_of_modes == 0 && b->num_of_modes == 0) {
260c72fcc34Sopenharmony_ci		/* Nothing to do */
261c72fcc34Sopenharmony_ci		return;
262c72fcc34Sopenharmony_ci	}
263c72fcc34Sopenharmony_ci
264c72fcc34Sopenharmony_ci	/* Ensure that num_of_modes is sane. */
265c72fcc34Sopenharmony_ci	if (a->num_of_modes > DMIC_MAX_MODES ||
266c72fcc34Sopenharmony_ci	    b->num_of_modes > DMIC_MAX_MODES)
267c72fcc34Sopenharmony_ci		return;
268c72fcc34Sopenharmony_ci
269c72fcc34Sopenharmony_ci	/* Check for request only for FIFO A or B. In such case pass list for A or B as such. */
270c72fcc34Sopenharmony_ci	if (b->num_of_modes == 0) {
271c72fcc34Sopenharmony_ci		c->num_of_modes = a->num_of_modes;
272c72fcc34Sopenharmony_ci		for (i = 0; i < a->num_of_modes; i++) {
273c72fcc34Sopenharmony_ci			c->clkdiv[i] = a->clkdiv[i];
274c72fcc34Sopenharmony_ci			c->mcic[i] = a->mcic[i];
275c72fcc34Sopenharmony_ci			c->mfir_a[i] = a->mfir[i];
276c72fcc34Sopenharmony_ci			c->mfir_b[i] = 0; /* Mark FIR B as non-used */
277c72fcc34Sopenharmony_ci		}
278c72fcc34Sopenharmony_ci		return;
279c72fcc34Sopenharmony_ci	}
280c72fcc34Sopenharmony_ci
281c72fcc34Sopenharmony_ci	if (a->num_of_modes == 0) {
282c72fcc34Sopenharmony_ci		c->num_of_modes = b->num_of_modes;
283c72fcc34Sopenharmony_ci		for (i = 0; i < b->num_of_modes; i++) {
284c72fcc34Sopenharmony_ci			c->clkdiv[i] = b->clkdiv[i];
285c72fcc34Sopenharmony_ci			c->mcic[i] = b->mcic[i];
286c72fcc34Sopenharmony_ci			c->mfir_b[i] = b->mfir[i];
287c72fcc34Sopenharmony_ci			c->mfir_a[i] = 0; /* Mark FIR A as non-used */
288c72fcc34Sopenharmony_ci		}
289c72fcc34Sopenharmony_ci		return;
290c72fcc34Sopenharmony_ci	}
291c72fcc34Sopenharmony_ci
292c72fcc34Sopenharmony_ci	/* Merge a list of compatible modes */
293c72fcc34Sopenharmony_ci	i = 0;
294c72fcc34Sopenharmony_ci	for (n = 0; n < a->num_of_modes; n++) {
295c72fcc34Sopenharmony_ci		/* Find all indices of values a->clkdiv[n] in b->clkdiv[] */
296c72fcc34Sopenharmony_ci		idx_length = find_equal_int16(idx, b->clkdiv, a->clkdiv[n],
297c72fcc34Sopenharmony_ci					      b->num_of_modes, 0);
298c72fcc34Sopenharmony_ci		for (m = 0; m < idx_length; m++) {
299c72fcc34Sopenharmony_ci			if (b->mcic[idx[m]] == a->mcic[n]) {
300c72fcc34Sopenharmony_ci				c->clkdiv[i] = a->clkdiv[n];
301c72fcc34Sopenharmony_ci				c->mcic[i] = a->mcic[n];
302c72fcc34Sopenharmony_ci				c->mfir_a[i] = a->mfir[n];
303c72fcc34Sopenharmony_ci				c->mfir_b[i] = b->mfir[idx[m]];
304c72fcc34Sopenharmony_ci				i++;
305c72fcc34Sopenharmony_ci			}
306c72fcc34Sopenharmony_ci		}
307c72fcc34Sopenharmony_ci		c->num_of_modes = i;
308c72fcc34Sopenharmony_ci	}
309c72fcc34Sopenharmony_ci}
310c72fcc34Sopenharmony_ci
311c72fcc34Sopenharmony_ci/* Finds a suitable FIR decimation filter from the included set */
312c72fcc34Sopenharmony_cistatic struct pdm_decim *get_fir(struct intel_dmic_params *dmic,
313c72fcc34Sopenharmony_ci				 struct dmic_calc_configuration *cfg, int mfir)
314c72fcc34Sopenharmony_ci{
315c72fcc34Sopenharmony_ci	int i = 0;
316c72fcc34Sopenharmony_ci	int fs;
317c72fcc34Sopenharmony_ci	int cic_fs;
318c72fcc34Sopenharmony_ci	int fir_max_length;
319c72fcc34Sopenharmony_ci	struct pdm_decim *fir = NULL;
320c72fcc34Sopenharmony_ci	int di = dmic->dmic_dai_index;
321c72fcc34Sopenharmony_ci
322c72fcc34Sopenharmony_ci	if (mfir <= 0)
323c72fcc34Sopenharmony_ci		return fir;
324c72fcc34Sopenharmony_ci
325c72fcc34Sopenharmony_ci	cic_fs = dmic->dmic_prm[di].io_clk / cfg->clkdiv / cfg->mcic;
326c72fcc34Sopenharmony_ci	fs = cic_fs / mfir;
327c72fcc34Sopenharmony_ci	/* FIR max. length depends on available cycles and coef RAM length. Exceeding this length
328c72fcc34Sopenharmony_ci	 * sets HW overrun status and overwrite of other register.
329c72fcc34Sopenharmony_ci	 */
330c72fcc34Sopenharmony_ci	fir_max_length = MIN(DMIC_HW_FIR_LENGTH_MAX,
331c72fcc34Sopenharmony_ci			     (int)dmic->dmic_prm[di].io_clk / fs / 2 -
332c72fcc34Sopenharmony_ci			     DMIC_FIR_PIPELINE_OVERHEAD);
333c72fcc34Sopenharmony_ci
334c72fcc34Sopenharmony_ci	/* Loop until NULL */
335c72fcc34Sopenharmony_ci	while (fir_list[i]) {
336c72fcc34Sopenharmony_ci		if (fir_list[i]->decim_factor == mfir) {
337c72fcc34Sopenharmony_ci			if (fir_list[i]->length <= fir_max_length) {
338c72fcc34Sopenharmony_ci				/* Store pointer, break from loop to avoid a possible other mode
339c72fcc34Sopenharmony_ci				 * with lower FIR length.
340c72fcc34Sopenharmony_ci				 */
341c72fcc34Sopenharmony_ci				fir = fir_list[i];
342c72fcc34Sopenharmony_ci				break;
343c72fcc34Sopenharmony_ci			}
344c72fcc34Sopenharmony_ci		}
345c72fcc34Sopenharmony_ci		i++;
346c72fcc34Sopenharmony_ci	}
347c72fcc34Sopenharmony_ci
348c72fcc34Sopenharmony_ci	return fir;
349c72fcc34Sopenharmony_ci}
350c72fcc34Sopenharmony_ci
351c72fcc34Sopenharmony_ci/* Calculate scale and shift to use for FIR coefficients. Scale is applied before write to HW coef
352c72fcc34Sopenharmony_ci * RAM. Shift will be programmed to HW register.
353c72fcc34Sopenharmony_ci */
354c72fcc34Sopenharmony_cistatic int fir_coef_scale(int32_t *fir_scale, int *fir_shift, int add_shift,
355c72fcc34Sopenharmony_ci			  const int32_t coef[], int coef_length, int32_t gain)
356c72fcc34Sopenharmony_ci{
357c72fcc34Sopenharmony_ci	int32_t amax;
358c72fcc34Sopenharmony_ci	int32_t new_amax;
359c72fcc34Sopenharmony_ci	int32_t fir_gain;
360c72fcc34Sopenharmony_ci	int shift;
361c72fcc34Sopenharmony_ci
362c72fcc34Sopenharmony_ci	/* Multiply gain passed from CIC with output full scale. */
363c72fcc34Sopenharmony_ci	fir_gain = Q_MULTSR_32X32((int64_t)gain, DMIC_HW_SENS_Q28,
364c72fcc34Sopenharmony_ci				  DMIC_FIR_SCALE_Q, 28, DMIC_FIR_SCALE_Q);
365c72fcc34Sopenharmony_ci
366c72fcc34Sopenharmony_ci	/* Find the largest FIR coefficient value. */
367c72fcc34Sopenharmony_ci	amax = find_max_abs_int32((int32_t *)coef, coef_length);
368c72fcc34Sopenharmony_ci
369c72fcc34Sopenharmony_ci	/* Scale max. tap value with FIR gain. */
370c72fcc34Sopenharmony_ci	new_amax = Q_MULTSR_32X32((int64_t)amax, fir_gain, 31,
371c72fcc34Sopenharmony_ci				  DMIC_FIR_SCALE_Q, DMIC_FIR_SCALE_Q);
372c72fcc34Sopenharmony_ci	if (new_amax <= 0)
373c72fcc34Sopenharmony_ci		return -EINVAL;
374c72fcc34Sopenharmony_ci
375c72fcc34Sopenharmony_ci	/* Get left shifts count to normalize the fractional value as 32 bit. We need right shifts
376c72fcc34Sopenharmony_ci	 * count for scaling so need to invert. The difference of Q31 vs. used Q format is added to
377c72fcc34Sopenharmony_ci	 * get the correct normalization right shift value.
378c72fcc34Sopenharmony_ci	 */
379c72fcc34Sopenharmony_ci	shift = 31 - DMIC_FIR_SCALE_Q - norm_int32(new_amax);
380c72fcc34Sopenharmony_ci
381c72fcc34Sopenharmony_ci	/* Add to shift for coef raw Q31 format shift and store to configuration. Ensure range (fail
382c72fcc34Sopenharmony_ci	 * should not happen with OK coefficient set).
383c72fcc34Sopenharmony_ci	 */
384c72fcc34Sopenharmony_ci	*fir_shift = -shift + add_shift;
385c72fcc34Sopenharmony_ci	if (*fir_shift < DMIC_HW_FIR_SHIFT_MIN ||
386c72fcc34Sopenharmony_ci	    *fir_shift > DMIC_HW_FIR_SHIFT_MAX)
387c72fcc34Sopenharmony_ci		return -EINVAL;
388c72fcc34Sopenharmony_ci
389c72fcc34Sopenharmony_ci	/* Compensate shift into FIR coef scaler and store as Q4.20. */
390c72fcc34Sopenharmony_ci	if (shift < 0)
391c72fcc34Sopenharmony_ci		*fir_scale = fir_gain << -shift;
392c72fcc34Sopenharmony_ci	else
393c72fcc34Sopenharmony_ci		*fir_scale = fir_gain >> shift;
394c72fcc34Sopenharmony_ci
395c72fcc34Sopenharmony_ci	return 0;
396c72fcc34Sopenharmony_ci}
397c72fcc34Sopenharmony_ci
398c72fcc34Sopenharmony_ci/* This function selects with a simple criteria one mode to set up the decimator. For the settings
399c72fcc34Sopenharmony_ci * chosen for FIFOs A and B output a lookup is done for FIR coefficients from the included
400c72fcc34Sopenharmony_ci * coefficients tables. For some decimation factors there may be several length coefficient sets. It
401c72fcc34Sopenharmony_ci * is due to possible restruction of decimation engine cycles per given sample rate. If the
402c72fcc34Sopenharmony_ci * coefficients length is exceeded the lookup continues. Therefore the list of coefficient set must
403c72fcc34Sopenharmony_ci * present the filters for a decimation factor in decreasing length order.
404c72fcc34Sopenharmony_ci *
405c72fcc34Sopenharmony_ci * Note: If there is no filter available an error is returned. The parameters should be reviewed for
406c72fcc34Sopenharmony_ci * such case. If still a filter is missing it should be added into the included set. FIR decimation
407c72fcc34Sopenharmony_ci * with a high factor usually needs compromizes into specifications and is not desirable.
408c72fcc34Sopenharmony_ci */
409c72fcc34Sopenharmony_cistatic int select_mode(struct intel_dmic_params *dmic, struct dmic_calc_configuration *cfg,
410c72fcc34Sopenharmony_ci		       struct dmic_calc_matched_modes *modes)
411c72fcc34Sopenharmony_ci{
412c72fcc34Sopenharmony_ci	int32_t g_cic;
413c72fcc34Sopenharmony_ci	int32_t fir_in_max;
414c72fcc34Sopenharmony_ci	int32_t cic_out_max;
415c72fcc34Sopenharmony_ci	int32_t gain_to_fir;
416c72fcc34Sopenharmony_ci	int16_t idx[DMIC_MAX_MODES];
417c72fcc34Sopenharmony_ci	int16_t *mfir;
418c72fcc34Sopenharmony_ci	int mcic;
419c72fcc34Sopenharmony_ci	int bits_cic;
420c72fcc34Sopenharmony_ci	int ret;
421c72fcc34Sopenharmony_ci	int n;
422c72fcc34Sopenharmony_ci	int found = 0;
423c72fcc34Sopenharmony_ci
424c72fcc34Sopenharmony_ci	/* If there are more than one possibilities select a mode with a preferred FIR decimation
425c72fcc34Sopenharmony_ci	 * factor. If there are several select mode with highest ioclk divider to minimize
426c72fcc34Sopenharmony_ci	 * microphone power consumption. The highest clock divisors are in the end of list so select
427c72fcc34Sopenharmony_ci	 * the last of list. The minimum OSR criteria used in previous ensures that quality in the
428c72fcc34Sopenharmony_ci	 * candidates should be sufficient.
429c72fcc34Sopenharmony_ci	 */
430c72fcc34Sopenharmony_ci	if (modes->num_of_modes == 0) {
431c72fcc34Sopenharmony_ci		fprintf(stderr, "select_mode(): no modes available\n");
432c72fcc34Sopenharmony_ci		return -EINVAL;
433c72fcc34Sopenharmony_ci	}
434c72fcc34Sopenharmony_ci
435c72fcc34Sopenharmony_ci	/* Valid modes presence is indicated with non-zero decimation factor in 1st element. If FIR
436c72fcc34Sopenharmony_ci	 * A is not used get decimation factors from FIR B instead.
437c72fcc34Sopenharmony_ci	 */
438c72fcc34Sopenharmony_ci	if (modes->mfir_a[0] > 0)
439c72fcc34Sopenharmony_ci		mfir = modes->mfir_a;
440c72fcc34Sopenharmony_ci	else
441c72fcc34Sopenharmony_ci		mfir = modes->mfir_b;
442c72fcc34Sopenharmony_ci
443c72fcc34Sopenharmony_ci	/* Search fir_list[] decimation factors from start towards end. The found last configuration
444c72fcc34Sopenharmony_ci	 * entry with searched decimation factor will be used.
445c72fcc34Sopenharmony_ci	 */
446c72fcc34Sopenharmony_ci	for (n = 0; fir_list[n]; n++) {
447c72fcc34Sopenharmony_ci		found = find_equal_int16(idx, mfir, fir_list[n]->decim_factor,
448c72fcc34Sopenharmony_ci					 modes->num_of_modes, 0);
449c72fcc34Sopenharmony_ci		if (found)
450c72fcc34Sopenharmony_ci			break;
451c72fcc34Sopenharmony_ci	}
452c72fcc34Sopenharmony_ci
453c72fcc34Sopenharmony_ci	if (!found) {
454c72fcc34Sopenharmony_ci		fprintf(stderr, "select_mode(): No filter for decimation found\n");
455c72fcc34Sopenharmony_ci		return -EINVAL;
456c72fcc34Sopenharmony_ci	}
457c72fcc34Sopenharmony_ci	n = idx[found - 1]; /* Option with highest clock divisor and lowest mic clock rate */
458c72fcc34Sopenharmony_ci
459c72fcc34Sopenharmony_ci	/* Get microphone clock and decimation parameters for used mode from the list. */
460c72fcc34Sopenharmony_ci	cfg->clkdiv = modes->clkdiv[n];
461c72fcc34Sopenharmony_ci	cfg->mfir_a = modes->mfir_a[n];
462c72fcc34Sopenharmony_ci	cfg->mfir_b = modes->mfir_b[n];
463c72fcc34Sopenharmony_ci	cfg->mcic = modes->mcic[n];
464c72fcc34Sopenharmony_ci	cfg->fir_a = NULL;
465c72fcc34Sopenharmony_ci	cfg->fir_b = NULL;
466c72fcc34Sopenharmony_ci
467c72fcc34Sopenharmony_ci	/* Find raw FIR coefficients to match the decimation factors of FIR A and B. */
468c72fcc34Sopenharmony_ci	if (cfg->mfir_a > 0) {
469c72fcc34Sopenharmony_ci		cfg->fir_a = get_fir(dmic, cfg, cfg->mfir_a);
470c72fcc34Sopenharmony_ci		if (!cfg->fir_a) {
471c72fcc34Sopenharmony_ci			fprintf(stderr, "select_mode(): can't find FIR coefficients, mfir_a = %d\n",
472c72fcc34Sopenharmony_ci				cfg->mfir_a);
473c72fcc34Sopenharmony_ci			return -EINVAL;
474c72fcc34Sopenharmony_ci		}
475c72fcc34Sopenharmony_ci	}
476c72fcc34Sopenharmony_ci
477c72fcc34Sopenharmony_ci	if (cfg->mfir_b > 0) {
478c72fcc34Sopenharmony_ci		cfg->fir_b = get_fir(dmic, cfg, cfg->mfir_b);
479c72fcc34Sopenharmony_ci		if (!cfg->fir_b) {
480c72fcc34Sopenharmony_ci			fprintf(stderr, "select_mode(): can't find FIR coefficients, mfir_b = %d\n",
481c72fcc34Sopenharmony_ci				cfg->mfir_b);
482c72fcc34Sopenharmony_ci			return -EINVAL;
483c72fcc34Sopenharmony_ci		}
484c72fcc34Sopenharmony_ci	}
485c72fcc34Sopenharmony_ci
486c72fcc34Sopenharmony_ci	/* Calculate CIC shift from the decimation factor specific gain. The gain of HW decimator
487c72fcc34Sopenharmony_ci	 * equals decimation factor to power of 5.
488c72fcc34Sopenharmony_ci	 */
489c72fcc34Sopenharmony_ci	mcic = cfg->mcic;
490c72fcc34Sopenharmony_ci	g_cic = mcic * mcic * mcic * mcic * mcic;
491c72fcc34Sopenharmony_ci	if (g_cic < 0) {
492c72fcc34Sopenharmony_ci		/* Erroneous decimation factor and CIC gain */
493c72fcc34Sopenharmony_ci		fprintf(stderr, "select_mode(): erroneous decimation factor and CIC gain\n");
494c72fcc34Sopenharmony_ci		return -EINVAL;
495c72fcc34Sopenharmony_ci	}
496c72fcc34Sopenharmony_ci
497c72fcc34Sopenharmony_ci	bits_cic = 32 - norm_int32(g_cic);
498c72fcc34Sopenharmony_ci	cfg->cic_shift = bits_cic - DMIC_HW_BITS_FIR_INPUT;
499c72fcc34Sopenharmony_ci
500c72fcc34Sopenharmony_ci	/* Calculate remaining gain to FIR in Q format used for gain values. */
501c72fcc34Sopenharmony_ci	fir_in_max = INT_MAX(DMIC_HW_BITS_FIR_INPUT);
502c72fcc34Sopenharmony_ci	if (cfg->cic_shift >= 0)
503c72fcc34Sopenharmony_ci		cic_out_max = g_cic >> cfg->cic_shift;
504c72fcc34Sopenharmony_ci	else
505c72fcc34Sopenharmony_ci		cic_out_max = g_cic << -cfg->cic_shift;
506c72fcc34Sopenharmony_ci
507c72fcc34Sopenharmony_ci	gain_to_fir = (int32_t)((((int64_t)fir_in_max) << DMIC_FIR_SCALE_Q) /
508c72fcc34Sopenharmony_ci		cic_out_max);
509c72fcc34Sopenharmony_ci
510c72fcc34Sopenharmony_ci	/* Calculate FIR scale and shift */
511c72fcc34Sopenharmony_ci	if (cfg->mfir_a > 0) {
512c72fcc34Sopenharmony_ci		cfg->fir_a_length = cfg->fir_a->length;
513c72fcc34Sopenharmony_ci		ret = fir_coef_scale(&cfg->fir_a_scale, &cfg->fir_a_shift,
514c72fcc34Sopenharmony_ci				     cfg->fir_a->shift, cfg->fir_a->coef,
515c72fcc34Sopenharmony_ci				     cfg->fir_a->length, gain_to_fir);
516c72fcc34Sopenharmony_ci		if (ret < 0) {
517c72fcc34Sopenharmony_ci			/* Invalid coefficient set found, should not happen. */
518c72fcc34Sopenharmony_ci			fprintf(stderr, "select_mode(): invalid coefficient set found\n");
519c72fcc34Sopenharmony_ci			return -EINVAL;
520c72fcc34Sopenharmony_ci		}
521c72fcc34Sopenharmony_ci	} else {
522c72fcc34Sopenharmony_ci		cfg->fir_a_scale = 0;
523c72fcc34Sopenharmony_ci		cfg->fir_a_shift = 0;
524c72fcc34Sopenharmony_ci		cfg->fir_a_length = 0;
525c72fcc34Sopenharmony_ci	}
526c72fcc34Sopenharmony_ci
527c72fcc34Sopenharmony_ci	if (cfg->mfir_b > 0) {
528c72fcc34Sopenharmony_ci		cfg->fir_b_length = cfg->fir_b->length;
529c72fcc34Sopenharmony_ci		ret = fir_coef_scale(&cfg->fir_b_scale, &cfg->fir_b_shift,
530c72fcc34Sopenharmony_ci				     cfg->fir_b->shift, cfg->fir_b->coef,
531c72fcc34Sopenharmony_ci				     cfg->fir_b->length, gain_to_fir);
532c72fcc34Sopenharmony_ci		if (ret < 0) {
533c72fcc34Sopenharmony_ci			/* Invalid coefficient set found, should not happen. */
534c72fcc34Sopenharmony_ci			fprintf(stderr, "select_mode(): invalid coefficient set found\n");
535c72fcc34Sopenharmony_ci			return -EINVAL;
536c72fcc34Sopenharmony_ci		}
537c72fcc34Sopenharmony_ci	} else {
538c72fcc34Sopenharmony_ci		cfg->fir_b_scale = 0;
539c72fcc34Sopenharmony_ci		cfg->fir_b_shift = 0;
540c72fcc34Sopenharmony_ci		cfg->fir_b_length = 0;
541c72fcc34Sopenharmony_ci	}
542c72fcc34Sopenharmony_ci
543c72fcc34Sopenharmony_ci	return 0;
544c72fcc34Sopenharmony_ci}
545c72fcc34Sopenharmony_ci
546c72fcc34Sopenharmony_ci/* The FIFO input packer mode (IPM) settings are somewhat different in HW versions. This helper
547c72fcc34Sopenharmony_ci * function returns a suitable IPM bit field value to use.
548c72fcc34Sopenharmony_ci */
549c72fcc34Sopenharmony_cistatic void ipm_helper1(struct intel_dmic_params *dmic, int *ipm)
550c72fcc34Sopenharmony_ci{
551c72fcc34Sopenharmony_ci	int di = dmic->dmic_dai_index;
552c72fcc34Sopenharmony_ci	int pdm[DMIC_HW_CONTROLLERS];
553c72fcc34Sopenharmony_ci	int i;
554c72fcc34Sopenharmony_ci
555c72fcc34Sopenharmony_ci	/* Loop number of PDM controllers in the configuration. If mic A or B is enabled then a pdm
556c72fcc34Sopenharmony_ci	 * controller is marked as active for this DAI.
557c72fcc34Sopenharmony_ci	 */
558c72fcc34Sopenharmony_ci	for (i = 0; i < DMIC_HW_CONTROLLERS; i++) {
559c72fcc34Sopenharmony_ci		if (dmic->dmic_prm[di].pdm[i].enable_mic_a ||
560c72fcc34Sopenharmony_ci		    dmic->dmic_prm[di].pdm[i].enable_mic_b)
561c72fcc34Sopenharmony_ci			pdm[i] = 1;
562c72fcc34Sopenharmony_ci		else
563c72fcc34Sopenharmony_ci			pdm[i] = 0;
564c72fcc34Sopenharmony_ci	}
565c72fcc34Sopenharmony_ci
566c72fcc34Sopenharmony_ci	/* Set IPM to match active pdm controllers. */
567c72fcc34Sopenharmony_ci	*ipm = 0;
568c72fcc34Sopenharmony_ci
569c72fcc34Sopenharmony_ci	if (pdm[0] == 0 && pdm[1] > 0)
570c72fcc34Sopenharmony_ci		*ipm = 1;
571c72fcc34Sopenharmony_ci
572c72fcc34Sopenharmony_ci	if (pdm[0] > 0 && pdm[1] > 0)
573c72fcc34Sopenharmony_ci		*ipm = 2;
574c72fcc34Sopenharmony_ci}
575c72fcc34Sopenharmony_ci
576c72fcc34Sopenharmony_cistatic void ipm_helper2(struct intel_dmic_params *dmic, int source[], int *ipm)
577c72fcc34Sopenharmony_ci{
578c72fcc34Sopenharmony_ci	int di = dmic->dmic_dai_index;
579c72fcc34Sopenharmony_ci	int pdm[DMIC_HW_CONTROLLERS];
580c72fcc34Sopenharmony_ci	int i;
581c72fcc34Sopenharmony_ci	int n = 0;
582c72fcc34Sopenharmony_ci
583c72fcc34Sopenharmony_ci	for (i = 0; i < OUTCONTROLX_IPM_NUMSOURCES; i++)
584c72fcc34Sopenharmony_ci		source[i] = 0;
585c72fcc34Sopenharmony_ci
586c72fcc34Sopenharmony_ci	/* Loop number of PDM controllers in the configuration. If mic A or B is enabled then a pdm
587c72fcc34Sopenharmony_ci	 * controller is marked as active. The function returns in array source[] the indice of
588c72fcc34Sopenharmony_ci	 * enabled pdm controllers to be used for IPM configuration.
589c72fcc34Sopenharmony_ci	 */
590c72fcc34Sopenharmony_ci	for (i = 0; i < DMIC_HW_CONTROLLERS; i++) {
591c72fcc34Sopenharmony_ci		if (dmic->dmic_prm[di].pdm[i].enable_mic_a ||
592c72fcc34Sopenharmony_ci		    dmic->dmic_prm[di].pdm[i].enable_mic_b) {
593c72fcc34Sopenharmony_ci			pdm[i] = 1;
594c72fcc34Sopenharmony_ci			source[n] = i;
595c72fcc34Sopenharmony_ci			n++;
596c72fcc34Sopenharmony_ci		} else {
597c72fcc34Sopenharmony_ci			pdm[i] = 0;
598c72fcc34Sopenharmony_ci		}
599c72fcc34Sopenharmony_ci	}
600c72fcc34Sopenharmony_ci
601c72fcc34Sopenharmony_ci	/* IPM bit field is set to count of active pdm controllers. */
602c72fcc34Sopenharmony_ci	*ipm = pdm[0];
603c72fcc34Sopenharmony_ci	for (i = 1; i < DMIC_HW_CONTROLLERS; i++)
604c72fcc34Sopenharmony_ci		*ipm += pdm[i];
605c72fcc34Sopenharmony_ci}
606c72fcc34Sopenharmony_ci
607c72fcc34Sopenharmony_ci/* Loop number of PDM controllers in the configuration. The function checks if the controller should
608c72fcc34Sopenharmony_ci * operate as stereo or mono left (A) or mono right (B) mode. Mono right mode is setup as channel
609c72fcc34Sopenharmony_ci * swapped mono left.
610c72fcc34Sopenharmony_ci */
611c72fcc34Sopenharmony_cistatic int stereo_helper(struct intel_dmic_params *dmic, int stereo[], int swap[])
612c72fcc34Sopenharmony_ci{
613c72fcc34Sopenharmony_ci	int cnt;
614c72fcc34Sopenharmony_ci	int i;
615c72fcc34Sopenharmony_ci	int swap_check;
616c72fcc34Sopenharmony_ci	int ret = 0;
617c72fcc34Sopenharmony_ci
618c72fcc34Sopenharmony_ci	for (i = 0; i < DMIC_HW_CONTROLLERS; i++) {
619c72fcc34Sopenharmony_ci		cnt = 0;
620c72fcc34Sopenharmony_ci		if (dmic->dmic_prm[0].pdm[i].enable_mic_a ||
621c72fcc34Sopenharmony_ci		    dmic->dmic_prm[1].pdm[i].enable_mic_a)
622c72fcc34Sopenharmony_ci			cnt++;
623c72fcc34Sopenharmony_ci
624c72fcc34Sopenharmony_ci		if (dmic->dmic_prm[0].pdm[i].enable_mic_b ||
625c72fcc34Sopenharmony_ci		    dmic->dmic_prm[1].pdm[i].enable_mic_b)
626c72fcc34Sopenharmony_ci			cnt++;
627c72fcc34Sopenharmony_ci
628c72fcc34Sopenharmony_ci		/* Set stereo mode if both mic A anc B are enabled. */
629c72fcc34Sopenharmony_ci		cnt >>= 1;
630c72fcc34Sopenharmony_ci		stereo[i] = cnt;
631c72fcc34Sopenharmony_ci
632c72fcc34Sopenharmony_ci		/* Swap channels if only mic B is used for mono processing. */
633c72fcc34Sopenharmony_ci		swap[i] = (dmic->dmic_prm[0].pdm[i].enable_mic_b ||
634c72fcc34Sopenharmony_ci			   dmic->dmic_prm[1].pdm[i].enable_mic_b) && !cnt;
635c72fcc34Sopenharmony_ci
636c72fcc34Sopenharmony_ci		/* Check that swap does not conflict with other DAI request */
637c72fcc34Sopenharmony_ci		swap_check = (dmic->dmic_prm[1].pdm[i].enable_mic_a ||
638c72fcc34Sopenharmony_ci			      dmic->dmic_prm[0].pdm[i].enable_mic_a);
639c72fcc34Sopenharmony_ci
640c72fcc34Sopenharmony_ci		if (swap_check && swap[i]) {
641c72fcc34Sopenharmony_ci			ret = -EINVAL;
642c72fcc34Sopenharmony_ci			break;
643c72fcc34Sopenharmony_ci		}
644c72fcc34Sopenharmony_ci	}
645c72fcc34Sopenharmony_ci	return ret;
646c72fcc34Sopenharmony_ci}
647c72fcc34Sopenharmony_ci
648c72fcc34Sopenharmony_cistatic int configure_registers(struct intel_dmic_params *dmic, struct dmic_calc_configuration *cfg)
649c72fcc34Sopenharmony_ci{
650c72fcc34Sopenharmony_ci	int stereo[DMIC_HW_CONTROLLERS];
651c72fcc34Sopenharmony_ci	int swap[DMIC_HW_CONTROLLERS];
652c72fcc34Sopenharmony_ci	uint32_t val = 0;
653c72fcc34Sopenharmony_ci	int32_t ci;
654c72fcc34Sopenharmony_ci	uint32_t cu;
655c72fcc34Sopenharmony_ci	int ipm;
656c72fcc34Sopenharmony_ci	int of0;
657c72fcc34Sopenharmony_ci	int of1;
658c72fcc34Sopenharmony_ci	int fir_decim;
659c72fcc34Sopenharmony_ci	int fir_length;
660c72fcc34Sopenharmony_ci	int length;
661c72fcc34Sopenharmony_ci	int edge;
662c72fcc34Sopenharmony_ci	int soft_reset;
663c72fcc34Sopenharmony_ci	int cic_mute;
664c72fcc34Sopenharmony_ci	int fir_mute;
665c72fcc34Sopenharmony_ci	unsigned int i;
666c72fcc34Sopenharmony_ci	int j;
667c72fcc34Sopenharmony_ci	int ret;
668c72fcc34Sopenharmony_ci	int mic;
669c72fcc34Sopenharmony_ci	int chmap_bits;
670c72fcc34Sopenharmony_ci	int di = dmic->dmic_dai_index;
671c72fcc34Sopenharmony_ci	int dccomp = 1;
672c72fcc34Sopenharmony_ci	int array_a = 0;
673c72fcc34Sopenharmony_ci	int array_b = 0;
674c72fcc34Sopenharmony_ci	int bfth = 3; /* Should be 3 for 8 entries, 1 is 2 entries */
675c72fcc34Sopenharmony_ci	int th = 3; /* Used with TIE=1 */
676c72fcc34Sopenharmony_ci	int source[OUTCONTROLX_IPM_NUMSOURCES];
677c72fcc34Sopenharmony_ci
678c72fcc34Sopenharmony_ci	/*
679c72fcc34Sopenharmony_ci	 * ts_group value describes which audio channels in the hw fifo are enabled. A 32 bit
680c72fcc34Sopenharmony_ci	 * value is divided into 8 x 4 bit nibbles corresponding to 8 audio channels. Hex value 0xF
681c72fcc34Sopenharmony_ci	 * means "not in use", any other value means the channel is enabled. For example 0xFFFFFFFF
682c72fcc34Sopenharmony_ci	 * means no channels are enabled, 0xFFFFFF10 means channels 1 and 2 are enabled.
683c72fcc34Sopenharmony_ci	 *
684c72fcc34Sopenharmony_ci	 * ts_group array index corresponds to dmic hw fifos, that gather audio samples from pdm
685c72fcc34Sopenharmony_ci	 * controllers. 1 pdm controller can host 2 mono dmics and usually pdm controllers are
686c72fcc34Sopenharmony_ci	 * connected to 2 hw fifos -> we can for example run the dmics simultaneously with different
687c72fcc34Sopenharmony_ci	 * sampling rates.
688c72fcc34Sopenharmony_ci	 *
689c72fcc34Sopenharmony_ci	 * Currently there is no evidence we would ever have more than 2 hw fifos, so ts_group[2]
690c72fcc34Sopenharmony_ci	 * and ts_group[3] are not used for anything. Also the nibbles could be used for channel
691c72fcc34Sopenharmony_ci	 * mapping the pdm channels arbitrarely into hw fifos, however currently it is used as
692c72fcc34Sopenharmony_ci	 * binary not_enabled/enabled setting.
693c72fcc34Sopenharmony_ci	 *
694c72fcc34Sopenharmony_ci	 * if we have 2 dmics (stereo) it means we are using 1 pdm controller with possibly 2 hw
695c72fcc34Sopenharmony_ci	 * fifos:
696c72fcc34Sopenharmony_ci	 *        mic1      fifo0(2ch)
697c72fcc34Sopenharmony_ci	 *            \    /
698c72fcc34Sopenharmony_ci	 *             pdm0
699c72fcc34Sopenharmony_ci	 *            /    \
700c72fcc34Sopenharmony_ci	 *        mic2      fifo1(2ch)
701c72fcc34Sopenharmony_ci	 *
702c72fcc34Sopenharmony_ci	 * So in this case it makes only sense to control ts_group indexes 0 and 1 and their last 2
703c72fcc34Sopenharmony_ci	 * nibbles (as we have only 2 channels).
704c72fcc34Sopenharmony_ci	 *
705c72fcc34Sopenharmony_ci	 * if we have 4 dmics, it means we are using 2 pdm controller with possibly 2 x 4 channel hw
706c72fcc34Sopenharmony_ci	 * fifos:
707c72fcc34Sopenharmony_ci	 *
708c72fcc34Sopenharmony_ci	 *        mic1      fifo0(4ch)
709c72fcc34Sopenharmony_ci	 *            \    /    /
710c72fcc34Sopenharmony_ci	 *             pdm0    /
711c72fcc34Sopenharmony_ci	 *            /    \  /
712c72fcc34Sopenharmony_ci	 *        mic2      \/
713c72fcc34Sopenharmony_ci	 *	  mic3      /\
714c72fcc34Sopenharmony_ci	 *            \    /  \
715c72fcc34Sopenharmony_ci	 *             pdm1    \
716c72fcc34Sopenharmony_ci	 *            /    \    \
717c72fcc34Sopenharmony_ci	 *        mic4      fifo1(4ch)
718c72fcc34Sopenharmony_ci	 *
719c72fcc34Sopenharmony_ci	 * So it makes sense to control ts_group indexes 0 and 1 and their last 4 nibbles.
720c72fcc34Sopenharmony_ci	 *
721c72fcc34Sopenharmony_ci	 * channel_pdm_mask defines which existing pdm controllers will be taken into use. So if
722c72fcc34Sopenharmony_ci	 * either of mic a or b is enabled -> that particular pdm controller is in use. For example
723c72fcc34Sopenharmony_ci	 * pdm0 in use/not_in_use is defined by setting bit 0 in channel_pdm_mask to 1/0.
724c72fcc34Sopenharmony_ci	 *
725c72fcc34Sopenharmony_ci	 * channel_ctrl_mask defines what mic channels are available in hw for a pdm controller. in
726c72fcc34Sopenharmony_ci	 * theory pdm controller could have only 1 channel enabled, in practice there's always 2
727c72fcc34Sopenharmony_ci	 * channels which are both enabled -> set bits 0 and 1.
728c72fcc34Sopenharmony_ci	 */
729c72fcc34Sopenharmony_ci
730c72fcc34Sopenharmony_ci	for (i = 0, mic = 0, chmap_bits = 4; i < DMIC_HW_CONTROLLERS; i++) {
731c72fcc34Sopenharmony_ci		/* enable fifo channels (ts_group) based on mic_enable in dai definition */
732c72fcc34Sopenharmony_ci		if (dmic->dmic_prm[di].pdm[i].enable_mic_a) {
733c72fcc34Sopenharmony_ci			dmic->dmic_blob.ts_group[di] &= ~(0xF << (chmap_bits * mic));
734c72fcc34Sopenharmony_ci			dmic->dmic_blob.ts_group[di] |= 0x0 << (chmap_bits * mic);
735c72fcc34Sopenharmony_ci		}
736c72fcc34Sopenharmony_ci		mic++;
737c72fcc34Sopenharmony_ci		if (dmic->dmic_prm[di].pdm[i].enable_mic_b) {
738c72fcc34Sopenharmony_ci			dmic->dmic_blob.ts_group[di] &= ~(0xF << (chmap_bits * mic));
739c72fcc34Sopenharmony_ci			dmic->dmic_blob.ts_group[di] |= 0x1 << (chmap_bits * mic);
740c72fcc34Sopenharmony_ci		}
741c72fcc34Sopenharmony_ci		mic++;
742c72fcc34Sopenharmony_ci	}
743c72fcc34Sopenharmony_ci
744c72fcc34Sopenharmony_ci	/* set channel_pdm_mask to describe what pdm controllers are in use */
745c72fcc34Sopenharmony_ci	for (i = 0; i < dmic->dmic_prm[di].num_pdm_active; i++)
746c72fcc34Sopenharmony_ci		dmic->dmic_blob.channel_pdm_mask |= 1 << i;
747c72fcc34Sopenharmony_ci
748c72fcc34Sopenharmony_ci	/* set always both mic channels enabled */
749c72fcc34Sopenharmony_ci	dmic->dmic_blob.channel_ctrl_mask = 0x3;
750c72fcc34Sopenharmony_ci
751c72fcc34Sopenharmony_ci	/* Normal start sequence */
752c72fcc34Sopenharmony_ci	soft_reset = 0;
753c72fcc34Sopenharmony_ci	cic_mute = 0;
754c72fcc34Sopenharmony_ci	fir_mute = 0;
755c72fcc34Sopenharmony_ci
756c72fcc34Sopenharmony_ci	/* OUTCONTROL0 and OUTCONTROL1 */
757c72fcc34Sopenharmony_ci	of0 = (dmic->dmic_prm[0].fifo_bits == 32) ? 2 : 0;
758c72fcc34Sopenharmony_ci	of1 = (dmic->dmic_prm[1].fifo_bits == 32) ? 2 : 0;
759c72fcc34Sopenharmony_ci
760c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[di].driver_version == 1) {
761c72fcc34Sopenharmony_ci		if (di == 0) {
762c72fcc34Sopenharmony_ci			ipm_helper1(dmic, &ipm);
763c72fcc34Sopenharmony_ci			val = OUTCONTROL0_TIE(0) |
764c72fcc34Sopenharmony_ci				OUTCONTROL0_SIP(0) |
765c72fcc34Sopenharmony_ci				OUTCONTROL0_FINIT(0) |
766c72fcc34Sopenharmony_ci				OUTCONTROL0_FCI(0) |
767c72fcc34Sopenharmony_ci				OUTCONTROL0_BFTH(bfth) |
768c72fcc34Sopenharmony_ci				OUTCONTROL0_OF(of0) |
769c72fcc34Sopenharmony_ci				OUTCONTROL0_IPM_VER1(ipm) |
770c72fcc34Sopenharmony_ci				OUTCONTROL0_TH(th);
771c72fcc34Sopenharmony_ci		} else {
772c72fcc34Sopenharmony_ci			ipm_helper1(dmic, &ipm);
773c72fcc34Sopenharmony_ci			val = OUTCONTROL1_TIE(0) |
774c72fcc34Sopenharmony_ci				OUTCONTROL1_SIP(0) |
775c72fcc34Sopenharmony_ci				OUTCONTROL1_FINIT(0) |
776c72fcc34Sopenharmony_ci				OUTCONTROL1_FCI(0) |
777c72fcc34Sopenharmony_ci				OUTCONTROL1_BFTH(bfth) |
778c72fcc34Sopenharmony_ci				OUTCONTROL1_OF(of1) |
779c72fcc34Sopenharmony_ci				OUTCONTROL1_IPM_VER1(ipm) |
780c72fcc34Sopenharmony_ci				OUTCONTROL1_TH(th);
781c72fcc34Sopenharmony_ci		}
782c72fcc34Sopenharmony_ci	}
783c72fcc34Sopenharmony_ci
784c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[di].driver_version == 2 || dmic->dmic_prm[di].driver_version == 3) {
785c72fcc34Sopenharmony_ci		if (di == 0) {
786c72fcc34Sopenharmony_ci			ipm_helper2(dmic, source, &ipm);
787c72fcc34Sopenharmony_ci			val = OUTCONTROL0_TIE(0) |
788c72fcc34Sopenharmony_ci				OUTCONTROL0_SIP(0) |
789c72fcc34Sopenharmony_ci				OUTCONTROL0_FINIT(0) |
790c72fcc34Sopenharmony_ci				OUTCONTROL0_FCI(0) |
791c72fcc34Sopenharmony_ci				OUTCONTROL0_BFTH(bfth) |
792c72fcc34Sopenharmony_ci				OUTCONTROL0_OF(of0) |
793c72fcc34Sopenharmony_ci				OUTCONTROL0_IPM_VER2(ipm) |
794c72fcc34Sopenharmony_ci				OUTCONTROL0_IPM_SOURCE_1(source[0]) |
795c72fcc34Sopenharmony_ci				OUTCONTROL0_IPM_SOURCE_2(source[1]) |
796c72fcc34Sopenharmony_ci				OUTCONTROL0_IPM_SOURCE_3(source[2]) |
797c72fcc34Sopenharmony_ci				OUTCONTROL0_IPM_SOURCE_4(source[3]) |
798c72fcc34Sopenharmony_ci				OUTCONTROL0_IPM_SOURCE_MODE(1) |
799c72fcc34Sopenharmony_ci				OUTCONTROL0_TH(th);
800c72fcc34Sopenharmony_ci		} else {
801c72fcc34Sopenharmony_ci			ipm_helper2(dmic, source, &ipm);
802c72fcc34Sopenharmony_ci			val = OUTCONTROL1_TIE(0) |
803c72fcc34Sopenharmony_ci				OUTCONTROL1_SIP(0) |
804c72fcc34Sopenharmony_ci				OUTCONTROL1_FINIT(0) |
805c72fcc34Sopenharmony_ci				OUTCONTROL1_FCI(0) |
806c72fcc34Sopenharmony_ci				OUTCONTROL1_BFTH(bfth) |
807c72fcc34Sopenharmony_ci				OUTCONTROL1_OF(of1) |
808c72fcc34Sopenharmony_ci				OUTCONTROL1_IPM_VER2(ipm) |
809c72fcc34Sopenharmony_ci				OUTCONTROL1_IPM_SOURCE_1(source[0]) |
810c72fcc34Sopenharmony_ci				OUTCONTROL1_IPM_SOURCE_2(source[1]) |
811c72fcc34Sopenharmony_ci				OUTCONTROL1_IPM_SOURCE_3(source[2]) |
812c72fcc34Sopenharmony_ci				OUTCONTROL1_IPM_SOURCE_4(source[3]) |
813c72fcc34Sopenharmony_ci				OUTCONTROL1_IPM_SOURCE_MODE(1) |
814c72fcc34Sopenharmony_ci				OUTCONTROL1_TH(th);
815c72fcc34Sopenharmony_ci		}
816c72fcc34Sopenharmony_ci	}
817c72fcc34Sopenharmony_ci
818c72fcc34Sopenharmony_ci	dmic->dmic_blob.chan_ctrl_cfg[di] = val;
819c72fcc34Sopenharmony_ci
820c72fcc34Sopenharmony_ci	ret = stereo_helper(dmic, stereo, swap);
821c72fcc34Sopenharmony_ci	if (ret < 0) {
822c72fcc34Sopenharmony_ci		fprintf(stderr, "configure_registers(): enable conflict\n");
823c72fcc34Sopenharmony_ci		return ret;
824c72fcc34Sopenharmony_ci	}
825c72fcc34Sopenharmony_ci
826c72fcc34Sopenharmony_ci	for (i = 0; i < DMIC_HW_CONTROLLERS; i++) {
827c72fcc34Sopenharmony_ci		/* CIC */
828c72fcc34Sopenharmony_ci		val = CIC_CONTROL_SOFT_RESET(soft_reset) |
829c72fcc34Sopenharmony_ci			CIC_CONTROL_CIC_START_B(1) |
830c72fcc34Sopenharmony_ci			CIC_CONTROL_CIC_START_A(1) |
831c72fcc34Sopenharmony_ci			CIC_CONTROL_MIC_B_POLARITY(dmic->dmic_prm[di].pdm[i].polarity_mic_b) |
832c72fcc34Sopenharmony_ci			CIC_CONTROL_MIC_A_POLARITY(dmic->dmic_prm[di].pdm[i].polarity_mic_a) |
833c72fcc34Sopenharmony_ci			CIC_CONTROL_MIC_MUTE(cic_mute);
834c72fcc34Sopenharmony_ci
835c72fcc34Sopenharmony_ci		if (dmic->dmic_prm[di].driver_version == 1)
836c72fcc34Sopenharmony_ci			val |= CIC_CONTROL_STEREO_MODE(stereo[i]);
837c72fcc34Sopenharmony_ci
838c72fcc34Sopenharmony_ci		dmic->dmic_blob_pdm[i].cic_control = val;
839c72fcc34Sopenharmony_ci
840c72fcc34Sopenharmony_ci		val = CIC_CONFIG_CIC_SHIFT(cfg->cic_shift + 8) |
841c72fcc34Sopenharmony_ci			CIC_CONFIG_COMB_COUNT(cfg->mcic - 1);
842c72fcc34Sopenharmony_ci		dmic->dmic_blob_pdm[i].cic_config = val;
843c72fcc34Sopenharmony_ci
844c72fcc34Sopenharmony_ci		/* Mono right channel mic usage requires swap of PDM channels
845c72fcc34Sopenharmony_ci		 * since the mono decimation is done with only left channel
846c72fcc34Sopenharmony_ci		 * processing active.
847c72fcc34Sopenharmony_ci		 */
848c72fcc34Sopenharmony_ci		edge = dmic->dmic_prm[di].pdm[i].clk_edge;
849c72fcc34Sopenharmony_ci		if (swap[i])
850c72fcc34Sopenharmony_ci			edge = !edge;
851c72fcc34Sopenharmony_ci
852c72fcc34Sopenharmony_ci		val = MIC_CONTROL_PDM_CLKDIV(cfg->clkdiv - 2) |
853c72fcc34Sopenharmony_ci			MIC_CONTROL_PDM_SKEW(dmic->dmic_prm[di].pdm[i].skew) |
854c72fcc34Sopenharmony_ci			MIC_CONTROL_CLK_EDGE(edge) |
855c72fcc34Sopenharmony_ci			MIC_CONTROL_PDM_EN_B(1) |
856c72fcc34Sopenharmony_ci			MIC_CONTROL_PDM_EN_A(1);
857c72fcc34Sopenharmony_ci		dmic->dmic_blob_pdm[i].mic_control = val;
858c72fcc34Sopenharmony_ci
859c72fcc34Sopenharmony_ci		/*
860c72fcc34Sopenharmony_ci		 * Here we have to check the both FIRs if they are
861c72fcc34Sopenharmony_ci		 * configured as the later configured DAI may have changed
862c72fcc34Sopenharmony_ci		 * the configuration of the DAI configured earlier.
863c72fcc34Sopenharmony_ci		 */
864c72fcc34Sopenharmony_ci		if (cfg->mfir_a) {
865c72fcc34Sopenharmony_ci			/* FIR A */
866c72fcc34Sopenharmony_ci			fir_decim = MAX(cfg->mfir_a - 1, 0);
867c72fcc34Sopenharmony_ci			fir_length = MAX(cfg->fir_a_length - 1, 0);
868c72fcc34Sopenharmony_ci			val = FIR_CONTROL_A_START(1) |
869c72fcc34Sopenharmony_ci				FIR_CONTROL_A_ARRAY_START_EN(array_a) |
870c72fcc34Sopenharmony_ci				FIR_CONTROL_A_DCCOMP(dccomp) |
871c72fcc34Sopenharmony_ci				FIR_CONTROL_A_MUTE(fir_mute) |
872c72fcc34Sopenharmony_ci				FIR_CONTROL_A_STEREO(stereo[i]);
873c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][0].fir_control = val;
874c72fcc34Sopenharmony_ci
875c72fcc34Sopenharmony_ci			val = FIR_CONFIG_A_FIR_DECIMATION(fir_decim) |
876c72fcc34Sopenharmony_ci				FIR_CONFIG_A_FIR_SHIFT(cfg->fir_a_shift) |
877c72fcc34Sopenharmony_ci				FIR_CONFIG_A_FIR_LENGTH(fir_length);
878c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][0].fir_config = val;
879c72fcc34Sopenharmony_ci
880c72fcc34Sopenharmony_ci			val = DC_OFFSET_LEFT_A_DC_OFFS(DCCOMP_TC0);
881c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][0].dc_offset_left = val;
882c72fcc34Sopenharmony_ci
883c72fcc34Sopenharmony_ci			val = DC_OFFSET_RIGHT_A_DC_OFFS(DCCOMP_TC0);
884c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][0].dc_offset_right = val;
885c72fcc34Sopenharmony_ci
886c72fcc34Sopenharmony_ci			val = OUT_GAIN_LEFT_A_GAIN(0);
887c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][0].out_gain_left = val;
888c72fcc34Sopenharmony_ci
889c72fcc34Sopenharmony_ci			val = OUT_GAIN_RIGHT_A_GAIN(0);
890c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][0].out_gain_right = val;
891c72fcc34Sopenharmony_ci
892c72fcc34Sopenharmony_ci			/* Write coef RAM A with scaled coefficient in reverse order */
893c72fcc34Sopenharmony_ci			length = cfg->fir_a_length;
894c72fcc34Sopenharmony_ci			for (j = 0; j < length; j++) {
895c72fcc34Sopenharmony_ci				ci = (int32_t)Q_MULTSR_32X32((int64_t)cfg->fir_a->coef[j],
896c72fcc34Sopenharmony_ci							     cfg->fir_a_scale, 31,
897c72fcc34Sopenharmony_ci							     DMIC_FIR_SCALE_Q, DMIC_HW_FIR_COEF_Q);
898c72fcc34Sopenharmony_ci				cu = FIR_COEF_A(ci);
899c72fcc34Sopenharmony_ci				/* blob_pdm[i].fir_coeffs[0][j] = cu; */
900c72fcc34Sopenharmony_ci				dmic->dmic_fir_array.fir_coeffs[i][0][j] = cu;
901c72fcc34Sopenharmony_ci			}
902c72fcc34Sopenharmony_ci			dmic->dmic_fir_array.fir_len[0] = length;
903c72fcc34Sopenharmony_ci		} else {
904c72fcc34Sopenharmony_ci			dmic->dmic_fir_array.fir_len[0] = 0;
905c72fcc34Sopenharmony_ci		}
906c72fcc34Sopenharmony_ci
907c72fcc34Sopenharmony_ci		if (cfg->mfir_b) {
908c72fcc34Sopenharmony_ci			/* FIR B */
909c72fcc34Sopenharmony_ci			fir_decim = MAX(cfg->mfir_b - 1, 0);
910c72fcc34Sopenharmony_ci			fir_length = MAX(cfg->fir_b_length - 1, 0);
911c72fcc34Sopenharmony_ci			val = FIR_CONTROL_B_START(1) |
912c72fcc34Sopenharmony_ci				FIR_CONTROL_B_ARRAY_START_EN(array_b) |
913c72fcc34Sopenharmony_ci				FIR_CONTROL_B_DCCOMP(dccomp) |
914c72fcc34Sopenharmony_ci				FIR_CONTROL_B_MUTE(fir_mute) |
915c72fcc34Sopenharmony_ci				FIR_CONTROL_B_STEREO(stereo[i]);
916c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][1].fir_control = val;
917c72fcc34Sopenharmony_ci
918c72fcc34Sopenharmony_ci			val = FIR_CONFIG_B_FIR_DECIMATION(fir_decim) |
919c72fcc34Sopenharmony_ci				FIR_CONFIG_B_FIR_SHIFT(cfg->fir_b_shift) |
920c72fcc34Sopenharmony_ci				FIR_CONFIG_B_FIR_LENGTH(fir_length);
921c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][1].fir_config = val;
922c72fcc34Sopenharmony_ci			val = DC_OFFSET_LEFT_B_DC_OFFS(DCCOMP_TC0);
923c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][1].dc_offset_left = val;
924c72fcc34Sopenharmony_ci
925c72fcc34Sopenharmony_ci			val = DC_OFFSET_RIGHT_B_DC_OFFS(DCCOMP_TC0);
926c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][1].dc_offset_right = val;
927c72fcc34Sopenharmony_ci
928c72fcc34Sopenharmony_ci			val = OUT_GAIN_LEFT_B_GAIN(0);
929c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][1].out_gain_left = val;
930c72fcc34Sopenharmony_ci
931c72fcc34Sopenharmony_ci			val = OUT_GAIN_RIGHT_B_GAIN(0);
932c72fcc34Sopenharmony_ci			dmic->dmic_blob_fir[i][1].out_gain_right = val;
933c72fcc34Sopenharmony_ci
934c72fcc34Sopenharmony_ci			/* Write coef RAM B with scaled coefficient in reverse order */
935c72fcc34Sopenharmony_ci			length = cfg->fir_b_length;
936c72fcc34Sopenharmony_ci			for (j = 0; j < length; j++) {
937c72fcc34Sopenharmony_ci				ci = (int32_t)Q_MULTSR_32X32((int64_t)cfg->fir_b->coef[j],
938c72fcc34Sopenharmony_ci							     cfg->fir_b_scale, 31,
939c72fcc34Sopenharmony_ci							     DMIC_FIR_SCALE_Q, DMIC_HW_FIR_COEF_Q);
940c72fcc34Sopenharmony_ci				cu = FIR_COEF_B(ci);
941c72fcc34Sopenharmony_ci				/* blob_pdm[i].fir_coeffs[1][j] = cu; */
942c72fcc34Sopenharmony_ci				dmic->dmic_fir_array.fir_coeffs[i][1][j] = cu;
943c72fcc34Sopenharmony_ci			}
944c72fcc34Sopenharmony_ci			dmic->dmic_fir_array.fir_len[1] = length;
945c72fcc34Sopenharmony_ci		} else {
946c72fcc34Sopenharmony_ci			dmic->dmic_fir_array.fir_len[1] = 0;
947c72fcc34Sopenharmony_ci		}
948c72fcc34Sopenharmony_ci	}
949c72fcc34Sopenharmony_ci
950c72fcc34Sopenharmony_ci	return 0;
951c72fcc34Sopenharmony_ci}
952c72fcc34Sopenharmony_ci
953c72fcc34Sopenharmony_ci/* The decimation for PDM (pulse density modulation) stream is done in a programmable HW filter
954c72fcc34Sopenharmony_ci * engine. The input to configuration algorithm is needed sample rate, channels/enabled microphones,
955c72fcc34Sopenharmony_ci * microphone clock range, microphone clock duty cycle range, and system clock rate.
956c72fcc34Sopenharmony_ci *
957c72fcc34Sopenharmony_ci * The PDM bus clock divider, CIC and FIR decimation ratios are searched and configuration for
958c72fcc34Sopenharmony_ci * optimal power consumption, filtering requirements, and HW constraints is chosen. The FIR filter
959c72fcc34Sopenharmony_ci * for the chosen decimation is looked up from table and scaled to match the other decimation path
960c72fcc34Sopenharmony_ci * sensitivity.
961c72fcc34Sopenharmony_ci */
962c72fcc34Sopenharmony_ciint dmic_calculate(struct intel_nhlt_params *nhlt)
963c72fcc34Sopenharmony_ci{
964c72fcc34Sopenharmony_ci	struct intel_dmic_params *dmic = (struct intel_dmic_params *)nhlt->dmic_params;
965c72fcc34Sopenharmony_ci	struct dmic_calc_matched_modes modes_ab;
966c72fcc34Sopenharmony_ci	struct dmic_calc_decim_modes modes_a;
967c72fcc34Sopenharmony_ci	struct dmic_calc_decim_modes modes_b;
968c72fcc34Sopenharmony_ci	struct dmic_calc_configuration cfg;
969c72fcc34Sopenharmony_ci	int ret = 0;
970c72fcc34Sopenharmony_ci	int di;
971c72fcc34Sopenharmony_ci
972c72fcc34Sopenharmony_ci	if (!dmic)
973c72fcc34Sopenharmony_ci		return -EINVAL;
974c72fcc34Sopenharmony_ci
975c72fcc34Sopenharmony_ci	di = dmic->dmic_dai_index;
976c72fcc34Sopenharmony_ci
977c72fcc34Sopenharmony_ci	if (di >= DMIC_HW_FIFOS) {
978c72fcc34Sopenharmony_ci		fprintf(stderr, "dmic_set_config(): dai->index exceeds number of FIFOs\n");
979c72fcc34Sopenharmony_ci		ret = -EINVAL;
980c72fcc34Sopenharmony_ci		goto out;
981c72fcc34Sopenharmony_ci	}
982c72fcc34Sopenharmony_ci
983c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[di].num_pdm_active > DMIC_HW_CONTROLLERS) {
984c72fcc34Sopenharmony_ci		fprintf(stderr, "dmic_set_config():controller count exceeds platform capability\n");
985c72fcc34Sopenharmony_ci		ret = -EINVAL;
986c72fcc34Sopenharmony_ci		goto out;
987c72fcc34Sopenharmony_ci	}
988c72fcc34Sopenharmony_ci
989c72fcc34Sopenharmony_ci	/* fifo bits 0 means fifo disabled */
990c72fcc34Sopenharmony_ci	switch (dmic->dmic_prm[di].fifo_bits) {
991c72fcc34Sopenharmony_ci	case 0:
992c72fcc34Sopenharmony_ci	case 16:
993c72fcc34Sopenharmony_ci	case 32:
994c72fcc34Sopenharmony_ci		break;
995c72fcc34Sopenharmony_ci	default:
996c72fcc34Sopenharmony_ci		fprintf(stderr, "dmic_set_config(): fifo_bits EINVAL\n");
997c72fcc34Sopenharmony_ci		ret = -EINVAL;
998c72fcc34Sopenharmony_ci		goto out;
999c72fcc34Sopenharmony_ci	}
1000c72fcc34Sopenharmony_ci
1001c72fcc34Sopenharmony_ci	/* Match and select optimal decimators configuration for FIFOs A and B paths. This setup
1002c72fcc34Sopenharmony_ci	 * phase is still abstract. Successful completion points struct cfg to FIR coefficients and
1003c72fcc34Sopenharmony_ci	 * contains the scale value to use for FIR coefficient RAM write as well as the CIC and FIR
1004c72fcc34Sopenharmony_ci	 * shift values.
1005c72fcc34Sopenharmony_ci	 */
1006c72fcc34Sopenharmony_ci	find_modes(dmic, &modes_a, dmic->dmic_prm[0].fifo_fs);
1007c72fcc34Sopenharmony_ci	if (modes_a.num_of_modes == 0 && dmic->dmic_prm[0].fifo_fs > 0) {
1008c72fcc34Sopenharmony_ci		fprintf(stderr, "dmic_set_config(): No modes found for FIFO A\n");
1009c72fcc34Sopenharmony_ci		ret = -EINVAL;
1010c72fcc34Sopenharmony_ci		goto out;
1011c72fcc34Sopenharmony_ci	}
1012c72fcc34Sopenharmony_ci
1013c72fcc34Sopenharmony_ci	find_modes(dmic, &modes_b, dmic->dmic_prm[1].fifo_fs);
1014c72fcc34Sopenharmony_ci	if (modes_b.num_of_modes == 0 && dmic->dmic_prm[1].fifo_fs > 0) {
1015c72fcc34Sopenharmony_ci		fprintf(stderr, "dmic_set_config(): No modes found for FIFO B\n");
1016c72fcc34Sopenharmony_ci		ret = -EINVAL;
1017c72fcc34Sopenharmony_ci		goto out;
1018c72fcc34Sopenharmony_ci	}
1019c72fcc34Sopenharmony_ci
1020c72fcc34Sopenharmony_ci	match_modes(&modes_ab, &modes_a, &modes_b);
1021c72fcc34Sopenharmony_ci	ret = select_mode(dmic, &cfg, &modes_ab);
1022c72fcc34Sopenharmony_ci	if (ret < 0) {
1023c72fcc34Sopenharmony_ci		fprintf(stderr, "dmic_set_config(): select_mode() failed\n");
1024c72fcc34Sopenharmony_ci		ret = -EINVAL;
1025c72fcc34Sopenharmony_ci		goto out;
1026c72fcc34Sopenharmony_ci	}
1027c72fcc34Sopenharmony_ci
1028c72fcc34Sopenharmony_ci	/* Struct reg contains a mirror of actual HW registers. Determine register bits
1029c72fcc34Sopenharmony_ci	 * configuration from decimator configuration and the requested parameters.
1030c72fcc34Sopenharmony_ci	 */
1031c72fcc34Sopenharmony_ci	ret = configure_registers(dmic, &cfg);
1032c72fcc34Sopenharmony_ci	if (ret < 0) {
1033c72fcc34Sopenharmony_ci		fprintf(stderr, "dmic_set_config(): cannot configure registers\n");
1034c72fcc34Sopenharmony_ci		ret = -EINVAL;
1035c72fcc34Sopenharmony_ci		goto out;
1036c72fcc34Sopenharmony_ci	}
1037c72fcc34Sopenharmony_ci
1038c72fcc34Sopenharmony_ci	dmic_print_internal(dmic);
1039c72fcc34Sopenharmony_ci
1040c72fcc34Sopenharmony_ci	dmic->dmic_count++;
1041c72fcc34Sopenharmony_ci
1042c72fcc34Sopenharmony_ciout:
1043c72fcc34Sopenharmony_ci	return ret;
1044c72fcc34Sopenharmony_ci}
1045c72fcc34Sopenharmony_ci
1046c72fcc34Sopenharmony_ciint dmic_get_params(struct intel_nhlt_params *nhlt, int index, uint32_t *sample_rate,
1047c72fcc34Sopenharmony_ci		    uint16_t *channel_count, uint32_t *bits_per_sample, uint8_t *array_type,
1048c72fcc34Sopenharmony_ci		    uint8_t *num_mics, uint8_t *extension, uint32_t *snr, uint32_t *sensitivity)
1049c72fcc34Sopenharmony_ci{
1050c72fcc34Sopenharmony_ci	struct intel_dmic_params *dmic = (struct intel_dmic_params *)nhlt->dmic_params;
1051c72fcc34Sopenharmony_ci	uint32_t channels = 0;
1052c72fcc34Sopenharmony_ci
1053c72fcc34Sopenharmony_ci	if (!dmic)
1054c72fcc34Sopenharmony_ci		return -EINVAL;
1055c72fcc34Sopenharmony_ci
1056c72fcc34Sopenharmony_ci	/* check all pdm's for enabled mics */
1057c72fcc34Sopenharmony_ci	*channel_count = 0;
1058c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[index].pdm[0].enable_mic_a)
1059c72fcc34Sopenharmony_ci		channels++;
1060c72fcc34Sopenharmony_ci
1061c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[index].pdm[0].enable_mic_b)
1062c72fcc34Sopenharmony_ci		channels++;
1063c72fcc34Sopenharmony_ci
1064c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[index].pdm[1].enable_mic_a)
1065c72fcc34Sopenharmony_ci		channels++;
1066c72fcc34Sopenharmony_ci
1067c72fcc34Sopenharmony_ci	if (dmic->dmic_prm[index].pdm[1].enable_mic_b)
1068c72fcc34Sopenharmony_ci		channels++;
1069c72fcc34Sopenharmony_ci
1070c72fcc34Sopenharmony_ci	*sample_rate = dmic->dmic_prm[index].fifo_fs;
1071c72fcc34Sopenharmony_ci	*channel_count = channels;
1072c72fcc34Sopenharmony_ci	*bits_per_sample = dmic->dmic_prm[index].fifo_bits;
1073c72fcc34Sopenharmony_ci	*num_mics = dmic->dmic_mic_config.num_mics;
1074c72fcc34Sopenharmony_ci	*extension = dmic->dmic_mic_config.extension;
1075c72fcc34Sopenharmony_ci	*array_type = dmic->dmic_mic_config.array_type;
1076c72fcc34Sopenharmony_ci	*snr = dmic->dmic_mic_config.snr;
1077c72fcc34Sopenharmony_ci	*sensitivity = dmic->dmic_mic_config.sensitivity;
1078c72fcc34Sopenharmony_ci
1079c72fcc34Sopenharmony_ci	return 0;
1080c72fcc34Sopenharmony_ci}
1081c72fcc34Sopenharmony_ci
1082c72fcc34Sopenharmony_ciint dmic_get_mic_params(struct intel_nhlt_params *nhlt, int index,
1083c72fcc34Sopenharmony_ci			uint8_t *type, uint8_t *panel, uint32_t *speaker_position_distance,
1084c72fcc34Sopenharmony_ci			uint32_t *horizontal_offset, uint32_t *vertical_offset,
1085c72fcc34Sopenharmony_ci			uint8_t *frequency_low_band, uint8_t *frequency_high_band,
1086c72fcc34Sopenharmony_ci			uint16_t *direction_angle, uint16_t *elevation_angle,
1087c72fcc34Sopenharmony_ci			uint16_t *vertical_angle_begin, uint16_t *vertical_angle_end,
1088c72fcc34Sopenharmony_ci			uint16_t *horizontal_angle_begin, uint16_t *horizontal_angle_end)
1089c72fcc34Sopenharmony_ci{
1090c72fcc34Sopenharmony_ci	struct intel_dmic_params *dmic = (struct intel_dmic_params *)nhlt->dmic_params;
1091c72fcc34Sopenharmony_ci
1092c72fcc34Sopenharmony_ci	if (!dmic)
1093c72fcc34Sopenharmony_ci		return -EINVAL;
1094c72fcc34Sopenharmony_ci
1095c72fcc34Sopenharmony_ci	*type = dmic->dmic_mic_config.vendor[index].type;
1096c72fcc34Sopenharmony_ci	*panel = dmic->dmic_mic_config.vendor[index].panel;
1097c72fcc34Sopenharmony_ci	*speaker_position_distance = dmic->dmic_mic_config.vendor[index].speaker_position_distance;
1098c72fcc34Sopenharmony_ci	*horizontal_offset = dmic->dmic_mic_config.vendor[index].horizontal_offset;
1099c72fcc34Sopenharmony_ci	*vertical_offset = dmic->dmic_mic_config.vendor[index].vertical_offset;
1100c72fcc34Sopenharmony_ci	*frequency_low_band = dmic->dmic_mic_config.vendor[index].frequency_low_band;
1101c72fcc34Sopenharmony_ci	*frequency_high_band = dmic->dmic_mic_config.vendor[index].frequency_high_band;
1102c72fcc34Sopenharmony_ci	*direction_angle = dmic->dmic_mic_config.vendor[index].direction_angle;
1103c72fcc34Sopenharmony_ci	*elevation_angle = dmic->dmic_mic_config.vendor[index].elevation_angle;
1104c72fcc34Sopenharmony_ci	*vertical_angle_begin = dmic->dmic_mic_config.vendor[index].vertical_angle_begin;
1105c72fcc34Sopenharmony_ci	*vertical_angle_end = dmic->dmic_mic_config.vendor[index].vertical_angle_end;
1106c72fcc34Sopenharmony_ci	*horizontal_angle_begin = dmic->dmic_mic_config.vendor[index].horizontal_angle_begin;
1107c72fcc34Sopenharmony_ci	*horizontal_angle_end = dmic->dmic_mic_config.vendor[index].horizontal_angle_end;
1108c72fcc34Sopenharmony_ci
1109c72fcc34Sopenharmony_ci	return 0;
1110c72fcc34Sopenharmony_ci}
1111c72fcc34Sopenharmony_ci
1112c72fcc34Sopenharmony_ciint dmic_get_vendor_blob_size(struct intel_nhlt_params *nhlt, size_t *size)
1113c72fcc34Sopenharmony_ci{
1114c72fcc34Sopenharmony_ci	struct intel_dmic_params *dmic = (struct intel_dmic_params *)nhlt->dmic_params;
1115c72fcc34Sopenharmony_ci	int i, fir_index_0, fir_index_1;
1116c72fcc34Sopenharmony_ci
1117c72fcc34Sopenharmony_ci	if (!dmic || !dmic->dmic_count)
1118c72fcc34Sopenharmony_ci		return -EINVAL;
1119c72fcc34Sopenharmony_ci
1120c72fcc34Sopenharmony_ci	*size = sizeof(struct dmic_intel_config_data);
1121c72fcc34Sopenharmony_ci
1122c72fcc34Sopenharmony_ci	/* if either of the fir is 0 length, copy the existing fir twice */
1123c72fcc34Sopenharmony_ci	fir_index_0 = 0;
1124c72fcc34Sopenharmony_ci	fir_index_1 = 1;
1125c72fcc34Sopenharmony_ci	if (dmic->dmic_fir_array.fir_len[0] == 0) {
1126c72fcc34Sopenharmony_ci		fir_index_0 = 1;
1127c72fcc34Sopenharmony_ci		fir_index_1 = 1;
1128c72fcc34Sopenharmony_ci	}
1129c72fcc34Sopenharmony_ci	if (dmic->dmic_fir_array.fir_len[1] == 0) {
1130c72fcc34Sopenharmony_ci		fir_index_0 = 0;
1131c72fcc34Sopenharmony_ci		fir_index_1 = 0;
1132c72fcc34Sopenharmony_ci	}
1133c72fcc34Sopenharmony_ci
1134c72fcc34Sopenharmony_ci	/* variable amount of pdm's */
1135c72fcc34Sopenharmony_ci	for (i = 0; i < DMIC_HW_CONTROLLERS; i++) {
1136c72fcc34Sopenharmony_ci		/* only copy the pdm data if it is enabled */
1137c72fcc34Sopenharmony_ci		if ((dmic->dmic_blob.channel_pdm_mask & BIT(i)) == 0)
1138c72fcc34Sopenharmony_ci			continue;
1139c72fcc34Sopenharmony_ci
1140c72fcc34Sopenharmony_ci		*size += sizeof(struct dmic_intel_pdm_ctrl_cfg);
1141c72fcc34Sopenharmony_ci		*size += sizeof(struct dmic_intel_fir_config) * DMIC_HW_FIFOS;
1142c72fcc34Sopenharmony_ci
1143c72fcc34Sopenharmony_ci		*size += dmic->dmic_fir_array.fir_len[fir_index_0] * sizeof(uint32_t);
1144c72fcc34Sopenharmony_ci		*size += dmic->dmic_fir_array.fir_len[fir_index_1] * sizeof(uint32_t);
1145c72fcc34Sopenharmony_ci	}
1146c72fcc34Sopenharmony_ci
1147c72fcc34Sopenharmony_ci	return 0;
1148c72fcc34Sopenharmony_ci}
1149c72fcc34Sopenharmony_ci
1150c72fcc34Sopenharmony_ciint dmic_get_vendor_blob_count(struct intel_nhlt_params *nhlt)
1151c72fcc34Sopenharmony_ci{
1152c72fcc34Sopenharmony_ci	struct intel_dmic_params *dmic = (struct intel_dmic_params *)nhlt->dmic_params;
1153c72fcc34Sopenharmony_ci
1154c72fcc34Sopenharmony_ci	if (!dmic || !dmic->dmic_count)
1155c72fcc34Sopenharmony_ci		return 0;
1156c72fcc34Sopenharmony_ci
1157c72fcc34Sopenharmony_ci	return dmic->dmic_count;
1158c72fcc34Sopenharmony_ci}
1159c72fcc34Sopenharmony_ci
1160c72fcc34Sopenharmony_ciint dmic_get_vendor_blob(struct intel_nhlt_params *nhlt, uint8_t *vendor_blob)
1161c72fcc34Sopenharmony_ci{
1162c72fcc34Sopenharmony_ci	struct intel_dmic_params *dmic = (struct intel_dmic_params *)nhlt->dmic_params;
1163c72fcc34Sopenharmony_ci	int i, fir_index_0, fir_index_1;
1164c72fcc34Sopenharmony_ci	uint8_t *orig_blob = vendor_blob;
1165c72fcc34Sopenharmony_ci	size_t blob_size;
1166c72fcc34Sopenharmony_ci
1167c72fcc34Sopenharmony_ci	if (!dmic || !dmic->dmic_count)
1168c72fcc34Sopenharmony_ci		return -EINVAL;
1169c72fcc34Sopenharmony_ci
1170c72fcc34Sopenharmony_ci	/* top level struct */
1171c72fcc34Sopenharmony_ci	memcpy(vendor_blob, &dmic->dmic_blob, sizeof(struct dmic_intel_config_data));
1172c72fcc34Sopenharmony_ci	vendor_blob += sizeof(struct dmic_intel_config_data);
1173c72fcc34Sopenharmony_ci
1174c72fcc34Sopenharmony_ci	/* if either of the fir is 0 length, copy the existing fir twice */
1175c72fcc34Sopenharmony_ci	fir_index_0 = 0;
1176c72fcc34Sopenharmony_ci	fir_index_1 = 1;
1177c72fcc34Sopenharmony_ci	if (dmic->dmic_fir_array.fir_len[0] == 0) {
1178c72fcc34Sopenharmony_ci		fir_index_0 = 1;
1179c72fcc34Sopenharmony_ci		fir_index_1 = 1;
1180c72fcc34Sopenharmony_ci	}
1181c72fcc34Sopenharmony_ci	if (dmic->dmic_fir_array.fir_len[1] == 0) {
1182c72fcc34Sopenharmony_ci		fir_index_0 = 0;
1183c72fcc34Sopenharmony_ci		fir_index_1 = 0;
1184c72fcc34Sopenharmony_ci	}
1185c72fcc34Sopenharmony_ci
1186c72fcc34Sopenharmony_ci	/* variable amount of pdm's */
1187c72fcc34Sopenharmony_ci	for (i = 0; i < DMIC_HW_CONTROLLERS; i++) {
1188c72fcc34Sopenharmony_ci		/* only copy the pdm data if it is enabled */
1189c72fcc34Sopenharmony_ci		if ((dmic->dmic_blob.channel_pdm_mask & BIT(i)) == 0)
1190c72fcc34Sopenharmony_ci			continue;
1191c72fcc34Sopenharmony_ci
1192c72fcc34Sopenharmony_ci		/* top level struct first pdm data */
1193c72fcc34Sopenharmony_ci		memcpy(vendor_blob, (uint8_t *)&dmic->dmic_blob_pdm[i],
1194c72fcc34Sopenharmony_ci		       sizeof(struct dmic_intel_pdm_ctrl_cfg));
1195c72fcc34Sopenharmony_ci		vendor_blob += sizeof(struct dmic_intel_pdm_ctrl_cfg);
1196c72fcc34Sopenharmony_ci
1197c72fcc34Sopenharmony_ci		/* top level struct first pdm data first fir */
1198c72fcc34Sopenharmony_ci		memcpy(vendor_blob, (uint8_t *)&dmic->dmic_blob_fir[i][fir_index_0],
1199c72fcc34Sopenharmony_ci		       sizeof(struct dmic_intel_fir_config));
1200c72fcc34Sopenharmony_ci		vendor_blob += sizeof(struct dmic_intel_fir_config);
1201c72fcc34Sopenharmony_ci
1202c72fcc34Sopenharmony_ci		/* top level struct first pdm data second fir */
1203c72fcc34Sopenharmony_ci		memcpy(vendor_blob, (uint8_t *)&dmic->dmic_blob_fir[i][fir_index_1],
1204c72fcc34Sopenharmony_ci		       sizeof(struct dmic_intel_fir_config));
1205c72fcc34Sopenharmony_ci		vendor_blob += sizeof(struct dmic_intel_fir_config);
1206c72fcc34Sopenharmony_ci
1207c72fcc34Sopenharmony_ci		/* fir coeffs a */
1208c72fcc34Sopenharmony_ci		memcpy(vendor_blob, (uint8_t *)&dmic->dmic_fir_array.fir_coeffs[i][fir_index_0][0],
1209c72fcc34Sopenharmony_ci		       dmic->dmic_fir_array.fir_len[fir_index_0] * sizeof(uint32_t));
1210c72fcc34Sopenharmony_ci		vendor_blob += dmic->dmic_fir_array.fir_len[fir_index_0] * sizeof(uint32_t);
1211c72fcc34Sopenharmony_ci
1212c72fcc34Sopenharmony_ci		/* fir coeffs b */
1213c72fcc34Sopenharmony_ci		memcpy(vendor_blob, (uint8_t *)&dmic->dmic_fir_array.fir_coeffs[i][fir_index_1][0],
1214c72fcc34Sopenharmony_ci		       dmic->dmic_fir_array.fir_len[fir_index_1] * sizeof(uint32_t));
1215c72fcc34Sopenharmony_ci		vendor_blob += dmic->dmic_fir_array.fir_len[fir_index_1] * sizeof(uint32_t);
1216c72fcc34Sopenharmony_ci	}
1217c72fcc34Sopenharmony_ci
1218c72fcc34Sopenharmony_ci	dmic_get_vendor_blob_size(nhlt, &blob_size);
1219c72fcc34Sopenharmony_ci	dmic_print_bytes_as_hex((uint8_t *)orig_blob, blob_size);
1220c72fcc34Sopenharmony_ci	dmic_print_integers_as_hex((uint32_t *)orig_blob, blob_size / 4);
1221c72fcc34Sopenharmony_ci
1222c72fcc34Sopenharmony_ci	return 0;
1223c72fcc34Sopenharmony_ci}
1224c72fcc34Sopenharmony_ci
1225c72fcc34Sopenharmony_ciint dmic_set_params(struct intel_nhlt_params *nhlt, int dai_index, int driver_version,
1226c72fcc34Sopenharmony_ci		    int io_clk, int num_pdm_active, int fifo_word_length, int clk_min, int clk_max,
1227c72fcc34Sopenharmony_ci		    int duty_min, int duty_max, int sample_rate, int unmute_ramp_time)
1228c72fcc34Sopenharmony_ci{
1229c72fcc34Sopenharmony_ci	struct intel_dmic_params *dmic = (struct intel_dmic_params *)nhlt->dmic_params;
1230c72fcc34Sopenharmony_ci
1231c72fcc34Sopenharmony_ci	if (!dmic)
1232c72fcc34Sopenharmony_ci		return -EINVAL;
1233c72fcc34Sopenharmony_ci
1234c72fcc34Sopenharmony_ci	if (dai_index >= DMIC_HW_FIFOS) {
1235c72fcc34Sopenharmony_ci		fprintf(stderr, "set_dmic_data illegal dai index\n");
1236c72fcc34Sopenharmony_ci		return -EINVAL;
1237c72fcc34Sopenharmony_ci	}
1238c72fcc34Sopenharmony_ci
1239c72fcc34Sopenharmony_ci	dmic->dmic_dai_index = dai_index;
1240c72fcc34Sopenharmony_ci	dmic->dmic_prm[dai_index].driver_version = driver_version;
1241c72fcc34Sopenharmony_ci	dmic->dmic_prm[dai_index].io_clk = io_clk;
1242c72fcc34Sopenharmony_ci	dmic->dmic_prm[dai_index].num_pdm_active = num_pdm_active;
1243c72fcc34Sopenharmony_ci	dmic->dmic_prm[dai_index].fifo_bits = fifo_word_length;
1244c72fcc34Sopenharmony_ci	dmic->dmic_prm[dai_index].pdmclk_min = clk_min;
1245c72fcc34Sopenharmony_ci	dmic->dmic_prm[dai_index].pdmclk_max = clk_max;
1246c72fcc34Sopenharmony_ci	dmic->dmic_prm[dai_index].duty_min = duty_min;
1247c72fcc34Sopenharmony_ci	dmic->dmic_prm[dai_index].duty_max = duty_max;
1248c72fcc34Sopenharmony_ci	dmic->dmic_prm[dai_index].fifo_fs = sample_rate;
1249c72fcc34Sopenharmony_ci	dmic->dmic_prm[dai_index].unmute_ramp_time = unmute_ramp_time;
1250c72fcc34Sopenharmony_ci
1251c72fcc34Sopenharmony_ci	return 0;
1252c72fcc34Sopenharmony_ci}
1253c72fcc34Sopenharmony_ci
1254c72fcc34Sopenharmony_ciint dmic_set_pdm_params(struct intel_nhlt_params *nhlt, int pdm_index, int enable_a,
1255c72fcc34Sopenharmony_ci			int enable_b, int polarity_a, int polarity_b, int clk_edge, int skew)
1256c72fcc34Sopenharmony_ci{
1257c72fcc34Sopenharmony_ci	struct intel_dmic_params *dmic = (struct intel_dmic_params *)nhlt->dmic_params;
1258c72fcc34Sopenharmony_ci	int di;
1259c72fcc34Sopenharmony_ci
1260c72fcc34Sopenharmony_ci	if (!dmic)
1261c72fcc34Sopenharmony_ci		return -EINVAL;
1262c72fcc34Sopenharmony_ci
1263c72fcc34Sopenharmony_ci	if (pdm_index >= DMIC_HW_CONTROLLERS) {
1264c72fcc34Sopenharmony_ci		fprintf(stderr, "set_pdm_data illegal pdm_index\n");
1265c72fcc34Sopenharmony_ci		return -EINVAL;
1266c72fcc34Sopenharmony_ci	}
1267c72fcc34Sopenharmony_ci
1268c72fcc34Sopenharmony_ci	di = dmic->dmic_dai_index;
1269c72fcc34Sopenharmony_ci
1270c72fcc34Sopenharmony_ci	dmic->dmic_prm[di].pdm[pdm_index].enable_mic_a = enable_a;
1271c72fcc34Sopenharmony_ci	dmic->dmic_prm[di].pdm[pdm_index].enable_mic_b = enable_b;
1272c72fcc34Sopenharmony_ci	dmic->dmic_prm[di].pdm[pdm_index].polarity_mic_a = polarity_a;
1273c72fcc34Sopenharmony_ci	dmic->dmic_prm[di].pdm[pdm_index].polarity_mic_b = polarity_b;
1274c72fcc34Sopenharmony_ci	dmic->dmic_prm[di].pdm[pdm_index].clk_edge = clk_edge;
1275c72fcc34Sopenharmony_ci	dmic->dmic_prm[di].pdm[pdm_index].skew = skew;
1276c72fcc34Sopenharmony_ci
1277c72fcc34Sopenharmony_ci	return 0;
1278c72fcc34Sopenharmony_ci}
1279c72fcc34Sopenharmony_ci
1280c72fcc34Sopenharmony_ciint dmic_set_ext_params(struct intel_nhlt_params *nhlt, uint32_t snr, uint32_t sensitivity)
1281c72fcc34Sopenharmony_ci{
1282c72fcc34Sopenharmony_ci	struct intel_dmic_params *dmic = (struct intel_dmic_params *)nhlt->dmic_params;
1283c72fcc34Sopenharmony_ci
1284c72fcc34Sopenharmony_ci	if (!dmic)
1285c72fcc34Sopenharmony_ci		return -EINVAL;
1286c72fcc34Sopenharmony_ci
1287c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.extension = 1;
1288c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.snr = snr;
1289c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.sensitivity = sensitivity;
1290c72fcc34Sopenharmony_ci
1291c72fcc34Sopenharmony_ci	return 0;
1292c72fcc34Sopenharmony_ci}
1293c72fcc34Sopenharmony_ci
1294c72fcc34Sopenharmony_ciint dmic_set_mic_params(struct intel_nhlt_params *nhlt, int index,
1295c72fcc34Sopenharmony_ci			uint8_t type, uint8_t panel, uint32_t speaker_position_distance,
1296c72fcc34Sopenharmony_ci			uint32_t horizontal_offset, uint32_t vertical_offset,
1297c72fcc34Sopenharmony_ci			uint8_t frequency_low_band, uint8_t frequency_high_band,
1298c72fcc34Sopenharmony_ci			uint16_t direction_angle, uint16_t elevation_angle,
1299c72fcc34Sopenharmony_ci			uint16_t vertical_angle_begin, uint16_t vertical_angle_end,
1300c72fcc34Sopenharmony_ci			uint16_t horizontal_angle_begin, uint16_t horizontal_angle_end)
1301c72fcc34Sopenharmony_ci{
1302c72fcc34Sopenharmony_ci	struct intel_dmic_params *dmic = (struct intel_dmic_params *)nhlt->dmic_params;
1303c72fcc34Sopenharmony_ci
1304c72fcc34Sopenharmony_ci	if (!dmic)
1305c72fcc34Sopenharmony_ci		return -EINVAL;
1306c72fcc34Sopenharmony_ci
1307c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].type = type;
1308c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].panel = panel;
1309c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].speaker_position_distance = speaker_position_distance;
1310c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].horizontal_offset = horizontal_offset;
1311c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].vertical_offset = vertical_offset;
1312c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].frequency_low_band = frequency_low_band;
1313c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].frequency_high_band = frequency_high_band;
1314c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].direction_angle = direction_angle;
1315c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].elevation_angle = elevation_angle;
1316c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].vertical_angle_begin = vertical_angle_begin;
1317c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].vertical_angle_end = vertical_angle_end;
1318c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].horizontal_angle_begin = horizontal_angle_begin;
1319c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.vendor[index].horizontal_angle_end = horizontal_angle_end;
1320c72fcc34Sopenharmony_ci
1321c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.num_mics++;
1322c72fcc34Sopenharmony_ci
1323c72fcc34Sopenharmony_ci	return 0;
1324c72fcc34Sopenharmony_ci}
1325c72fcc34Sopenharmony_ci
1326c72fcc34Sopenharmony_ci/* init dmic parameters, should be called before parsing dais */
1327c72fcc34Sopenharmony_ciint dmic_init_params(struct intel_nhlt_params *nhlt)
1328c72fcc34Sopenharmony_ci{
1329c72fcc34Sopenharmony_ci	struct intel_dmic_params *dmic;
1330c72fcc34Sopenharmony_ci	int i;
1331c72fcc34Sopenharmony_ci
1332c72fcc34Sopenharmony_ci	dmic = calloc(1, sizeof(struct intel_dmic_params));
1333c72fcc34Sopenharmony_ci	if (!dmic)
1334c72fcc34Sopenharmony_ci		return -ENOMEM;
1335c72fcc34Sopenharmony_ci
1336c72fcc34Sopenharmony_ci	nhlt->dmic_params = dmic;
1337c72fcc34Sopenharmony_ci	/* set always to 1, some fw variants use this for choosing memory type */
1338c72fcc34Sopenharmony_ci	dmic->dmic_blob.gateway_attributes = 1;
1339c72fcc34Sopenharmony_ci	/* delay in ms to unmute mics after clock is started */
1340c72fcc34Sopenharmony_ci	dmic->dmic_blob.clock_on_delay = 16;
1341c72fcc34Sopenharmony_ci
1342c72fcc34Sopenharmony_ci	for (i = 0; i < DMIC_TS_GROUP_SIZE; i++)
1343c72fcc34Sopenharmony_ci		dmic->dmic_blob.ts_group[i] = 0xFFFFFFFF; /* not enabled */
1344c72fcc34Sopenharmony_ci
1345c72fcc34Sopenharmony_ci	dmic->dmic_count = 0;
1346c72fcc34Sopenharmony_ci
1347c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.num_mics = 0;
1348c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.extension = 0;
1349c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.array_type = 0;
1350c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.snr = 0;
1351c72fcc34Sopenharmony_ci	dmic->dmic_mic_config.sensitivity = 0;
1352c72fcc34Sopenharmony_ci
1353c72fcc34Sopenharmony_ci	return 0;
1354c72fcc34Sopenharmony_ci}
1355