From b5df7bf2aca0ec428a5dc2e6353f1cfeaf161009 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Mon, 17 May 2021 14:32:54 +0800 Subject: [PATCH] dmic: switch to use uncached dmic_prm[] When multi-core introduced, we need to use uncached address for the global configuration variables, to make sure they are consistent for all DSP cores. When variables change, write through for both cached and uncached addresses, to ensure the consistency. Signed-off-by: Keyon Jie --- src/drivers/intel/dmic.c | 148 ++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 63 deletions(-) diff --git a/src/drivers/intel/dmic.c b/src/drivers/intel/dmic.c index 39172a74a..fff265cf9 100644 --- a/src/drivers/intel/dmic.c +++ b/src/drivers/intel/dmic.c @@ -134,7 +134,7 @@ 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 */ +/* 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; @@ -225,6 +225,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]); int clkdiv_min; int clkdiv_max; int clkdiv; @@ -256,37 +257,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 (dmic_prm[di]->pdmclk_max < DMIC_HW_PDM_CLK_MIN || - dmic_prm[di]->pdmclk_max > DMIC_HW_IOCLK / 2) { + if (uncached_dmic_prm[di]->pdmclk_max < DMIC_HW_PDM_CLK_MIN || + uncached_dmic_prm[di]->pdmclk_max > DMIC_HW_IOCLK / 2) { dai_err(dai, "find_modes(): pdm clock max not in range"); return; } - if (dmic_prm[di]->pdmclk_min < DMIC_HW_PDM_CLK_MIN || - dmic_prm[di]->pdmclk_min > dmic_prm[di]->pdmclk_max) { + if (uncached_dmic_prm[di]->pdmclk_min < DMIC_HW_PDM_CLK_MIN || + uncached_dmic_prm[di]->pdmclk_min > uncached_dmic_prm[di]->pdmclk_max) { dai_err(dai, "find_modes(): pdm clock min not in range"); return; } /* Check for sane duty cycle */ - if (dmic_prm[di]->duty_min > dmic_prm[di]->duty_max) { + if (uncached_dmic_prm[di]->duty_min > uncached_dmic_prm[di]->duty_max) { dai_err(dai, "find_modes(): duty cycle min > max"); return; } - if (dmic_prm[di]->duty_min < DMIC_HW_DUTY_MIN || - dmic_prm[di]->duty_min > DMIC_HW_DUTY_MAX) { + if (uncached_dmic_prm[di]->duty_min < DMIC_HW_DUTY_MIN || + uncached_dmic_prm[di]->duty_min > DMIC_HW_DUTY_MAX) { dai_err(dai, "find_modes(): pdm clock min not in range"); return; } - if (dmic_prm[di]->duty_max < DMIC_HW_DUTY_MIN || - dmic_prm[di]->duty_max > DMIC_HW_DUTY_MAX) { + if (uncached_dmic_prm[di]->duty_max < DMIC_HW_DUTY_MIN || + uncached_dmic_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, dmic_prm[di]->pdmclk_max); + clkdiv_min = ceil_divide(DMIC_HW_IOCLK, uncached_dmic_prm[di]->pdmclk_max); clkdiv_min = MAX(clkdiv_min, DMIC_HW_CIC_DECIM_MIN); - clkdiv_max = DMIC_HW_IOCLK / dmic_prm[di]->pdmclk_min; + clkdiv_max = DMIC_HW_IOCLK / uncached_dmic_prm[di]->pdmclk_min; /* Loop possible clock dividers and check based on resulting * oversampling ratio that CIC and FIR decimation ratios are @@ -309,8 +310,8 @@ static void find_modes(struct dai *dai, * not exceed microphone specification. If exceed proceed to * next clkdiv. */ - if (osr < osr_min || du_min < dmic_prm[di]->duty_min || - du_max > dmic_prm[di]->duty_max) + if (osr < osr_min || du_min < uncached_dmic_prm[di]->duty_min || + du_max > uncached_dmic_prm[di]->duty_max) continue; /* Loop FIR decimation factors candidates. If the @@ -673,6 +674,7 @@ static int select_mode(struct dai *dai, static inline void ipm_helper1(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; @@ -681,8 +683,8 @@ static inline void ipm_helper1(int *ipm, int di) * this DAI. */ for (i = 0; i < DMIC_HW_CONTROLLERS; i++) { - if (dmic_prm[di]->pdm[i].enable_mic_a || - dmic_prm[di]->pdm[i].enable_mic_b) + if (uncached_dmic_prm[di]->pdm[i].enable_mic_a || + uncached_dmic_prm[di]->pdm[i].enable_mic_b) pdm[i] = 1; else pdm[i] = 0; @@ -702,6 +704,7 @@ static inline void ipm_helper1(int *ipm, int di) static inline void ipm_helper2(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; @@ -715,8 +718,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 (dmic_prm[di]->pdm[i].enable_mic_a || - dmic_prm[di]->pdm[i].enable_mic_b) { + if (uncached_dmic_prm[di]->pdm[i].enable_mic_a || + uncached_dmic_prm[di]->pdm[i].enable_mic_b) { pdm[i] = 1; source[n] = i; n++; @@ -739,6 +742,7 @@ static inline void ipm_helper2(int source[], int *ipm, int di) */ static int stereo_helper(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; @@ -746,12 +750,12 @@ static int stereo_helper(int stereo[], int swap[]) for (i = 0; i < DMIC_HW_CONTROLLERS; i++) { cnt = 0; - if (dmic_prm[0]->pdm[i].enable_mic_a || - dmic_prm[1]->pdm[i].enable_mic_a) + if (uncached_dmic_prm[0]->pdm[i].enable_mic_a || + uncached_dmic_prm[1]->pdm[i].enable_mic_a) cnt++; - if (dmic_prm[0]->pdm[i].enable_mic_b || - dmic_prm[1]->pdm[i].enable_mic_b) + if (uncached_dmic_prm[0]->pdm[i].enable_mic_b || + uncached_dmic_prm[1]->pdm[i].enable_mic_b) cnt++; /* Set stereo mode if both mic A anc B are enabled. */ @@ -759,12 +763,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] = (dmic_prm[0]->pdm[i].enable_mic_b || - dmic_prm[1]->pdm[i].enable_mic_b) && !cnt; + swap[i] = (uncached_dmic_prm[0]->pdm[i].enable_mic_b || + uncached_dmic_prm[1]->pdm[i].enable_mic_b) && !cnt; /* Check that swap does not conflict with other DAI request */ - swap_check = dmic_prm[1]->pdm[i].enable_mic_a || - dmic_prm[0]->pdm[i].enable_mic_a; + swap_check = uncached_dmic_prm[1]->pdm[i].enable_mic_a || + uncached_dmic_prm[0]->pdm[i].enable_mic_a; if (swap_check && swap[i]) ret = -EINVAL; @@ -775,13 +779,14 @@ 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); int stereo[DMIC_HW_CONTROLLERS]; int swap[DMIC_HW_CONTROLLERS]; uint32_t val; uint32_t ref; int32_t ci; uint32_t cu; - int uncached_dmic_active_fifos = *cache_to_uncache(&dmic_active_fifos); int ipm; int of0; int of1; @@ -821,10 +826,10 @@ static int configure_registers(struct dai *dai, dai_info(dai, "configuring registers"); /* OUTCONTROL0 and OUTCONTROL1 */ - of0 = (dmic_prm[0]->fifo_bits == 32) ? 2 : 0; + of0 = (prm_t[0]->fifo_bits == 32) ? 2 : 0; #if DMIC_HW_FIFOS > 1 - of1 = (dmic_prm[1]->fifo_bits == 32) ? 2 : 0; + of1 = (prm_t[1]->fifo_bits == 32) ? 2 : 0; #else of1 = 0; #endif @@ -897,8 +902,8 @@ 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] = (dmic_prm[di]->pdm[i].enable_mic_b << 1) | - dmic_prm[di]->pdm[i].enable_mic_a; + pdata->enable[i] = (prm_t[di]->pdm[i].enable_mic_b << 1) | + prm_t[di]->pdm[i].enable_mic_a; } @@ -914,8 +919,8 @@ static int configure_registers(struct dai *dai, val = CIC_CONTROL_SOFT_RESET(soft_reset) | CIC_CONTROL_CIC_START_B(0) | CIC_CONTROL_CIC_START_A(0) | - CIC_CONTROL_MIC_B_POLARITY(dmic_prm[di]->pdm[i].polarity_mic_a) | - CIC_CONTROL_MIC_A_POLARITY(dmic_prm[di]->pdm[i].polarity_mic_b) | + 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_MUTE(cic_mute) | CIC_CONTROL_STEREO_MODE(stereo[i]); dai_write(dai, base[i] + CIC_CONTROL, val); @@ -930,12 +935,12 @@ static int configure_registers(struct dai *dai, * since the mono decimation is done with only left channel * processing active. */ - edge = dmic_prm[di]->pdm[i].clk_edge; + edge = prm_t[di]->pdm[i].clk_edge; if (swap[i]) edge = !edge; val = MIC_CONTROL_PDM_CLKDIV(cfg->clkdiv - 2) | - MIC_CONTROL_PDM_SKEW(dmic_prm[di]->pdm[i].skew) | + MIC_CONTROL_PDM_SKEW(prm_t[di]->pdm[i].skew) | MIC_CONTROL_CLK_EDGE(edge) | MIC_CONTROL_PDM_EN_B(0) | MIC_CONTROL_PDM_EN_A(0); @@ -1061,12 +1066,18 @@ 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]); int di = dai->index; - params->rate = dmic_prm[di]->fifo_fs; + 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]); + return -EINVAL; + } + params->rate = uncached_dmic_prm[di]->fifo_fs; params->buffer_fmt = 0; - switch (dmic_prm[di]->num_pdm_active) { + switch (uncached_dmic_prm[di]->num_pdm_active) { case 1: params->channels = 2; break; @@ -1078,7 +1089,7 @@ static int dmic_get_hw_params(struct dai *dai, return -EINVAL; } - switch (dmic_prm[di]->fifo_bits) { + switch (uncached_dmic_prm[di]->fifo_bits) { case 16: params->frame_fmt = SOF_IPC_FRAME_S16_LE; break; @@ -1095,6 +1106,7 @@ 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; @@ -1153,36 +1165,41 @@ 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 (!dmic_prm[0]) { + 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_prm[0] = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, + 0, SOF_MEM_CAPS_RAM, DMIC_HW_FIFOS * size); - if (!dmic_prm[0]) { + /* 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++) + for (i = 1; i < DMIC_HW_FIFOS; i++) { dmic_prm[i] = (struct sof_ipc_dai_dmic_params *) - ((uint8_t *)dmic_prm[i - 1] + size); + ((uint8_t *)uncached_dmic_prm[i - 1] + size); + /* write it back */ + uncached_dmic_prm[i] = dmic_prm[i]; + } } /* Copy the new DMIC params header (all but not pdm[]) to persistent. * The last arrived request determines the parameters. */ - ret = memcpy_s(dmic_prm[di], sizeof(*dmic_prm[di]), &config->dmic, + ret = memcpy_s(uncached_dmic_prm[di], sizeof(*uncached_dmic_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++) { - dmic_prm[di]->pdm[i].id = i; + uncached_dmic_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 (dmic_prm[di]->pdm[i].id == config->dmic.pdm[j].id) { - ret = memcpy_s(&dmic_prm[di]->pdm[i], - sizeof(dmic_prm[di]->pdm[i]), + 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]), &config->dmic.pdm[j], sizeof( struct sof_ipc_dai_dmic_pdm_ctrl)); @@ -1194,13 +1211,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", - dmic_prm[di]->pdmclk_min, dmic_prm[di]->pdmclk_max); + uncached_dmic_prm[di]->pdmclk_min, uncached_dmic_prm[di]->pdmclk_max); dai_info(dai, "dmic_set_config(), prm duty_min = %u, duty_max = %u", - dmic_prm[di]->duty_min, dmic_prm[di]->duty_max); + uncached_dmic_prm[di]->duty_min, uncached_dmic_prm[di]->duty_max); dai_info(dai, "dmic_set_config(), prm fifo_fs = %u, fifo_bits = %u", - dmic_prm[di]->fifo_fs, dmic_prm[di]->fifo_bits); + uncached_dmic_prm[di]->fifo_fs, uncached_dmic_prm[di]->fifo_bits); - switch (dmic_prm[di]->fifo_bits) { + switch (uncached_dmic_prm[di]->fifo_bits) { case 0: case 16: case 32: @@ -1217,15 +1234,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, dmic_prm[0]->fifo_fs, di); - if (modes_a.num_of_modes == 0 && dmic_prm[0]->fifo_fs > 0) { + 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) { dai_err(dai, "dmic_set_config(): No modes found found for FIFO A"); ret = -EINVAL; goto out; } - find_modes(dai, &modes_b, dmic_prm[1]->fifo_fs, di); - if (modes_b.num_of_modes == 0 && dmic_prm[1]->fifo_fs > 0) { + 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) { dai_err(dai, "dmic_set_config(): No modes found for FIFO B"); ret = -EINVAL; goto out; @@ -1272,8 +1289,9 @@ out: /* start the DMIC for capture */ static void dmic_start(struct dai *dai) { - struct dmic_pdata *dmic = dai_get_drvdata(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; int mic_b; @@ -1311,13 +1329,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 (dmic_prm[0]->fifo_fs > 0) + if (uncached_dmic_prm[0]->fifo_fs > 0) fir_a = (dmic->enable[i] > 0) ? 1 : 0; else fir_a = 0; #if DMIC_HW_FIFOS > 1 - if (dmic_prm[1]->fifo_fs > 0) + if (uncached_dmic_prm[1]->fifo_fs > 0) fir_b = (dmic->enable[i] > 0) ? 1 : 0; else fir_b = 0; @@ -1611,8 +1629,9 @@ static int dmic_probe(struct dai *dai) static int dmic_remove(struct dai *dai) { - struct dmic_pdata *dmic = dai_get_drvdata(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; dai_info(dai, "dmic_remove()"); @@ -1634,9 +1653,12 @@ static int dmic_remove(struct dai *dai) /* Disable DMIC power */ pm_runtime_put_sync(DMIC_POW, dai->index); - rfree(dmic_prm[0]); - for (i = 0; i < DMIC_HW_FIFOS; i++) + 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; }