1% success = dmic_init(prm) 2% 3% Create PDM microphones interface configuration 4 5% SPDX-License-Identifier: BSD-3-Clause 6% 7% Copyright (c) 2019, Intel Corporation. All rights reserved. 8% 9% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> 10 11function success = dmic_init(prm) 12 13hw.controllers = 4; 14hw.bits_cic = 26; 15hw.bits_fir_coef = 20; 16hw.bits_fir_gain = 20; 17hw.bits_fir_input = 22; 18hw.bits_fir_output = 24; 19hw.bits_fir_internal = 26; 20hw.bits_gain_output = 22; 21hw.fir_length_max = 250; 22hw.cic_shift_right_range = [-8 4]; 23hw.fir_shift_right_range = [0 8]; 24hw.fir_max_length = 250; 25hw.version = 1; 26hw.number_of_pdm_controllers = 2; 27hw.ioclk = 19.2e6; 28spec.scale = 0.95; 29spec.linear_phase = 1; 30spec.rp = 0.1; 31spec.cp = 0.4375; 32spec.cs = 0.5100; 33spec.rs = 95; 34success = 0; 35 36if (prm.fifo_a_fs == 0) && (prm.fifo_b_fs == 0) 37 fprintf(1,'Error: At least one FIFO needs non-zero Fs!\n'); 38 return; 39end 40 41%% Match modes 42[a_clkdiv, a_mcic, a_mfir] = find_modes(prm, hw, prm.fifo_a_fs); 43[b_clkdiv, b_mcic, b_mfir] = find_modes(prm, hw, prm.fifo_b_fs); 44[common_clkdiv_list,common_mcic_list,a_mfir_list,b_mfir_list] = ... 45 match_modes(a_clkdiv, a_mcic, a_mfir, b_clkdiv, b_mcic, b_mfir); 46 47if isempty(common_clkdiv_list) 48 error('No compatible settings were found!\n'); 49end 50 51%% Set basic configuration data 52cfg = get_cfg(prm, hw); 53 54%% Done, print 1st modes combination 55fprintf('Selected fifo_a_fs=%d, fifo_b_fs=%d: ', prm.fifo_a_fs, prm.fifo_b_fs); 56cfg = select_mode(common_mcic_list, a_mfir_list, b_mfir_list, common_clkdiv_list, cfg); 57cfg = get_cic_config(prm, cfg, hw); 58cfg = get_fir_config(prm, cfg, hw, spec); 59 60end 61 62%% Functions 63 64%% Get FIR filters 65function cfg = get_fir_config(prm, cfg, hw, spec) 66 67if prm.fifo_a_fs > 0 68 [coef, shift] = get_fir(cfg.mfir_a, prm, cfg, hw, spec); 69 70 [cfg.fir_coef_a, cfg.fir_shift_a, cfg.fir_length_a] = ... 71 scale_fir_coef(coef, shift, spec.scale, cfg.remain_gain_to_fir, hw.bits_fir_coef); 72 cfg.fir_gain_a = 1; 73else 74 cfg.fir_gain_a = 0; 75 cfg.fir_coef_a = 0; 76 cfg.fir_shift_a = 0; 77 cfg.fir_length_a = 1; 78end 79 80if prm.fifo_b_fs > 0 81 [coef, shift] = get_fir(cfg.mfir_b, prm, cfg, hw, spec); 82 83 [cfg.fir_coef_b, cfg.fir_shift_b, cfg.fir_length_b] = ... 84 scale_fir_coef(coef, shift, spec.scale, cfg.remain_gain_to_fir, hw.bits_fir_coef); 85 cfg.fir_gain_b = 1; 86else 87 cfg.fir_gain_b = 0; 88 cfg.fir_coef_b = 0; 89 cfg.fir_shift_b = 0; 90 cfg.fir_length_b = 1; 91end 92 93end 94 95function [coefq, shiftq, len] = scale_fir_coef(coef32, shift32, hw_sens, add_gain, bits) 96 97out_scale = 2^(bits-1); 98q31_scale = 2^31; 99coef = coef32/q31_scale * 2^(-shift32) * hw_sens * add_gain; 100max_abs_coef = max(abs(coef)); 101scale = 0.9999/max_abs_coef; 102shiftq = floor(log(scale)/log(2)); 103c = 2^shiftq; 104coefq = round(out_scale * coef * c); 105len = length(coefq); 106 107end 108 109% This function becomes table lookup in C 110function [coef32, shift] = get_fir(mfir, prm, cfg, hw, spec) 111 112fs_fir = cfg.mic_clk/cfg.mcic; 113fs = fs_fir/mfir; 114passhz = spec.cp * fs; 115stophz = spec.cs * fs; 116max_length = min(hw.fir_max_length, floor(hw.ioclk/fs/2-5)); 117 118[ coef, shift, bw, sb, rs, got_pb, got_sb, passed] = ... 119 dmic_fir(spec.rp, spec.rs, passhz, stophz, cfg.mic_clk, fs_fir, max_length, spec.linear_phase); 120 121if passed == 0 122 fprintf(1, 'Warning: Filter specification was reduced.\n'); 123 if (got_pb > 1) || (got_sb > -60) 124 error('The design is erroneous.'); 125 end 126end 127 128coef32 = round(2^31 * coef); 129fir.length = length(coef32); 130fir.coef = coef32; 131fir.shift = shift; 132cp = bw/fs; 133cs = sb/fs; 134fir.cp = cp; 135fir.cs = cs; 136fir.rp = spec.rp; 137fir.rs = rs; 138fir.m = mfir; 139dmic_fir_export(fir, 'include'); 140 141end 142 143%% Select one mode from possible combinations 144function cfg = select_mode(common_mcic_list, a_mfir_list, b_mfir_list, common_clkdiv_list, cfg) 145 146cfg.mcic = 0; 147cfg.mfir_a = 0; 148cfg.mfir_b = 0; 149cfg.clk_div = 0; 150 151% Order of preference for FIR decimation factors, prime numbers 152% even if low value, are less preferable due to incompatibility 153% with other FIR decimation factor. 154mpref = [2 4 6 8 3 5 7 9 10 11 12 13 14 15]; 155 156% Find common mode with lowest FIR decimation ratio. If there are many 157% select one with lowest mic clock rate. Lowest rates or highest dividers 158% are in the end of list. 159if length(common_mcic_list) > 0 160 for mtry = mpref 161 idx = find(a_mfir_list == mtry); 162 if ~isempty(idx) 163 n = idx(end); 164 break; 165 end 166 end 167 cfg.mcic = common_mcic_list(n); 168 cfg.clk_div = common_clkdiv_list(n); 169 if a_mfir_list(1) > 0 170 cfg.mfir_a = a_mfir_list(n); 171 end 172 if b_mfir_list(1) > 0 173 cfg.mfir_b = b_mfir_list(n); 174 end 175 fprintf(1, 'clk_div=%d, cic=%d, fir_a=%d, fir_b=%d\n', ... 176 cfg.clk_div, cfg.mcic, cfg.mfir_a, cfg.mfir_b); 177end 178 179end 180 181%% Compute CIC filter settings 182function cfg = get_cic_config(prm, cfg, hw) 183 184cfg.mic_clk = hw.ioclk/cfg.clk_div; 185g_cic = cfg.mcic^5; 186bitsneeded = floor(log(g_cic)/log(2)+1)+1; 187cfg.cic_shift = bitsneeded - hw.bits_fir_input; 188 189if hw.bits_cic < bitsneeded 190 fprintf(1,'Error: Needed CIC word length is exceeded %d\n', bitsneeded); 191end 192 193if cfg.cic_shift < hw.cic_shift_right_range(1); 194 fprintf(1,'Warning: Limited CIC shift right from %d', cfg.cic_shift); 195 cfg.cic_shift = hw.cic_shift_right_range(1); 196end 197 198if cfg.cic_shift > hw.cic_shift_right_range(2); 199 fprintf(1,'Error: Limited CIC shift right from %d', cfg.cic_shift); 200 cfg.cic_shift = hw.cic_shift_right_range(2); 201end 202 203% Compute how much gain is left for FIR from scaling to full scale 204cfg.remain_gain_to_fir = 2^(hw.bits_fir_input-1)/(g_cic/2^cfg.cic_shift); 205 206end 207 208%% Find modes those are possible and exist in setup database 209function [clkdiv, mcic, mfir] = find_modes(prm, hw, pcm_fs) 210 211if pcm_fs < 1 212 clkdiv = 0; 213 mcic = 0; 214 mfir = 0; 215 return; 216end 217osr_min = 50; 218if pcm_fs > 48e3 219 osr_min = floor(3.0e6 / pcm_fs); 220end 221mcic_min = 5; 222mcic_max = 31; % 8 bits reg but CIC gain and 26 bits implementation limits this 223mfir_min = 2; 224mfir_max = 15; 225clkdiv_min = ceil(hw.ioclk/prm.pdmclk_max); 226clkdiv_max = floor(hw.ioclk/prm.pdmclk_min); 227n = 1; 228clkdiv = []; 229mcic = []; 230mfir = []; 231% Highest to lowest PDM clock, prefer best quality in range 232for clkdiv_test = clkdiv_min:clkdiv_max 233 if clkdiv_test > 4 % Limitation in cAVS1.5-2.0 234 c1 = floor(clkdiv_test/2); 235 c2 = clkdiv_test - c1; 236 du_min = 100*c1/clkdiv_test; 237 du_max = 100*c2/clkdiv_test; 238 pdmclk = hw.ioclk/clkdiv_test; 239 osr = round(pdmclk/pcm_fs); 240 % Lowest FIR decimation to highest, prefer low FIR 241 % decimation ratios 242 for mfir_test = mfir_min:osr 243 mcic_test = floor(osr/mfir_test); 244 if (abs(pcm_fs*mfir_test*mcic_test -pdmclk) < 1) ... 245 && (osr >= osr_min) ... 246 && (mcic_test >= mcic_min) ... 247 && (mcic_test <= mcic_max) ... 248 && (mfir_test <= mfir_max) ... 249 && (du_min >= prm.duty_min) ... 250 && (du_max <= prm.duty_max) 251 sfir = sprintf('FIR %d x %d x %dHz', ... 252 mcic_test, mfir_test, round(pcm_fs)); 253 %fprintf('Found: %s\n',sfir); 254 clkdiv(n) = clkdiv_test; 255 mcic(n) = mcic_test; 256 mfir(n) = mfir_test; 257 n=n+1; 258 end 259 end 260 end 261end 262end 263 264 265%% Match found modes for common clkdiv and mcic, a DMIC hardware constraint 266function [common_clkdiv_list,common_mcic_list,a_mfir_list,b_mfir_list] = ... 267 match_modes(a_clkdiv, a_mcic, a_mfir, b_clkdiv, b_mcic, b_mfir) 268 269if b_clkdiv == 0 270 common_clkdiv_list = a_clkdiv; 271 common_mcic_list = a_mcic; 272 a_mfir_list = a_mfir; 273 b_mfir_list = 0; 274 return; 275end 276common_clkdiv_list = []; 277common_mcic_list = []; 278a_mfir_list = []; 279b_mfir_list = []; 280n_list = 1; 281for n=1:length(a_clkdiv) 282 idx = find(b_clkdiv == a_clkdiv(n)); 283 for m=1:length(idx) 284 if b_mcic(idx(m)) == a_mcic(n) 285 common_clkdiv = a_clkdiv(n); 286 common_mcic = a_mcic(n); 287 common_clkdiv_list(n_list) = common_clkdiv; 288 common_mcic_list(n_list) = common_mcic; 289 a_mfir_list(n_list) = a_mfir(n); 290 b_mfir_list(n_list) = b_mfir(idx(m)); 291 fprintf('Option %d: div=%d, mcic=%d, mfira=%d, mfirb=%d\n', ... 292 n_list, common_clkdiv, common_mcic, ... 293 a_mfir_list(n_list), b_mfir_list(n_list)); 294 n_list = n_list+1; 295 end 296 end 297end 298end 299 300%% Misc blob details needed 301function cfg = get_cfg(prm, hw) 302 303% if FIFO A or B is disabled, append a dummy blob to keep modes matching 304% code happy with identical A and B request 305if (prm.fifo_a_fs == 0) && (prm.fifo_b_fs == 0) 306 fprintf('Error: FIFO A or B need to be assigned a nonzero samplerate\n'); 307 return; 308end 309 310cfg.hw_version = hw.version; 311 312cfg.fifo_a_fs = prm.fifo_a_fs; 313cfg.fifo_b_fs = prm.fifo_b_fs; 314 315cfg.pdm01_provided = (prm.pdm(1).enable_mic_a | prm.pdm(1).enable_mic_b) ... 316 + (prm.pdm(2).enable_mic_a | prm.pdm(2).enable_mic_b)*2; 317cfg.ch01_provided = (prm.fifo_a_fs > 0) + (prm.fifo_b_fs > 0)*2; 318 319if prm.fifo_a_fs > 0 320 cfg.a_nchannels = prm.pdm(1).enable_mic_a + prm.pdm(1).enable_mic_b ... 321 + prm.pdm(2).enable_mic_a + prm.pdm(2).enable_mic_b; 322else 323 cfg.a_nchannels = 0; 324end 325if prm.fifo_b_fs > 0 326 cfg.b_nchannels = prm.pdm(1).enable_mic_a + prm.pdm(1).enable_mic_b ... 327 + prm.pdm(2).enable_mic_a + prm.pdm(2).enable_mic_b; 328else 329 cfg.b_nchannels = 0; 330end 331 332end 333