dai: intel: dmic: New functions for writing fir coefficients

Created set of new functions for configure fir coefficients with support
for packed format. This allowed to make the dai_dmic_set_config_nhlt
function simpler.

Signed-off-by: Adrian Warecki <adrian.warecki@intel.com>
This commit is contained in:
Adrian Warecki 2023-06-29 16:09:26 +02:00 committed by Anas Nashif
commit b26921d776
3 changed files with 133 additions and 77 deletions

View file

@ -22,10 +22,6 @@ extern struct dai_dmic_global_shared dai_dmic_global;
/* Base addresses (in PDM scope) of 2ch PDM controllers and coefficient RAM. */ /* 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 base[4] = {PDM0, PDM1, PDM2, PDM3};
static const uint32_t coef_base_a[4] = {PDM0_COEFFICIENT_A, PDM1_COEFFICIENT_A,
PDM2_COEFFICIENT_A, PDM3_COEFFICIENT_A};
static const uint32_t coef_base_b[4] = {PDM0_COEFFICIENT_B, PDM1_COEFFICIENT_B,
PDM2_COEFFICIENT_B, PDM3_COEFFICIENT_B};
static inline void dai_dmic_write(const struct dai_intel_dmic *dmic, static inline void dai_dmic_write(const struct dai_intel_dmic *dmic,
uint32_t reg, uint32_t val) uint32_t reg, uint32_t val)
@ -38,6 +34,98 @@ static inline uint32_t dai_dmic_read(const struct dai_intel_dmic *dmic, uint32_t
return sys_read32(dmic->reg_base + reg); return sys_read32(dmic->reg_base + reg);
} }
/*
* @brief Move pointer to next coefficient data
*
* @return Returns pointer right after coefficient data
*/
static const uint32_t *dai_dmic_skip_coeff(const uint32_t *coeff, const int length,
const bool packed)
{
if (!packed) {
coeff += length;
} else {
coeff += ROUND_UP(3 * length, sizeof(uint32_t)) / sizeof(uint32_t);
}
return coeff;
}
/*
* @brief Write the fir coefficients in the PDMs' RAM
*/
static void dai_dmic_write_coeff(const struct dai_intel_dmic *dmic, uint32_t base,
const uint32_t *coeff, int length, const bool packed)
{
const uint8_t *coeff_in_bytes;
uint32_t coeff_val;
if (!packed) {
while (length--) {
dai_dmic_write(dmic, base, *coeff++);
base += sizeof(uint32_t);
}
} else {
coeff_in_bytes = (const uint8_t *)coeff;
while (length--) {
coeff_val = coeff_in_bytes[0] +
(coeff_in_bytes[1] << 8) +
(coeff_in_bytes[2] << 16);
dai_dmic_write(dmic, base, coeff_val);
base += sizeof(uint32_t);
coeff_in_bytes += 3;
}
}
}
/*
* @brief Configures the fir coefficients in the PDMs' RAM
*
* @return Returns pointer right after coefficients data
*/
static const uint32_t *dai_dmic_configure_coeff(const struct dai_intel_dmic *dmic,
const struct nhlt_pdm_ctrl_cfg * const pdm_cfg,
const uint32_t pdm_base,
const uint32_t *coeffs)
{
int fir_length_a, fir_length_b;
bool packed = false;
const uint32_t *coeffs_b;
fir_length_a = FIELD_GET(FIR_CONFIG_FIR_LENGTH, pdm_cfg->fir_config[0].fir_config) + 1;
fir_length_b = FIELD_GET(FIR_CONFIG_FIR_LENGTH, pdm_cfg->fir_config[1].fir_config) + 1;
if (fir_length_a > 256 || fir_length_b > 256) {
LOG_ERR("invalid coeff length! %d %d", fir_length_a, fir_length_b);
return NULL;
}
if (*coeffs == FIR_COEFFS_PACKED_TO_24_BITS) {
packed = true;
/* First dword is not included into length_0 and length_1 - skip it. */
coeffs++;
}
coeffs_b = dai_dmic_skip_coeff(coeffs, fir_length_a, packed);
LOG_INF("fir_length_a = %d, fir_length_b = %d, packed = %d", fir_length_a, fir_length_b,
packed);
if (dmic->dai_config_params.dai_index == 0) {
dai_dmic_write_coeff(dmic, pdm_base + PDM_COEFFICIENT_A, coeffs, fir_length_a,
packed);
} else {
dai_dmic_write_coeff(dmic, pdm_base + PDM_COEFFICIENT_B, coeffs_b, fir_length_b,
packed);
}
return dai_dmic_skip_coeff(coeffs_b, fir_length_b, packed);
}
static int dai_nhlt_get_clock_div(const struct dai_intel_dmic *dmic, const int pdm) static int dai_nhlt_get_clock_div(const struct dai_intel_dmic *dmic, const int pdm)
{ {
uint32_t val; uint32_t val;
@ -538,10 +626,6 @@ static void configure_fir(struct dai_intel_dmic *dmic, const uint32_t base,
int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cfg) int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cfg)
{ {
const struct nhlt_pdm_ctrl_cfg *pdm_cfg; const struct nhlt_pdm_ctrl_cfg *pdm_cfg;
const struct nhlt_pdm_ctrl_fir_cfg *fir_cfg_a[DMIC_HW_CONTROLLERS_MAX];
const struct nhlt_pdm_ctrl_fir_cfg *fir_cfg_b[DMIC_HW_CONTROLLERS_MAX];
const uint32_t *fir_a[DMIC_HW_CONTROLLERS_MAX] = {NULL};
const uint32_t *fir_b[DMIC_HW_CONTROLLERS_MAX];
struct nhlt_dmic_channel_ctrl_mask *dmic_cfg; struct nhlt_dmic_channel_ctrl_mask *dmic_cfg;
uint32_t channel_ctrl_mask; uint32_t channel_ctrl_mask;
@ -553,13 +637,14 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf
const uint8_t *p = bespoke_cfg; const uint8_t *p = bespoke_cfg;
int num_fifos; int num_fifos;
int num_pdm; int num_pdm;
int fir_length_a;
int fir_length_b;
int n; int n;
int i;
int fir_decimation, fir_length;
int ret; int ret;
const uint32_t *fir_coeffs;
/* Array of pointers to pdm coefficient data. Used to reuse coefficient from another pdm. */
const uint32_t *pdm_coeff_ptr[DMIC_HW_CONTROLLERS_MAX] = { 0 };
if (dmic->dai_config_params.dai_index >= DMIC_HW_FIFOS_MAX) { if (dmic->dai_config_params.dai_index >= DMIC_HW_FIFOS_MAX) {
LOG_ERR("dmic_set_config_nhlt(): illegal DAI index %d", LOG_ERR("dmic_set_config_nhlt(): illegal DAI index %d",
dmic->dai_config_params.dai_index); dmic->dai_config_params.dai_index);
@ -633,6 +718,8 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf
return -EINVAL; return -EINVAL;
} }
pdm_cfg = (const struct nhlt_pdm_ctrl_cfg *)p;
for (pdm_idx = 0; pdm_idx < CONFIG_DAI_DMIC_HW_CONTROLLERS; pdm_idx++) { for (pdm_idx = 0; pdm_idx < CONFIG_DAI_DMIC_HW_CONTROLLERS; pdm_idx++) {
pdm_base = base[pdm_idx]; pdm_base = base[pdm_idx];
@ -645,9 +732,6 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf
LOG_DBG("PDM%d", pdm_idx); LOG_DBG("PDM%d", pdm_idx);
/* Get CIC configuration */ /* Get CIC configuration */
pdm_cfg = (const struct nhlt_pdm_ctrl_cfg *)p;
p += sizeof(struct nhlt_pdm_ctrl_cfg);
if (dai_dmic_global.active_fifos_mask == 0) { if (dai_dmic_global.active_fifos_mask == 0) {
print_pdm_ctrl(pdm_cfg); print_pdm_ctrl(pdm_cfg);
@ -674,53 +758,39 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf
FIR_CHANNEL_REGS_SIZE * dmic->dai_config_params.dai_index, FIR_CHANNEL_REGS_SIZE * dmic->dai_config_params.dai_index,
&pdm_cfg->fir_config[dmic->dai_config_params.dai_index]); &pdm_cfg->fir_config[dmic->dai_config_params.dai_index]);
/* FIR A */
fir_cfg_a[pdm_idx] = &pdm_cfg->fir_config[0];
val = fir_cfg_a[pdm_idx]->fir_config;
fir_length = FIELD_GET(FIR_CONFIG_FIR_LENGTH, val);
fir_length_a = fir_length + 1; /* Need for parsing */
fir_decimation = FIELD_GET(FIR_CONFIG_FIR_DECIMATION, val);
/* FIR B */ /* Configure fir coefficients */
fir_cfg_b[pdm_idx] = &pdm_cfg->fir_config[1];
val = fir_cfg_b[pdm_idx]->fir_config;
fir_length = FIELD_GET(FIR_CONFIG_FIR_LENGTH, val);
fir_length_b = fir_length + 1; /* Need for parsing */
fir_decimation = FIELD_GET(FIR_CONFIG_FIR_DECIMATION, val);
/* Set up FIR coefficients RAM */ /* Check if FIR coeffs should be reused */
val = pdm_cfg->reuse_fir_from_pdm; if (pdm_cfg->reuse_fir_from_pdm == 0) {
if (val == 0) { /* get ptr, where FIR coeffs starts */
fir_a[pdm_idx] = (uint32_t *)p; fir_coeffs = pdm_cfg->fir_coeffs;
p += sizeof(int32_t) * fir_length_a;
fir_b[pdm_idx] = (uint32_t *)p; /* and save it for future pdms reference */
p += sizeof(int32_t) * fir_length_b; pdm_coeff_ptr[pdm_idx] = fir_coeffs;
} else { } else {
val--; if (pdm_cfg->reuse_fir_from_pdm > pdm_idx) {
if (val >= pdm_idx) { LOG_ERR("invalid reuse fir index %u", pdm_cfg->reuse_fir_from_pdm);
LOG_ERR("Illegal FIR reuse 0x%x", val);
return -EINVAL; return -EINVAL;
} }
if (!fir_a[val]) { /* get FIR coeffs from another pdm */
LOG_ERR("PDM%d FIR reuse from %d fail", pdm_idx, val); fir_coeffs = pdm_coeff_ptr[pdm_cfg->reuse_fir_from_pdm - 1];
if (!fir_coeffs) {
LOG_ERR("unable to reuse fir from %u", pdm_cfg->reuse_fir_from_pdm);
return -EINVAL; return -EINVAL;
} }
fir_a[pdm_idx] = fir_a[val];
fir_b[pdm_idx] = fir_b[val];
} }
if (dmic->dai_config_params.dai_index == 0) { fir_coeffs = dai_dmic_configure_coeff(dmic, pdm_cfg, pdm_base, fir_coeffs);
LOG_INF("len = %d", fir_length_a);
for (i = 0; i < fir_length_a; i++) /* Update pdm_cfg ptr for next PDM Ctrl. */
dai_dmic_write(dmic, if (pdm_cfg->reuse_fir_from_pdm) {
coef_base_a[pdm_idx] + (i << 2), fir_a[pdm_idx][i]); /* fir_coeffs array is empty if reusing previous coeffs */
pdm_cfg = (const struct nhlt_pdm_ctrl_cfg *)&pdm_cfg->fir_coeffs;
} else { } else {
LOG_INF("len = %d", fir_length_b); pdm_cfg = (const struct nhlt_pdm_ctrl_cfg *)fir_coeffs;
for (i = 0; i < fir_length_b; i++)
dai_dmic_write(dmic,
coef_base_b[pdm_idx] + (i << 2), fir_b[pdm_idx][i]);
} }
} }

View file

@ -90,24 +90,17 @@
#define GLOBAL_CAPABILITIES 0x200 #define GLOBAL_CAPABILITIES 0x200
#define PDM_COEFFICIENT_A 0x400
#define PDM_COEF_RAM_A_LENGTH 0x400
#define PDM_COEFFICIENT_B 0x800
#define PDM_COEF_RAM_B_LENGTH 0x400
#define PDM0 0x1000 #define PDM0 0x1000
#define PDM0_COEFFICIENT_A 0x1400
#define PDM0_COEFFICIENT_B 0x1800
#define PDM1 0x2000 #define PDM1 0x2000
#define PDM1_COEFFICIENT_A 0x2400
#define PDM1_COEFFICIENT_B 0x2800
#define PDM2 0x3000 #define PDM2 0x3000
#define PDM2_COEFFICIENT_A 0x3400
#define PDM2_COEFFICIENT_B 0x3800
#define PDM3 0x4000 #define PDM3 0x4000
#define PDM3_COEFFICIENT_A 0x4400
#define PDM3_COEFFICIENT_B 0x4800
#define PDM_COEF_RAM_A_LENGTH 0x0400
#define PDM_COEF_RAM_B_LENGTH 0x0400
/* Local registers in each PDMx */ /* Local registers in each PDMx */

View file

@ -87,24 +87,17 @@
#define GLOBAL_CAPABILITIES 0x200 #define GLOBAL_CAPABILITIES 0x200
#define PDM_COEFFICIENT_A 0x400
#define PDM_COEF_RAM_A_LENGTH 0x400
#define PDM_COEFFICIENT_B 0x800
#define PDM_COEF_RAM_B_LENGTH 0x400
#define PDM0 0x1000 #define PDM0 0x1000
#define PDM0_COEFFICIENT_A 0x1400
#define PDM0_COEFFICIENT_B 0x1800
#define PDM1 0x2000 #define PDM1 0x2000
#define PDM1_COEFFICIENT_A 0x2400
#define PDM1_COEFFICIENT_B 0x2800
#define PDM2 0x3000 #define PDM2 0x3000
#define PDM2_COEFFICIENT_A 0x3400
#define PDM2_COEFFICIENT_B 0x3800
#define PDM3 0x4000 #define PDM3 0x4000
#define PDM3_COEFFICIENT_A 0x4400
#define PDM3_COEFFICIENT_B 0x4800
#define PDM_COEF_RAM_A_LENGTH 0x0400
#define PDM_COEF_RAM_B_LENGTH 0x0400
/* Local registers in each PDMx */ /* Local registers in each PDMx */