diff --git a/src/drivers/intel/CMakeLists.txt b/src/drivers/intel/CMakeLists.txt index aed842ce4b7f..265369dbed72 100644 --- a/src/drivers/intel/CMakeLists.txt +++ b/src/drivers/intel/CMakeLists.txt @@ -22,5 +22,5 @@ if(CONFIG_INTEL_ALH) endif() if(CONFIG_INTEL_DMIC) - add_local_sources(sof dmic.c) + add_subdirectory(dmic) endif() diff --git a/src/drivers/intel/dmic/CMakeLists.txt b/src/drivers/intel/dmic/CMakeLists.txt new file mode 100644 index 000000000000..14b33ab5d6b7 --- /dev/null +++ b/src/drivers/intel/dmic/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources(sof dmic.c) diff --git a/src/drivers/intel/dmic.c b/src/drivers/intel/dmic/dmic.c similarity index 86% rename from src/drivers/intel/dmic.c rename to src/drivers/intel/dmic/dmic.c index fff265cf9ac0..e30034ad4161 100644 --- a/src/drivers/intel/dmic.c +++ b/src/drivers/intel/dmic/dmic.c @@ -134,9 +134,8 @@ static const uint32_t coef_base_a[4] = {PDM0_COEFFICIENT_A, PDM1_COEFFICIENT_A, static const uint32_t coef_base_b[4] = {PDM0_COEFFICIENT_B, PDM1_COEFFICIENT_B, PDM2_COEFFICIENT_B, PDM3_COEFFICIENT_B}; -/* Global configuration request for DMIC, need to use uncached address to access them */ -static SHARED_DATA struct sof_ipc_dai_dmic_params *dmic_prm[DMIC_HW_FIFOS]; -static SHARED_DATA int dmic_active_fifos; +/* Global configuration request and state for DMIC */ +static SHARED_DATA struct dmic_global_shared dmic_global; /* this ramps volume changes over time */ static enum task_state dmic_work(void *data) @@ -160,8 +159,7 @@ static enum task_state dmic_work(void *data) * Gain is Q2.30 and gain modifier is Q12.20. */ dmic->startcount++; - dmic->gain = q_multsr_sat_32x32(dmic->gain, dmic->gain_coef, - Q_SHIFT_GAIN_X_GAIN_COEF); + dmic->gain = q_multsr_sat_32x32(dmic->gain, dmic->gain_coef, Q_SHIFT_GAIN_X_GAIN_COEF); /* Gain is stored as Q2.30, while HW register is Q1.19 so shift * the value right by 11. @@ -225,7 +223,7 @@ static enum task_state dmic_work(void *data) static void find_modes(struct dai *dai, struct decim_modes *modes, uint32_t fs, int di) { - struct sof_ipc_dai_dmic_params **uncached_dmic_prm = cache_to_uncache(&dmic_prm[0]); + struct dmic_pdata *dmic = dai_get_drvdata(dai); int clkdiv_min; int clkdiv_max; int clkdiv; @@ -257,37 +255,37 @@ static void find_modes(struct dai *dai, osr_min = DMIC_HIGH_RATE_OSR_MIN; /* Check for sane pdm clock, min 100 kHz, max ioclk/2 */ - if (uncached_dmic_prm[di]->pdmclk_max < DMIC_HW_PDM_CLK_MIN || - uncached_dmic_prm[di]->pdmclk_max > DMIC_HW_IOCLK / 2) { + if (dmic->global->prm[di].pdmclk_max < DMIC_HW_PDM_CLK_MIN || + dmic->global->prm[di].pdmclk_max > DMIC_HW_IOCLK / 2) { dai_err(dai, "find_modes(): pdm clock max not in range"); return; } - if (uncached_dmic_prm[di]->pdmclk_min < DMIC_HW_PDM_CLK_MIN || - uncached_dmic_prm[di]->pdmclk_min > uncached_dmic_prm[di]->pdmclk_max) { + if (dmic->global->prm[di].pdmclk_min < DMIC_HW_PDM_CLK_MIN || + dmic->global->prm[di].pdmclk_min > dmic->global->prm[di].pdmclk_max) { dai_err(dai, "find_modes(): pdm clock min not in range"); return; } /* Check for sane duty cycle */ - if (uncached_dmic_prm[di]->duty_min > uncached_dmic_prm[di]->duty_max) { + if (dmic->global->prm[di].duty_min > dmic->global->prm[di].duty_max) { dai_err(dai, "find_modes(): duty cycle min > max"); return; } - if (uncached_dmic_prm[di]->duty_min < DMIC_HW_DUTY_MIN || - uncached_dmic_prm[di]->duty_min > DMIC_HW_DUTY_MAX) { + if (dmic->global->prm[di].duty_min < DMIC_HW_DUTY_MIN || + dmic->global->prm[di].duty_min > DMIC_HW_DUTY_MAX) { dai_err(dai, "find_modes(): pdm clock min not in range"); return; } - if (uncached_dmic_prm[di]->duty_max < DMIC_HW_DUTY_MIN || - uncached_dmic_prm[di]->duty_max > DMIC_HW_DUTY_MAX) { + if (dmic->global->prm[di].duty_max < DMIC_HW_DUTY_MIN || + dmic->global->prm[di].duty_max > DMIC_HW_DUTY_MAX) { dai_err(dai, "find_modes(): pdm clock max not in range"); return; } /* Min and max clock dividers */ - clkdiv_min = ceil_divide(DMIC_HW_IOCLK, uncached_dmic_prm[di]->pdmclk_max); + clkdiv_min = ceil_divide(DMIC_HW_IOCLK, dmic->global->prm[di].pdmclk_max); clkdiv_min = MAX(clkdiv_min, DMIC_HW_CIC_DECIM_MIN); - clkdiv_max = DMIC_HW_IOCLK / uncached_dmic_prm[di]->pdmclk_min; + clkdiv_max = DMIC_HW_IOCLK / dmic->global->prm[di].pdmclk_min; /* Loop possible clock dividers and check based on resulting * oversampling ratio that CIC and FIR decimation ratios are @@ -310,8 +308,8 @@ static void find_modes(struct dai *dai, * not exceed microphone specification. If exceed proceed to * next clkdiv. */ - if (osr < osr_min || du_min < uncached_dmic_prm[di]->duty_min || - du_max > uncached_dmic_prm[di]->duty_max) + if (osr < osr_min || du_min < dmic->global->prm[di].duty_min || + du_max > dmic->global->prm[di].duty_max) continue; /* Loop FIR decimation factors candidates. If the @@ -672,9 +670,8 @@ static int select_mode(struct dai *dai, * value to use. */ -static inline void ipm_helper1(int *ipm, int di) +static inline void ipm_helper1(struct dmic_pdata *dmic, int *ipm, int di) { - struct sof_ipc_dai_dmic_params **uncached_dmic_prm = cache_to_uncache(&dmic_prm[0]); int pdm[DMIC_HW_CONTROLLERS]; int i; @@ -683,8 +680,8 @@ static inline void ipm_helper1(int *ipm, int di) * this DAI. */ for (i = 0; i < DMIC_HW_CONTROLLERS; i++) { - if (uncached_dmic_prm[di]->pdm[i].enable_mic_a || - uncached_dmic_prm[di]->pdm[i].enable_mic_b) + if (dmic->global->prm[di].pdm[i].enable_mic_a || + dmic->global->prm[di].pdm[i].enable_mic_b) pdm[i] = 1; else pdm[i] = 0; @@ -702,9 +699,8 @@ static inline void ipm_helper1(int *ipm, int di) #if DMIC_HW_VERSION >= 2 -static inline void ipm_helper2(int source[], int *ipm, int di) +static inline void ipm_helper2(struct dmic_pdata *dmic, int source[], int *ipm, int di) { - struct sof_ipc_dai_dmic_params **uncached_dmic_prm = cache_to_uncache(&dmic_prm[0]); int pdm[DMIC_HW_CONTROLLERS]; int i; int n = 0; @@ -718,8 +714,8 @@ static inline void ipm_helper2(int source[], int *ipm, int di) * pdm controllers to be used for IPM configuration. */ for (i = 0; i < DMIC_HW_CONTROLLERS; i++) { - if (uncached_dmic_prm[di]->pdm[i].enable_mic_a || - uncached_dmic_prm[di]->pdm[i].enable_mic_b) { + if (dmic->global->prm[di].pdm[i].enable_mic_a || + dmic->global->prm[di].pdm[i].enable_mic_b) { pdm[i] = 1; source[n] = i; n++; @@ -740,9 +736,8 @@ static inline void ipm_helper2(int source[], int *ipm, int di) * or mono right (B) mode. Mono right mode is setup as channel * swapped mono left. */ -static int stereo_helper(int stereo[], int swap[]) +static int stereo_helper(struct dmic_pdata *dmic, int stereo[], int swap[]) { - struct sof_ipc_dai_dmic_params **uncached_dmic_prm = cache_to_uncache(&dmic_prm[0]); int cnt; int i; int swap_check; @@ -750,12 +745,12 @@ static int stereo_helper(int stereo[], int swap[]) for (i = 0; i < DMIC_HW_CONTROLLERS; i++) { cnt = 0; - if (uncached_dmic_prm[0]->pdm[i].enable_mic_a || - uncached_dmic_prm[1]->pdm[i].enable_mic_a) + if (dmic->global->prm[0].pdm[i].enable_mic_a || + dmic->global->prm[1].pdm[i].enable_mic_a) cnt++; - if (uncached_dmic_prm[0]->pdm[i].enable_mic_b || - uncached_dmic_prm[1]->pdm[i].enable_mic_b) + if (dmic->global->prm[0].pdm[i].enable_mic_b || + dmic->global->prm[1].pdm[i].enable_mic_b) cnt++; /* Set stereo mode if both mic A anc B are enabled. */ @@ -763,12 +758,12 @@ static int stereo_helper(int stereo[], int swap[]) stereo[i] = cnt; /* Swap channels if only mic B is used for mono processing. */ - swap[i] = (uncached_dmic_prm[0]->pdm[i].enable_mic_b || - uncached_dmic_prm[1]->pdm[i].enable_mic_b) && !cnt; + swap[i] = (dmic->global->prm[0].pdm[i].enable_mic_b || + dmic->global->prm[1].pdm[i].enable_mic_b) && !cnt; /* Check that swap does not conflict with other DAI request */ - swap_check = uncached_dmic_prm[1]->pdm[i].enable_mic_a || - uncached_dmic_prm[0]->pdm[i].enable_mic_a; + swap_check = dmic->global->prm[1].pdm[i].enable_mic_a || + dmic->global->prm[0].pdm[i].enable_mic_a; if (swap_check && swap[i]) ret = -EINVAL; @@ -779,8 +774,7 @@ static int stereo_helper(int stereo[], int swap[]) static int configure_registers(struct dai *dai, struct dmic_configuration *cfg) { - struct sof_ipc_dai_dmic_params **prm_t = cache_to_uncache(&dmic_prm[0]); - int uncached_dmic_active_fifos = *cache_to_uncache(&dmic_active_fifos); + struct dmic_pdata *dmic = dai_get_drvdata(dai); int stereo[DMIC_HW_CONTROLLERS]; int swap[DMIC_HW_CONTROLLERS]; uint32_t val; @@ -800,8 +794,9 @@ static int configure_registers(struct dai *dai, int i; int j; int ret; + int pol_a; + int pol_b; int di = dai->index; - struct dmic_pdata *pdata = dai_get_drvdata(dai); int dccomp = 1; int array_a = 0; int array_b = 0; @@ -818,7 +813,7 @@ static int configure_registers(struct dai *dai, #endif /* pdata is set by dmic_probe(), error if it has not been set */ - if (!pdata) { + if (!dmic) { dai_err(dai, "configure_registers(): pdata not set"); return -EINVAL; } @@ -826,17 +821,17 @@ static int configure_registers(struct dai *dai, dai_info(dai, "configuring registers"); /* OUTCONTROL0 and OUTCONTROL1 */ - of0 = (prm_t[0]->fifo_bits == 32) ? 2 : 0; + of0 = (dmic->global->prm[0].fifo_bits == 32) ? 2 : 0; #if DMIC_HW_FIFOS > 1 - of1 = (prm_t[1]->fifo_bits == 32) ? 2 : 0; + of1 = (dmic->global->prm[1].fifo_bits == 32) ? 2 : 0; #else of1 = 0; #endif #if DMIC_HW_VERSION == 1 || (DMIC_HW_VERSION == 2 && DMIC_HW_CONTROLLERS <= 2) if (di == 0) { - ipm_helper1(&ipm, 0); + ipm_helper1(dmic, &ipm, 0); val = OUTCONTROL0_TIE(0) | OUTCONTROL0_SIP(0) | OUTCONTROL0_FINIT(1) | @@ -848,7 +843,7 @@ static int configure_registers(struct dai *dai, dai_write(dai, OUTCONTROL0, val); dai_dbg(dai, "configure_registers(), OUTCONTROL0 = %08x", val); } else { - ipm_helper1(&ipm, 1); + ipm_helper1(dmic, &ipm, 1); val = OUTCONTROL1_TIE(0) | OUTCONTROL1_SIP(0) | OUTCONTROL1_FINIT(1) | @@ -864,7 +859,7 @@ static int configure_registers(struct dai *dai, #if DMIC_HW_VERSION == 3 || (DMIC_HW_VERSION == 2 && DMIC_HW_CONTROLLERS > 2) if (di == 0) { - ipm_helper2(source, &ipm, 0); + ipm_helper2(dmic, source, &ipm, 0); val = OUTCONTROL0_TIE(0) | OUTCONTROL0_SIP(0) | OUTCONTROL0_FINIT(1) | @@ -880,7 +875,7 @@ static int configure_registers(struct dai *dai, dai_write(dai, OUTCONTROL0, val); dai_dbg(dai, "configure_registers(), OUTCONTROL0 = %08x", val); } else { - ipm_helper2(source, &ipm, 1); + ipm_helper2(dmic, source, &ipm, 1); val = OUTCONTROL1_TIE(0) | OUTCONTROL1_SIP(0) | OUTCONTROL1_FINIT(1) | @@ -902,25 +897,30 @@ static int configure_registers(struct dai *dai, * for starting correct parts of the HW. */ for (i = 0; i < DMIC_HW_CONTROLLERS; i++) { - pdata->enable[i] = (prm_t[di]->pdm[i].enable_mic_b << 1) | - prm_t[di]->pdm[i].enable_mic_a; + dmic->enable[i] = (dmic->global->prm[di].pdm[i].enable_mic_b << 1) | + dmic->global->prm[di].pdm[i].enable_mic_a; } - ret = stereo_helper(stereo, swap); + ret = stereo_helper(dmic, stereo, swap); if (ret < 0) { dai_err(dai, "configure_registers(): enable conflict"); return ret; } + /* Note about accessing dmic_active_fifos_mask: the dai spinlock has been set in + * the calling function dmic_set_config(). + */ for (i = 0; i < DMIC_HW_CONTROLLERS; i++) { - if (uncached_dmic_active_fifos == 0) { + if (dmic->global->active_fifos_mask == 0) { /* CIC */ + pol_a = dmic->global->prm[di].pdm[i].polarity_mic_a; + pol_b = dmic->global->prm[di].pdm[i].polarity_mic_b; val = CIC_CONTROL_SOFT_RESET(soft_reset) | CIC_CONTROL_CIC_START_B(0) | CIC_CONTROL_CIC_START_A(0) | - CIC_CONTROL_MIC_B_POLARITY(prm_t[di]->pdm[i].polarity_mic_a) | - CIC_CONTROL_MIC_A_POLARITY(prm_t[di]->pdm[i].polarity_mic_b) | + CIC_CONTROL_MIC_B_POLARITY(pol_b) | + CIC_CONTROL_MIC_A_POLARITY(pol_a) | CIC_CONTROL_MIC_MUTE(cic_mute) | CIC_CONTROL_STEREO_MODE(stereo[i]); dai_write(dai, base[i] + CIC_CONTROL, val); @@ -935,12 +935,12 @@ static int configure_registers(struct dai *dai, * since the mono decimation is done with only left channel * processing active. */ - edge = prm_t[di]->pdm[i].clk_edge; + edge = dmic->global->prm[di].pdm[i].clk_edge; if (swap[i]) edge = !edge; val = MIC_CONTROL_PDM_CLKDIV(cfg->clkdiv - 2) | - MIC_CONTROL_PDM_SKEW(prm_t[di]->pdm[i].skew) | + MIC_CONTROL_PDM_SKEW(dmic->global->prm[di].pdm[i].skew) | MIC_CONTROL_CLK_EDGE(edge) | MIC_CONTROL_PDM_EN_B(0) | MIC_CONTROL_PDM_EN_A(0); @@ -1066,18 +1066,17 @@ static int configure_registers(struct dai *dai, static int dmic_get_hw_params(struct dai *dai, struct sof_ipc_stream_params *params, int dir) { - struct sof_ipc_dai_dmic_params **uncached_dmic_prm = cache_to_uncache(&dmic_prm[0]); + struct dmic_pdata *dmic = dai_get_drvdata(dai); int di = dai->index; - if (!uncached_dmic_prm[di]) { - dai_err(dai, "dmic_get_hw_params(): dai %d not configured! &dmic_prm[di] 0x%p", - di, &uncached_dmic_prm[di]); + if (!dmic) { + dai_err(dai, "dmic_get_hw_params(): dai %d not configured!", di); return -EINVAL; } - params->rate = uncached_dmic_prm[di]->fifo_fs; + params->rate = dmic->global->prm[di].fifo_fs; params->buffer_fmt = 0; - switch (uncached_dmic_prm[di]->num_pdm_active) { + switch (dmic->global->prm[di].num_pdm_active) { case 1: params->channels = 2; break; @@ -1085,11 +1084,12 @@ static int dmic_get_hw_params(struct dai *dai, params->channels = 4; break; default: - dai_info(dai, "dmic_get_hw_params(): not supported channels amount"); + dai_info(dai, "dmic_get_hw_params(): not supported PDM active count %d", + dmic->global->prm[di].num_pdm_active); return -EINVAL; } - switch (uncached_dmic_prm[di]->fifo_bits) { + switch (dmic->global->prm[di].fifo_bits) { case 16: params->frame_fmt = SOF_IPC_FRAME_S16_LE; break; @@ -1106,7 +1106,6 @@ static int dmic_get_hw_params(struct dai *dai, static int dmic_set_config(struct dai *dai, struct sof_ipc_dai_config *config) { - struct sof_ipc_dai_dmic_params **uncached_dmic_prm = cache_to_uncache(&dmic_prm[0]); struct dmic_pdata *dmic = dai_get_drvdata(dai); struct matched_modes modes_ab; struct dmic_configuration cfg; @@ -1114,7 +1113,6 @@ static int dmic_set_config(struct dai *dai, struct sof_ipc_dai_config *config) struct decim_modes modes_b; int32_t unmute_ramp_time_ms; int32_t step_db; - size_t size; int i, j, ret = 0; int di = dai->index; @@ -1165,44 +1163,25 @@ static int dmic_set_config(struct dai *dai, struct sof_ipc_dai_config *config) * the active controllers * "prm" is initialized with default params for all HW controllers */ - if (!uncached_dmic_prm[0]) { - size = sizeof(struct sof_ipc_dai_dmic_params); - dmic_prm[0] = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, - 0, SOF_MEM_CAPS_RAM, - DMIC_HW_FIFOS * size); - /* write it back */ - uncached_dmic_prm[0] = dmic_prm[0]; - if (!uncached_dmic_prm[0]) { - dai_err(dai, "dmic_set_config(): prm not initialized"); - ret = -ENOMEM; - goto out; - } - for (i = 1; i < DMIC_HW_FIFOS; i++) { - dmic_prm[i] = (struct sof_ipc_dai_dmic_params *) - ((uint8_t *)uncached_dmic_prm[i - 1] + size); - /* write it back */ - uncached_dmic_prm[i] = dmic_prm[i]; - } - } + assert(dmic); /* Copy the new DMIC params header (all but not pdm[]) to persistent. * The last arrived request determines the parameters. */ - ret = memcpy_s(uncached_dmic_prm[di], sizeof(*uncached_dmic_prm[di]), &config->dmic, + ret = memcpy_s(&dmic->global->prm[di], sizeof(dmic->global->prm[di]), &config->dmic, offsetof(struct sof_ipc_dai_dmic_params, pdm)); assert(!ret); /* copy the pdm controller params from ipc */ for (i = 0; i < DMIC_HW_CONTROLLERS; i++) { - uncached_dmic_prm[di]->pdm[i].id = i; + dmic->global->prm[di].pdm[i].id = i; for (j = 0; j < config->dmic.num_pdm_active; j++) { /* copy the pdm controller params id the id's match */ - if (uncached_dmic_prm[di]->pdm[i].id == config->dmic.pdm[j].id) { - ret = memcpy_s(&uncached_dmic_prm[di]->pdm[i], - sizeof(uncached_dmic_prm[di]->pdm[i]), + if (dmic->global->prm[di].pdm[i].id == config->dmic.pdm[j].id) { + ret = memcpy_s(&dmic->global->prm[di].pdm[i], + sizeof(dmic->global->prm[di].pdm[i]), &config->dmic.pdm[j], - sizeof( - struct sof_ipc_dai_dmic_pdm_ctrl)); + sizeof(struct sof_ipc_dai_dmic_pdm_ctrl)); assert(!ret); } } @@ -1211,13 +1190,13 @@ static int dmic_set_config(struct dai *dai, struct sof_ipc_dai_config *config) dai_info(dai, "dmic_set_config(), prm config->dmic.num_pdm_active = %u", config->dmic.num_pdm_active); dai_info(dai, "dmic_set_config(), prm pdmclk_min = %u, pdmclk_max = %u", - uncached_dmic_prm[di]->pdmclk_min, uncached_dmic_prm[di]->pdmclk_max); + dmic->global->prm[di].pdmclk_min, dmic->global->prm[di].pdmclk_max); dai_info(dai, "dmic_set_config(), prm duty_min = %u, duty_max = %u", - uncached_dmic_prm[di]->duty_min, uncached_dmic_prm[di]->duty_max); + dmic->global->prm[di].duty_min, dmic->global->prm[di].duty_max); dai_info(dai, "dmic_set_config(), prm fifo_fs = %u, fifo_bits = %u", - uncached_dmic_prm[di]->fifo_fs, uncached_dmic_prm[di]->fifo_bits); + dmic->global->prm[di].fifo_fs, dmic->global->prm[di].fifo_bits); - switch (uncached_dmic_prm[di]->fifo_bits) { + switch (dmic->global->prm[di].fifo_bits) { case 0: case 16: case 32: @@ -1234,15 +1213,15 @@ static int dmic_set_config(struct dai *dai, struct sof_ipc_dai_config *config) * to use for FIR coefficient RAM write as well as the CIC and FIR * shift values. */ - find_modes(dai, &modes_a, uncached_dmic_prm[0]->fifo_fs, di); - if (modes_a.num_of_modes == 0 && uncached_dmic_prm[0]->fifo_fs > 0) { + find_modes(dai, &modes_a, dmic->global->prm[0].fifo_fs, di); + if (modes_a.num_of_modes == 0 && dmic->global->prm[0].fifo_fs > 0) { dai_err(dai, "dmic_set_config(): No modes found found for FIFO A"); ret = -EINVAL; goto out; } - find_modes(dai, &modes_b, uncached_dmic_prm[1]->fifo_fs, di); - if (modes_b.num_of_modes == 0 && uncached_dmic_prm[1]->fifo_fs > 0) { + find_modes(dai, &modes_b, dmic->global->prm[1].fifo_fs, di); + if (modes_b.num_of_modes == 0 && dmic->global->prm[1].fifo_fs > 0) { dai_err(dai, "dmic_set_config(): No modes found for FIFO B"); ret = -EINVAL; goto out; @@ -1289,8 +1268,6 @@ static int dmic_set_config(struct dai *dai, struct sof_ipc_dai_config *config) /* start the DMIC for capture */ static void dmic_start(struct dai *dai) { - struct sof_ipc_dai_dmic_params **uncached_dmic_prm = cache_to_uncache(&dmic_prm[0]); - int *uncached_dmic_active_fifos = cache_to_uncache(&dmic_active_fifos); struct dmic_pdata *dmic = dai_get_drvdata(dai); int i; int mic_a; @@ -1329,13 +1306,13 @@ static void dmic_start(struct dai *dai) for (i = 0; i < DMIC_HW_CONTROLLERS; i++) { mic_a = dmic->enable[i] & 1; mic_b = (dmic->enable[i] & 2) >> 1; - if (uncached_dmic_prm[0]->fifo_fs > 0) + if (dmic->global->prm[0].fifo_fs > 0) fir_a = (dmic->enable[i] > 0) ? 1 : 0; else fir_a = 0; #if DMIC_HW_FIFOS > 1 - if (uncached_dmic_prm[1]->fifo_fs > 0) + if (dmic->global->prm[1].fifo_fs > 0) fir_b = (dmic->enable[i] > 0) ? 1 : 0; else fir_b = 0; @@ -1399,11 +1376,11 @@ static void dmic_start(struct dai *dai) CIC_CONTROL_SOFT_RESET_BIT, 0); } - if (dmic->state == COMP_STATE_PREPARE) - (*uncached_dmic_active_fifos)++; + /* Set bit dai->index */ + dmic->global->active_fifos_mask |= BIT(dai->index); + dmic->global->pause_mask &= ~BIT(dai->index); dmic->state = COMP_STATE_ACTIVE; - spin_unlock(&dai->lock); /* Currently there's no DMIC HW internal mutings and wait times @@ -1416,22 +1393,14 @@ static void dmic_start(struct dai *dai) DMIC_UNMUTE_RAMP_US); - dai_info(dai, "dmic_start(), done active_fifos = %d", - *uncached_dmic_active_fifos); + dai_info(dai, "dmic_start(), dmic_active_fifos_mask = 0x%x", + dmic->global->active_fifos_mask); } -/* stop the DMIC for capture */ -static void dmic_stop(struct dai *dai, bool in_active) +static void dmic_stop_fifo_packers(struct dai *dai, int fifo_index) { - struct dmic_pdata *dmic = dai_get_drvdata(dai); - int *uncached_dmic_active_fifos = cache_to_uncache(&dmic_active_fifos); - int i; - - dai_dbg(dai, "dmic_stop()"); - spin_lock(&dai->lock); - /* Stop FIFO packers and set FIFO initialize bits */ - switch (dai->index) { + switch (fifo_index) { case 0: dai_update_bits(dai, OUTCONTROL0, OUTCONTROL0_SIP_BIT | OUTCONTROL0_FINIT_BIT, @@ -1443,15 +1412,36 @@ static void dmic_stop(struct dai *dai, bool in_active) OUTCONTROL1_FINIT_BIT); break; } +} + +/* stop the DMIC for capture */ +static void dmic_stop(struct dai *dai, bool stop_is_pause) +{ + struct dmic_pdata *dmic = dai_get_drvdata(dai); + int i; + + dai_dbg(dai, "dmic_stop()"); + spin_lock(&dai->lock); + + dmic_stop_fifo_packers(dai, dai->index); /* Set soft reset and mute on for all PDM controllers. */ - dai_info(dai, "dmic_stop(), dmic_active_fifos = %d", - *uncached_dmic_active_fifos); + dai_info(dai, "dmic_stop(), dmic_active_fifos_mask = 0x%x", + dmic->global->active_fifos_mask); + + /* Clear bit dai->index for active FIFO. If stop for pause, set pause mask bit. + * If stop is not for pausing, it is safe to clear the pause bit. + */ + dmic->global->active_fifos_mask &= ~BIT(dai->index); + if (stop_is_pause) + dmic->global->pause_mask |= BIT(dai->index); + else + dmic->global->pause_mask &= ~BIT(dai->index); for (i = 0; i < DMIC_HW_CONTROLLERS; i++) { - /* Don't stop CIC yet if both FIFOs were active */ - if (*uncached_dmic_active_fifos == 1) { + /* Don't stop CIC yet if one FIFO remains active */ + if (dmic->global->active_fifos_mask == 0) { dai_update_bits(dai, base[i] + CIC_CONTROL, CIC_CONTROL_SOFT_RESET_BIT | CIC_CONTROL_MIC_MUTE_BIT, @@ -1472,9 +1462,6 @@ static void dmic_stop(struct dai *dai, bool in_active) } } - if (in_active) - (*uncached_dmic_active_fifos)--; - schedule_task_cancel(&dmic->dmicwork); spin_unlock(&dai->lock); } @@ -1523,7 +1510,7 @@ static int dmic_trigger(struct dai *dai, int cmd, int direction) break; case COMP_TRIGGER_STOP: dmic->state = COMP_STATE_PREPARE; - dmic_stop(dai, true); + dmic_stop(dai, false); break; case COMP_TRIGGER_PAUSE: dmic->state = COMP_STATE_PAUSED; @@ -1549,7 +1536,6 @@ static int dmic_trigger(struct dai *dai, int cmd, int direction) static void dmic_irq_handler(void *data) { struct dai *dai = data; - struct dmic_pdata *dmic = dai_get_drvdata(dai); uint32_t val0; uint32_t val1; @@ -1562,15 +1548,13 @@ static void dmic_irq_handler(void *data) if (val0 & OUTSTAT0_ROR_BIT) { dai_err(dai, "dmic_irq_handler(): full fifo A or PDM overrun"); dai_write(dai, OUTSTAT0, val0); - dmic_stop(dai, dmic->state == COMP_STATE_ACTIVE); - dmic->state = COMP_STATE_PREPARE; + dmic_stop_fifo_packers(dai, 0); } if (val1 & OUTSTAT1_ROR_BIT) { dai_err(dai, "dmic_irq_handler(): full fifo B or PDM overrun"); dai_write(dai, OUTSTAT1, val1); - dmic_stop(dai, dmic->state == COMP_STATE_ACTIVE); - dmic->state = COMP_STATE_PREPARE; + dmic_stop_fifo_packers(dai, 1); } } @@ -1585,7 +1569,6 @@ static int dmic_probe(struct dai *dai) if (dai_get_drvdata(dai)) return -EEXIST; /* already created */ - /* allocate private data */ dmic = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dmic)); if (!dmic) { dai_err(dai, "dmic_probe(): alloc failed"); @@ -1593,6 +1576,9 @@ static int dmic_probe(struct dai *dai) } dai_set_drvdata(dai, dmic); + /* Common shared data for all DMIC DAI instances */ + dmic->global = platform_shared_get(&dmic_global, sizeof(dmic_global)); + /* Set state, note there is no playback direction support */ dmic->state = COMP_STATE_READY; @@ -1614,52 +1600,45 @@ static int dmic_probe(struct dai *dai) /* Initialize start sequence handler */ schedule_task_init_ll(&dmic->dmicwork, SOF_UUID(dmic_work_task_uuid), SOF_SCHEDULE_LL_TIMER, - SOF_TASK_PRI_MED, dmic_work, dai, 0, 0); + SOF_TASK_PRI_MED, dmic_work, dai, cpu_get_id(), 0); /* Enable DMIC power */ pm_runtime_get_sync(DMIC_POW, dai->index); /* Disable dynamic clock gating for dmic before touching any reg */ pm_runtime_get_sync(DMIC_CLK, dai->index); - interrupt_enable(dmic->irq, dai); - - return 0; } static int dmic_remove(struct dai *dai) { - struct sof_ipc_dai_dmic_params **uncached_dmic_prm = cache_to_uncache(&dmic_prm[0]); - int uncached_dmic_active_fifos = *cache_to_uncache(&dmic_active_fifos); struct dmic_pdata *dmic = dai_get_drvdata(dai); - int i; + uint32_t active_fifos_mask = dmic->global->active_fifos_mask; + uint32_t pause_mask = dmic->global->pause_mask; dai_info(dai, "dmic_remove()"); + interrupt_disable(dmic->irq, dai); + interrupt_unregister(dmic->irq, dai); + /* remove scheduling */ schedule_task_free(&dmic->dmicwork); - rfree(dai_get_drvdata(dai)); + dai_info(dai, "dmic_remove(), dmic_active_fifos_mask = 0x%x, dmic_pause_mask = 0x%x", + active_fifos_mask, pause_mask); dai_set_drvdata(dai, NULL); + rfree(dmic); - interrupt_disable(dmic->irq, dai); - interrupt_unregister(dmic->irq, dai); - - /* The next end tasks must be passed if another DAI FIFO still runs */ - if (uncached_dmic_active_fifos) + /* The next end tasks must be passed if another DAI FIFO still runs. + * Note: dai_put() function that calls remove() applies the spinlock + * so it is not needed here to protect access to mask bits. + */ + if (active_fifos_mask || pause_mask) return 0; + /* Disable DMIC clock and power */ pm_runtime_put_sync(DMIC_CLK, dai->index); - /* Disable DMIC power */ pm_runtime_put_sync(DMIC_POW, dai->index); - - rfree(uncached_dmic_prm[0]); - for (i = 0; i < DMIC_HW_FIFOS; i++) { - dmic_prm[i] = NULL; - /* write it back */ - uncached_dmic_prm[i] = dmic_prm[i]; - } - return 0; } diff --git a/src/include/sof/drivers/dmic.h b/src/include/sof/drivers/dmic.h index 3c3448c1cbce..c0640ddd8e63 100644 --- a/src/include/sof/drivers/dmic.h +++ b/src/include/sof/drivers/dmic.h @@ -50,6 +50,7 @@ #if DMIC_HW_VERSION +#include #include #include #include @@ -315,15 +316,23 @@ #define dmic_irq(dmic) dmic->plat_data.irq #define dmic_irq_name(dmic) dmic->plat_data.irq_name +struct dmic_global_shared { + struct sof_ipc_dai_dmic_params prm[DMIC_HW_FIFOS]; /* Configuration requests */ + uint32_t active_fifos_mask; /* Bits (dai->index) are set to indicate active FIFO */ + uint32_t pause_mask; /* Bits (dai->index) are set to indicate driver pause */ +}; + /* DMIC private data */ struct dmic_pdata { - uint16_t enable[DMIC_HW_CONTROLLERS]; - uint32_t state; - struct task dmicwork; - int32_t startcount; - int32_t gain; - int32_t gain_coef; - int irq; + struct dmic_global_shared *global; /* Common data for all DMIC DAI instances */ + struct task dmicwork; /* HW gain ramp update task */ + uint16_t enable[DMIC_HW_CONTROLLERS]; /* Mic 0 and 1 enable bits array for PDMx */ + uint32_t state; /* Driver component state */ + int32_t startcount; /* Counter in dmicwork that controls HW unmute */ + int32_t gain_coef; /* Gain update constant */ + int32_t gain; /* Gain value to be applied to HW */ + int irq; /* Interrupt number used */ + }; extern const struct dai_driver dmic_driver; diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 7ff591b26abb..b824985087a8 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -132,7 +132,7 @@ if (CONFIG_SOC_SERIES_INTEL_CAVS_V15) ) zephyr_library_sources_ifdef(CONFIG_INTEL_DMIC - ${SOF_DRIVERS_PATH}/intel/dmic.c + ${SOF_DRIVERS_PATH}/intel/dmic/dmic.c ) # Platform sources @@ -185,7 +185,7 @@ if (CONFIG_SOC_SERIES_INTEL_CAVS_V18) ) zephyr_library_sources_ifdef(CONFIG_INTEL_DMIC - ${SOF_DRIVERS_PATH}/intel/dmic.c + ${SOF_DRIVERS_PATH}/intel/dmic/dmic.c ) # Platform sources @@ -240,7 +240,7 @@ if (CONFIG_SOC_SERIES_INTEL_CAVS_V20) ) zephyr_library_sources_ifdef(CONFIG_INTEL_DMIC - ${SOF_DRIVERS_PATH}/intel/dmic.c + ${SOF_DRIVERS_PATH}/intel/dmic/dmic.c ) # Platform sources @@ -297,7 +297,7 @@ if (CONFIG_SOC_SERIES_INTEL_CAVS_V25) ) zephyr_library_sources_ifdef(CONFIG_INTEL_DMIC - ${SOF_DRIVERS_PATH}/intel/dmic.c + ${SOF_DRIVERS_PATH}/intel/dmic/dmic.c ) # Platform sources