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 <yang.jie@linux.intel.com>
This commit is contained in:
Keyon Jie 2021-05-17 14:32:54 +08:00
parent e9d2900b3b
commit b5df7bf2ac
1 changed files with 85 additions and 63 deletions

View File

@ -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;
}