diff --git a/drivers/dai/intel/dmic/dmic.h b/drivers/dai/intel/dmic/dmic.h index 896c5fa0959..52399106925 100644 --- a/drivers/dai/intel/dmic/dmic.h +++ b/drivers/dai/intel/dmic/dmic.h @@ -133,56 +133,6 @@ #define DMA_HANDSHAKE_DMIC_CH0 0 #define DMA_HANDSHAKE_DMIC_CH1 1 -/* For NHLT DMIC configuration parsing */ -#define DMIC_HW_CONTROLLERS_MAX 4 -#define DMIC_HW_FIFOS_MAX 2 - -struct nhlt_dmic_gateway_attributes { - uint32_t dw; -}; - -struct nhlt_dmic_ts_group { - uint32_t ts_group[4]; -}; - -struct nhlt_dmic_clock_on_delay { - uint32_t clock_on_delay; -}; - -struct nhlt_dmic_channel_ctrl_mask { - uint8_t channel_ctrl_mask; - uint8_t clock_source; - uint16_t rsvd; -}; - -struct nhlt_pdm_ctrl_mask { - uint32_t pdm_ctrl_mask; -}; - -struct nhlt_pdm_ctrl_cfg { - uint32_t cic_control; - uint32_t cic_config; - uint32_t reserved0; - uint32_t mic_control; - uint32_t pdm_sdw_map; - uint32_t reuse_fir_from_pdm; - uint32_t reserved1[2]; -}; - -struct nhlt_pdm_ctrl_fir_cfg { - uint32_t fir_control; - uint32_t fir_config; - int32_t dc_offset_left; - int32_t dc_offset_right; - int32_t out_gain_left; - int32_t out_gain_right; - uint32_t reserved[2]; -}; - -struct nhlt_pdm_fir_coeffs { - int32_t fir_coeffs[0]; -}; - enum dai_dmic_frame_format { DAI_DMIC_FRAME_S16_LE = 0, DAI_DMIC_FRAME_S24_4LE, diff --git a/drivers/dai/intel/dmic/dmic_nhlt.c b/drivers/dai/intel/dmic/dmic_nhlt.c index ede7dc903a8..d0a6fdc996a 100644 --- a/drivers/dai/intel/dmic/dmic_nhlt.c +++ b/drivers/dai/intel/dmic/dmic_nhlt.c @@ -16,6 +16,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include #include "dmic.h" #include +#include "dmic_nhlt.h" extern struct dai_dmic_global_shared dai_dmic_global; @@ -279,8 +280,8 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf struct nhlt_pdm_ctrl_cfg *pdm_cfg[DMIC_HW_CONTROLLERS_MAX]; struct nhlt_pdm_ctrl_fir_cfg *fir_cfg_a[DMIC_HW_CONTROLLERS_MAX]; struct nhlt_pdm_ctrl_fir_cfg *fir_cfg_b[DMIC_HW_CONTROLLERS_MAX]; - struct nhlt_pdm_fir_coeffs *fir_a[DMIC_HW_CONTROLLERS_MAX] = {NULL}; - struct nhlt_pdm_fir_coeffs *fir_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; uint32_t out_control[DMIC_HW_FIFOS_MAX] = {0}; @@ -320,7 +321,7 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf /* Skip not used headers */ p += sizeof(struct nhlt_dmic_gateway_attributes); p += sizeof(struct nhlt_dmic_ts_group); - p += sizeof(struct nhlt_dmic_clock_on_delay); + p += sizeof(struct nhlt_dmic_global_config); /* Channel_ctlr_mask bits indicate the FIFOs enabled*/ dmic_cfg = (struct nhlt_dmic_channel_ctrl_mask *)p; @@ -512,8 +513,7 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf } /* FIR A */ - fir_cfg_a[n] = (struct nhlt_pdm_ctrl_fir_cfg *)p; - p += sizeof(struct nhlt_pdm_ctrl_fir_cfg); + fir_cfg_a[n] = &pdm_cfg[n]->fir_config[0]; val = fir_cfg_a[n]->fir_config; fir_length = FIELD_GET(FIR_CONFIG_FIR_LENGTH, val); fir_length_a = fir_length + 1; /* Need for parsing */ @@ -583,8 +583,7 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf } /* FIR B */ - fir_cfg_b[n] = (struct nhlt_pdm_ctrl_fir_cfg *)p; - p += sizeof(struct nhlt_pdm_ctrl_fir_cfg); + fir_cfg_b[n] = &pdm_cfg[n]->fir_config[1]; val = fir_cfg_b[n]->fir_config; fir_length = FIELD_GET(FIR_CONFIG_FIR_LENGTH, val); fir_length_b = fir_length + 1; /* Need for parsing */ @@ -642,9 +641,9 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf /* Set up FIR coefficients RAM */ val = pdm_cfg[n]->reuse_fir_from_pdm; if (val == 0) { - fir_a[n] = (struct nhlt_pdm_fir_coeffs *)p; + fir_a[n] = (uint32_t *)p; p += sizeof(int32_t) * fir_length_a; - fir_b[n] = (struct nhlt_pdm_fir_coeffs *)p; + fir_b[n] = (uint32_t *)p; p += sizeof(int32_t) * fir_length_b; } else { val--; @@ -669,14 +668,14 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf p_clkdiv, p_mcic, p_mfira, fir_length_a); for (i = 0; i < fir_length_a; i++) dai_dmic_write(dmic, - coef_base_a[n] + (i << 2), fir_a[n]->fir_coeffs[i]); + coef_base_a[n] + (i << 2), fir_a[n][i]); } else { LOG_INF( "dmic_set_config_nhlt(): clkdiv = %d, mcic = %d, mfir_b = %d, len = %d", p_clkdiv, p_mcic, p_mfirb, fir_length_b); for (i = 0; i < fir_length_b; i++) dai_dmic_write(dmic, - coef_base_b[n] + (i << 2), fir_b[n]->fir_coeffs[i]); + coef_base_b[n] + (i << 2), fir_b[n][i]); } } diff --git a/drivers/dai/intel/dmic/dmic_nhlt.h b/drivers/dai/intel/dmic/dmic_nhlt.h new file mode 100644 index 00000000000..f4a2c4fc029 --- /dev/null +++ b/drivers/dai/intel/dmic/dmic_nhlt.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (c) 2023 Intel Corporation + * + * Author: Adrian Warecki + */ + +#ifndef __INTEL_DAI_DRIVER_DMIC_NHLT_H__ +#define __INTEL_DAI_DRIVER_DMIC_NHLT_H__ + +/* For NHLT DMIC configuration parsing */ +#define DMIC_HW_CONTROLLERS_MAX 4 +#define DMIC_HW_FIFOS_MAX 2 + +struct nhlt_dmic_gateway_attributes { + uint32_t dw; +}; + +/* Time-slot mappings */ +struct nhlt_dmic_ts_group { + uint32_t ts_group[4]; +}; + +/* Global configuration settings */ +struct nhlt_dmic_global_config { + uint32_t clock_on_delay; +}; + +/* PDM channels to be programmed using data from channel_cfg array. */ +struct nhlt_dmic_channel_ctrl_mask { + /* i'th bit = 1 means that configuration for PDM channel # i is provided. */ + uint8_t channel_ctrl_mask; + uint8_t clock_source; + uint16_t rsvd; +}; + +/* Channel configuration, see PDM HW specification for details. */ +struct nhlt_dmic_channel_config { + uint32_t out_control; +}; + +struct nhlt_dmic_config_blob { + struct nhlt_dmic_gateway_attributes gtw_attributes; + struct nhlt_dmic_ts_group time_slot; + struct nhlt_dmic_global_config global_config; + struct nhlt_dmic_channel_ctrl_mask ctrl_mask; + struct nhlt_dmic_channel_config channel_config[]; +}; + +struct nhlt_pdm_ctrl_mask { + uint32_t pdm_ctrl_mask; +}; + +/* FIR configuration, see PDM HW specification for details. + * + * If there is only one PDM controller configuration passed, the other (missing) one is configured + * by the driver just by clearing CIC_CONTROL.SOFT_RESET bit. + * + * The driver needs to make sure that all mics are disabled before starting to program PDM + * controllers. + */ +struct nhlt_pdm_ctrl_fir_cfg { + uint32_t fir_control; + uint32_t fir_config; + int32_t dc_offset_left; + int32_t dc_offset_right; + int32_t out_gain_left; + int32_t out_gain_right; + uint32_t reserved[2]; +}; + +/* PDM controller configuration, see PDM HW specification for details. */ +struct nhlt_pdm_ctrl_cfg { + uint32_t cic_control; + uint32_t cic_config; + + uint32_t reserved0; + uint32_t mic_control; + + /* PDM SoundWire Map + * + * This field is used on platforms with SoundWire, otherwise ignored. + */ + uint32_t pdm_sdw_map; + + /* Index of another nhlt_pdm_ctrl_cfg to be used as a source of FIR coefficients. + * + * The index is 1-based, value of 0 means that FIR coefficients array fir_coeffs is provided + * by this item. + * This is a very common case that the same FIR coefficients are used to program more than + * one PDM controller. In this case, fir_coeffs array may be provided in a single copy + * following nhlt_pdm_ctrl_cfg #0 and be reused by nhlt_pdm_ctrl_cfg #1 by setting + * reuse_fir_from_pdm to 1 (1-based index). + */ + uint32_t reuse_fir_from_pdm; + uint32_t reserved1[2]; + + /* FIR configurations */ + struct nhlt_pdm_ctrl_fir_cfg fir_config[2]; + + /* Array of FIR coefficients, channel A goes first, then channel B. + * + * Actual size of the array depends on the number of active taps of the FIR filter for + * channel A plus the number of active taps of the FIR filter for channel B (see FIR_CONFIG) + * as well as on the form (packed/unpacked) of values. + */ + uint32_t fir_coeffs[]; +}; + +/* Tag indicating that FIRs are in a packed 24-bit format. + * + * Size of a single coefficient is 20-bit. Coefficients may be sent in either unpacked form where + * each value takes one DWORD (32-bits) or in packed form where the array begins with + * (FIR_COEFFS_PACKED_TO_24_BITS) value to indicate packed form (unpacked coefficient has always + * most significant byte set to 0) followed by array of 24-bit values (in little endian form). + */ +#define FIR_COEFFS_PACKED_TO_24_BITS 0xFFFFFFFF + +#endif /* __INTEL_DAI_DRIVER_DMIC_NHLT_H__ */