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