mirror of https://github.com/thesofproject/sof.git
Drivers: Intel: DMIC: Add blob support for Sue Creek and add checks
This patch adds the missing NHLT blob support for Sue Creek type of DMIC HW (v2). Previously the HW v1 type decoding of the blob would have returned wrong DAI parameters and streaming fail. Checks are added to verify correct usage of bitfields in OUTCONTROL, CIC_CONTROL, and FIR_CONTROL. These registers are different in HW v1 and v2. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
This commit is contained in:
parent
d93f3eeb46
commit
db8ee55b52
|
@ -16,15 +16,6 @@
|
|||
/* Decimation filters */
|
||||
#include <sof/audio/coefficients/pdm_decim/pdm_decim_table.h>
|
||||
|
||||
/* OUTCONTROLx IPM bit fields style */
|
||||
#if DMIC_HW_VERSION == 1 || (DMIC_HW_VERSION == 2 && DMIC_HW_CONTROLLERS <= 2)
|
||||
#define DMIC_IPM_VER1
|
||||
#elif DMIC_HW_VERSION == 3 || (DMIC_HW_VERSION == 2 && DMIC_HW_CONTROLLERS > 2)
|
||||
#define DMIC_IPM_VER2
|
||||
#else
|
||||
#error Not supported HW version
|
||||
#endif
|
||||
|
||||
/* Base addresses (in PDM scope) of 2ch PDM controllers and coefficient RAM. */
|
||||
static const uint32_t base[4] = {PDM0, PDM1, PDM2, PDM3};
|
||||
static const uint32_t coef_base_a[4] = {PDM0_COEFFICIENT_A, PDM1_COEFFICIENT_A,
|
||||
|
|
|
@ -17,6 +17,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};
|
||||
|
||||
#if defined DMIC_IPM_VER1
|
||||
static int nhlt_dmic_dai_params_get(struct dai *dai, uint32_t *outcontrol,
|
||||
struct nhlt_pdm_ctrl_cfg **pdm_cfg,
|
||||
struct nhlt_pdm_ctrl_fir_cfg **fir_cfg)
|
||||
|
@ -82,6 +83,99 @@ static int nhlt_dmic_dai_params_get(struct dai *dai, uint32_t *outcontrol,
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined DMIC_IPM_VER2
|
||||
|
||||
static int ipm_source_to_enable(struct dmic_pdata *dmic, struct nhlt_pdm_ctrl_cfg **pdm_cfg,
|
||||
int *count, int pdm_count, int stereo, int source_pdm)
|
||||
{
|
||||
int mic_swap;
|
||||
|
||||
if (source_pdm >= DMIC_HW_CONTROLLERS)
|
||||
return -EINVAL;
|
||||
|
||||
if (*count < pdm_count) {
|
||||
(*count)++;
|
||||
mic_swap = MIC_CONTROL_PDM_CLK_EDGE_GET(pdm_cfg[source_pdm]->mic_control);
|
||||
if (stereo)
|
||||
dmic->enable[source_pdm] = 0x3; /* PDMi MIC A and B */
|
||||
else
|
||||
dmic->enable[source_pdm] = mic_swap ? 0x2 : 0x1; /* PDMi MIC B or MIC A */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nhlt_dmic_dai_params_get(struct dai *dai, uint32_t *outcontrol,
|
||||
struct nhlt_pdm_ctrl_cfg **pdm_cfg,
|
||||
struct nhlt_pdm_ctrl_fir_cfg **fir_cfg)
|
||||
{
|
||||
struct dmic_pdata *dmic = dai_get_drvdata(dai);
|
||||
uint32_t outcontrol_val = outcontrol[dai->index];
|
||||
int num_pdm;
|
||||
int source_pdm;
|
||||
int ret;
|
||||
int n;
|
||||
bool stereo_pdm;
|
||||
|
||||
switch (OUTCONTROL0_OF_GET(outcontrol_val)) {
|
||||
case 0:
|
||||
case 1:
|
||||
dmic->dai_format = SOF_IPC_FRAME_S16_LE;
|
||||
break;
|
||||
case 2:
|
||||
dmic->dai_format = SOF_IPC_FRAME_S32_LE;
|
||||
break;
|
||||
default:
|
||||
dai_err(dai, "nhlt_dmic_dai_params_get(): Illegal OF bit field");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
num_pdm = OUTCONTROL0_IPM_GET(outcontrol_val);
|
||||
if (num_pdm > DMIC_HW_CONTROLLERS) {
|
||||
dai_err(dai, "nhlt_dmic_dai_params_get(): Illegal IPM PDM controllers count");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
stereo_pdm = 1;
|
||||
|
||||
dmic->dai_channels = (stereo_pdm + 1) * num_pdm;
|
||||
for (n = 0; n < DMIC_HW_CONTROLLERS; n++)
|
||||
dmic->enable[n] = 0;
|
||||
|
||||
n = 0;
|
||||
source_pdm = OUTCONTROL0_IPM_SOURCE_1_GET(outcontrol_val);
|
||||
ret = ipm_source_to_enable(dmic, pdm_cfg, &n, num_pdm, stereo_pdm, source_pdm);
|
||||
if (ret) {
|
||||
dai_err(dai, "nhlt_dmic_dai_params_get(): Illegal IPM_SOURCE_1");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
source_pdm = OUTCONTROL0_IPM_SOURCE_2_GET(outcontrol_val);
|
||||
ret = ipm_source_to_enable(dmic, pdm_cfg, &n, num_pdm, stereo_pdm, source_pdm);
|
||||
if (ret) {
|
||||
dai_err(dai, "nhlt_dmic_dai_params_get(): Illegal IPM_SOURCE_2");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
source_pdm = OUTCONTROL0_IPM_SOURCE_3_GET(outcontrol_val);
|
||||
ret = ipm_source_to_enable(dmic, pdm_cfg, &n, num_pdm, stereo_pdm, source_pdm);
|
||||
if (ret) {
|
||||
dai_err(dai, "nhlt_dmic_dai_params_get(): Illegal IPM_SOURCE_3");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
source_pdm = OUTCONTROL0_IPM_SOURCE_4_GET(outcontrol_val);
|
||||
ret = ipm_source_to_enable(dmic, pdm_cfg, &n, num_pdm, stereo_pdm, source_pdm);
|
||||
if (ret) {
|
||||
dai_err(dai, "nhlt_dmic_dai_params_get(): Illegal IPM_SOURCE_4");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int dmic_set_config_nhlt(struct dai *dai, void *spec_config)
|
||||
{
|
||||
|
@ -93,9 +187,10 @@ int dmic_set_config_nhlt(struct dai *dai, void *spec_config)
|
|||
struct nhlt_pdm_fir_coeffs *fir_b[DMIC_HW_CONTROLLERS_MAX];
|
||||
uint32_t out_control[DMIC_HW_FIFOS_MAX];
|
||||
uint32_t channel_ctrl_mask;
|
||||
uint32_t pdm_ctrl_mask;
|
||||
uint32_t val;
|
||||
uint32_t fir_control;
|
||||
uint32_t pdm_ctrl_mask;
|
||||
uint32_t ref;
|
||||
uint32_t val;
|
||||
const uint8_t *p = spec_config;
|
||||
int num_fifos;
|
||||
int num_pdm;
|
||||
|
@ -108,6 +203,9 @@ int dmic_set_config_nhlt(struct dai *dai, void *spec_config)
|
|||
int comb_count;
|
||||
int fir_decimation, fir_shift, fir_length;
|
||||
int bf1, bf2, bf3, bf4, bf5, bf6, bf7, bf8;
|
||||
#if defined DMIC_IPM_VER2
|
||||
int bf9, bf10, bf11, bf12;
|
||||
#endif
|
||||
int ret;
|
||||
int p_mcic = 0;
|
||||
int p_mfira = 0;
|
||||
|
@ -145,6 +243,29 @@ int dmic_set_config_nhlt(struct dai *dai, void *spec_config)
|
|||
dai_dbg(dai, "dmic_set_config_nhlt(): OUTCONTROL%d = %08x", n, out_control[n]);
|
||||
dai_dbg(dai, " tie=%d, sip=%d, finit=%d, fci=%d", bf1, bf2, bf3, bf4);
|
||||
dai_dbg(dai, " bfth=%d, of=%d, ipm=%d, th=%d", bf5, bf6, bf7, bf8);
|
||||
#if defined DMIC_IPM_VER1
|
||||
ref = OUTCONTROL0_TIE(bf1) | OUTCONTROL0_SIP(bf2) | OUTCONTROL0_FINIT(bf3) |
|
||||
OUTCONTROL0_FCI(bf4) | OUTCONTROL0_BFTH(bf5) | OUTCONTROL0_OF(bf6) |
|
||||
OUTCONTROL0_IPM(bf7) | OUTCONTROL0_TH(bf8);
|
||||
#elif defined DMIC_IPM_VER2
|
||||
bf9 = OUTCONTROL0_IPM_SOURCE_1_GET(val);
|
||||
bf10 = OUTCONTROL0_IPM_SOURCE_2_GET(val);
|
||||
bf11 = OUTCONTROL0_IPM_SOURCE_3_GET(val);
|
||||
bf12 = OUTCONTROL0_IPM_SOURCE_4_GET(val);
|
||||
dai_dbg(dai, " ipms1=%d, ipms2=%d, ipms3=%d, ipms4=%d",
|
||||
bf9, bf10, bf11, bf12);
|
||||
ref = OUTCONTROL0_TIE(bf1) | OUTCONTROL0_SIP(bf2) | OUTCONTROL0_FINIT(bf3) |
|
||||
OUTCONTROL0_FCI(bf4) | OUTCONTROL0_BFTH(bf5) | OUTCONTROL0_OF(bf6) |
|
||||
OUTCONTROL0_IPM(bf7) | OUTCONTROL0_IPM_SOURCE_1(bf9) |
|
||||
OUTCONTROL0_IPM_SOURCE_2(bf10) | OUTCONTROL0_IPM_SOURCE_3(bf11) |
|
||||
OUTCONTROL0_IPM_SOURCE_4(bf12) | OUTCONTROL0_TH(bf8);
|
||||
#endif
|
||||
if (ref != val) {
|
||||
dai_err(dai, "dmic_set_config_nhlt(): illegal OUTCONTROL%d = 0x%08x",
|
||||
n, val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
p += sizeof(uint32_t);
|
||||
}
|
||||
|
||||
|
@ -200,8 +321,18 @@ int dmic_set_config_nhlt(struct dai *dai, void *spec_config)
|
|||
dai_dbg(dai, "dmic_set_config_nhlt(): CIC_CONTROL = %08x", val);
|
||||
dai_dbg(dai, " soft_reset=%d, cic_start_b=%d, cic_start_a=%d",
|
||||
bf1, bf2, bf3);
|
||||
dai_dbg(dai, " mic_b_polarity=%d, mic_a_polarity=%d, mic_mute=%d, stereo_mode=%d",
|
||||
bf4, bf5, bf6, bf7);
|
||||
dai_dbg(dai, " mic_b_polarity=%d, mic_a_polarity=%d, mic_mute=%d",
|
||||
bf4, bf5, bf6);
|
||||
ref = CIC_CONTROL_SOFT_RESET(bf1) | CIC_CONTROL_CIC_START_B(bf2) |
|
||||
CIC_CONTROL_CIC_START_A(bf3) | CIC_CONTROL_MIC_B_POLARITY(bf4) |
|
||||
CIC_CONTROL_MIC_A_POLARITY(bf5) | CIC_CONTROL_MIC_MUTE(bf6) |
|
||||
CIC_CONTROL_STEREO_MODE(bf7);
|
||||
dai_dbg(dai, " stereo_mode=%d", bf7);
|
||||
if (ref != val) {
|
||||
dai_err(dai, "dmic_set_config_nhlt(): illegal CIC_CONTROL = 0x%08x",
|
||||
val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Clear CIC_START_A and CIC_START_B, set SOF_RESET and MIC_MUTE*/
|
||||
val = (val & ~(CIC_CONTROL_CIC_START_A_BIT | CIC_CONTROL_CIC_START_A_BIT)) |
|
||||
|
@ -260,6 +391,15 @@ int dmic_set_config_nhlt(struct dai *dai, void *spec_config)
|
|||
dai_dbg(dai, "dmic_set_config_nhlt(): FIR_CONTROL_A = %08x", val);
|
||||
dai_dbg(dai, " start=%d, array_start_en=%d, dccomp=%d", bf1, bf2, bf3);
|
||||
dai_dbg(dai, " mute=%d, stereo=%d", bf4, bf5);
|
||||
ref = FIR_CONTROL_A_START(bf1) | FIR_CONTROL_A_ARRAY_START_EN(bf2) |
|
||||
FIR_CONTROL_A_DCCOMP(bf3) | FIR_CONTROL_A_MUTE(bf4) |
|
||||
FIR_CONTROL_A_STEREO(bf5);
|
||||
|
||||
if (ref != val) {
|
||||
dai_err(dai, "dmic_set_config_nhlt(): illegal FIR_CONTROL = 0x%08x",
|
||||
val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Clear START, set MUTE */
|
||||
fir_control = (val & ~FIR_CONTROL_A_START_BIT) | FIR_CONTROL_A_MUTE_BIT;
|
||||
|
|
|
@ -144,7 +144,16 @@
|
|||
|
||||
/* Register bits */
|
||||
|
||||
#if DMIC_HW_VERSION == 1
|
||||
/* OUTCONTROLx IPM bit fields style */
|
||||
#if DMIC_HW_VERSION == 1 || (DMIC_HW_VERSION == 2 && DMIC_HW_CONTROLLERS <= 2)
|
||||
#define DMIC_IPM_VER1
|
||||
#elif DMIC_HW_VERSION == 2 && DMIC_HW_CONTROLLERS > 2
|
||||
#define DMIC_IPM_VER2
|
||||
#else
|
||||
#error Not supported HW version
|
||||
#endif
|
||||
|
||||
#if defined DMIC_IPM_VER1
|
||||
/* OUTCONTROL0 bits */
|
||||
#define OUTCONTROL0_TIE_BIT BIT(27)
|
||||
#define OUTCONTROL0_SIP_BIT BIT(26)
|
||||
|
@ -192,7 +201,7 @@
|
|||
#define OUTCONTROL1_TH_GET(x) GET_BITS(5, 0, x)
|
||||
#endif
|
||||
|
||||
#if DMIC_HW_VERSION >= 2
|
||||
#if defined DMIC_IPM_VER2
|
||||
/* OUTCONTROL0 bits */
|
||||
#define OUTCONTROL0_TIE_BIT BIT(27)
|
||||
#define OUTCONTROL0_SIP_BIT BIT(26)
|
||||
|
|
Loading…
Reference in New Issue