diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 6820d54364b2..a6e5394f3618 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -588,7 +588,7 @@ static int basefw_dma_control(bool first_block, } dma_control = (struct ipc4_dma_control *)data; - data_size = data_offset - (sizeof(struct ipc4_dma_control) - sizeof(uint32_t)); + data_size = data_offset - sizeof(struct ipc4_dma_control); if (data_size < (dma_control->config_length * sizeof(uint32_t))) { tr_err(&ipc_tr, "DMA Control data too short: got %u, expected %u", diff --git a/src/audio/base_fw_intel.c b/src/audio/base_fw_intel.c index ff22b16ea9d3..520894ec2d0a 100644 --- a/src/audio/base_fw_intel.c +++ b/src/audio/base_fw_intel.c @@ -9,6 +9,7 @@ #include #include #include +#include #if defined(CONFIG_SOC_SERIES_INTEL_ADSP_ACE) #include @@ -24,6 +25,7 @@ #include #include +#include "copier/copier_gain.h" struct ipc4_modules_info { uint32_t modules_count; @@ -353,7 +355,18 @@ int basefw_vendor_dma_control(uint32_t node_id, const char *config_data, size_t tr_info(&basefw_comp_tr, "node_id 0x%x, config_data 0x%x, data_size %u", node_id, (uint32_t)config_data, data_size); + switch (node.f.dma_type) { + case ipc4_dmic_link_input_class: + /* In DMIC case we don't need to update zephyr dai params */ + ret = copier_gain_dma_control(node, config_data, data_size, + SOF_DAI_INTEL_DMIC); + if (ret) { + tr_err(&basefw_comp_tr, + "Failed to update copier gain coefs, error: %d", ret); + return IPC4_INVALID_REQUEST; + } + return IPC4_SUCCESS; case ipc4_i2s_link_output_class: case ipc4_i2s_link_input_class: type = DAI_INTEL_SSP; diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index c1f748d5eeb4..f79c2b225255 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -322,6 +322,9 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, return -EINVAL; } dai.out_fmt = &copier->out_fmt; +#if CONFIG_COPIER_GAIN + dai.apply_gain = true; +#endif break; default: return -EINVAL; diff --git a/src/audio/copier/copier_gain.c b/src/audio/copier/copier_gain.c index 06fe92629b01..f7e2f24fdb8d 100644 --- a/src/audio/copier/copier_gain.c +++ b/src/audio/copier/copier_gain.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "copier.h" #include "copier_gain.h" @@ -26,6 +28,31 @@ int copier_gain_set_params(struct comp_dev *dev, struct dai_data *dd) /* Set basic gain parameters */ copier_gain_set_basic_params(dev, dd, ipc4_cfg); + switch (dd->dai->type) { + case SOF_DAI_INTEL_DMIC: + { + struct dmic_config_data *dmic_cfg = cd->gtw_cfg; + + if (!dmic_cfg) { + comp_err(dev, "No dmic config found"); + return -EINVAL; + } + + union dmic_global_cfg *dmic_glb_cfg = &dmic_cfg->dmic_blob.global_cfg; + + /* Get fade period from DMIC blob */ + fade_period = dmic_glb_cfg->ext_global_cfg.fade_in_period; + /* Convert and assign silence and fade length values */ + dd->gain_data->silence_sg_length = + frames * dmic_glb_cfg->ext_global_cfg.silence_period; + dd->gain_data->fade_sg_length = frames * fade_period; + } + break; + default: + comp_info(dev, "Apply default fade period for dai type %d", dd->dai->type); + break; + } + /* Set fade parameters */ ret = copier_gain_set_fade_params(dev, dd, ipc4_cfg, fade_period, frames); if (ret) @@ -73,18 +100,19 @@ enum copier_gain_state copier_gain_eval_state(struct copier_gain_params *gain_pa return state; } -int copier_gain_dma_control(uint32_t node_id, const uint32_t *config_data, +int copier_gain_dma_control(union ipc4_connector_node_id node, const char *config_data, size_t config_size, enum sof_ipc_dai_type dai_type) { + struct sof_tlv *tlv = (struct sof_tlv *)config_data; struct ipc *ipc = ipc_get(); struct ipc_comp_dev *icd; struct comp_dev *dev; struct list_item *clist; - int ret; list_for_item(clist, &ipc->comp_list) { struct gain_dma_control_data *gain_data = NULL; + void *tlv_val = NULL; icd = container_of(clist, struct ipc_comp_dev, list); @@ -99,6 +127,29 @@ int copier_gain_dma_control(uint32_t node_id, const uint32_t *config_data, struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); + switch (dai_type) { + case SOF_DAI_INTEL_DMIC: + if (cd->dd[0]->dai->index != node.f.v_index) + continue; + + if (!config_size) { + comp_err(dev, "Config length for DMIC couldn't be zero"); + return -EINVAL; + } + + /* Gain coefficients for DMIC */ + tlv_val = tlv_value_ptr_get(tlv, DMIC_SET_GAIN_COEFFICIENTS); + if (!tlv_val) { + comp_err(dev, "No gain coefficients in DMA_CONTROL ipc"); + return -EINVAL; + } + gain_data = tlv_val; + break; + default: + comp_warn(dev, "Gain DMA control: no dai type=%d found", dai_type); + break; + } + ret = copier_set_gain(dev, cd->dd[0], gain_data); if (ret) comp_err(dev, "Gain DMA control: failed to set gain"); diff --git a/src/audio/copier/copier_gain.h b/src/audio/copier/copier_gain.h index 0ec6e3a502a7..fd2132765ad8 100644 --- a/src/audio/copier/copier_gain.h +++ b/src/audio/copier/copier_gain.h @@ -230,13 +230,13 @@ bool copier_is_unity_gain(struct copier_gain_params *gain_params); * This function retrieves gain data from the DMA Control IPC message and updates * corresponding dai device gain params structure. * - * @param node_id Gateway node id. + * @param node Gateway node id. * @param config_data The gain configuration data. * @param config_size The size of the gain configuration data. * @param dai_type The type of the DAI device. * @return 0 on success, otherwise a negative error code. */ -int copier_gain_dma_control(uint32_t node_id, const uint32_t *config_data, +int copier_gain_dma_control(union ipc4_connector_node_id node, const char *config_data, size_t config_size, enum sof_ipc_dai_type dai_type); #endif /* __SOF_COPIER_GAIN_H__ */ diff --git a/src/include/ipc4/base_fw.h b/src/include/ipc4/base_fw.h index b1367971ffcb..ab98fad44160 100644 --- a/src/include/ipc4/base_fw.h +++ b/src/include/ipc4/base_fw.h @@ -485,7 +485,7 @@ struct ipc4_astate_table { struct ipc4_dma_control { uint32_t node_id; uint32_t config_length; - uint32_t config_data[1]; + uint32_t config_data[0]; } __attribute__((packed, aligned(4))); enum ipc4_perf_measurements_state_set { diff --git a/src/include/ipc4/dmic.h b/src/include/ipc4/dmic.h new file mode 100644 index 000000000000..d09332ec9c5c --- /dev/null +++ b/src/include/ipc4/dmic.h @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2024 Intel Corporation. + */ + +#ifndef __SOF_IPC4_DMIC_H__ +#define __SOF_IPC4_DMIC_H__ + +#include +#include +#include +#include "gateway.h" + +/** + * \file include/ipc4/dmic.h + * \brief IPC4 DMIC definitions. + * NOTE: This ABI uses bit fields and is non portable. + */ + +/* IOCTL ID of DMIC Set Gain Coefficients */ +#define DMIC_SET_GAIN_COEFFICIENTS 2 + +/* Maximum number of dmic gain coefficients */ +#define DMIC_MAX_GAIN_COEFFS_CNT 4 + +/** + * @brief Structure representing the global configuration for DMIC (Digital Microphone) module. + */ +union dmic_global_cfg { + /** + * @brief Raw 32-bit value of Global Cfg. + */ + uint32_t clock_on_delay; + + /** + * @brief Bitfields of Extended Global Config. + */ + struct { + /** + * @brief Specifies the period in milliseconds to override data with silence after + * DMA transfer is started. + */ + uint32_t silence_period : 16; + + /** + * @brief Specifies the period in milliseconds for fade-in to apply on input data + * (following silence_period if applied). + */ + uint32_t fade_in_period : 16; + } ext_global_cfg; +} __packed __aligned(4); + +/** + * @brief Structure representing the configuration of a DMIC channel. + */ +struct dmic_channel_cfg { + /** + * @brief Outcontrol + */ + uint32_t out_control; +}; + +/** + * @brief Structure representing FIR (Finite Impulse Response) configuration. + */ +struct dmic_fir_cfg { + /** + * @brief FIR_CONTROL + * Control register for FIR configuration. + */ + uint32_t fir_control; + + /** + * @brief FIR_CONFIG + * Configuration register for FIR filter. + */ + uint32_t fir_config; + + /** + * @brief DC_OFFSET_LEFT + * DC offset value for the left channel. + */ + uint32_t dc_offset_left; + + /** + * @brief DC_OFFSET_RIGHT + * DC offset value for the right channel. + */ + uint32_t dc_offset_rigth; + + /** + * @brief OUT_GAIN_LEFT + * Output gain value for the left channel. + */ + uint32_t out_gain_left; + + /** + * @brief OUT_GAIN_RIGHT + * Output gain value for the right channel. + */ + uint32_t out_gain_rigth; + + /** + * @brief rsvd_2 + * Reserved field. + */ + uint32_t rsvd_2[2]; +} __packed __aligned(4); + +/** + * @brief Structure representing the configuration of the PDM control for DMIC. + * + * This structure defines the configuration parameters for the PDM control of the DMIC + * (Digital Microphone) module. It includes fields for controlling the CIC (Cascaded + * Integrator-Comb) filter, MIC (Microphone) control, SoundWire mapping, FIR (Finite + * Impulse Response) configurations, and FIR coefficients. + */ +struct dmic_pdm_ctrl_cfg { + /** + * @brief CIC_CONTROL + * Control register for CIC configuration. + */ + uint32_t cic_control; + /** + * @brief CIC_CONFIG + * Configuration register for CIC filter. + */ + uint32_t cic_config; + /** + * @brief Reserved field + */ + uint32_t rsvd_0; + /** + * @brief MIC_CONTROL + * Control register for MIC configuration. + */ + uint32_t mic_control; + /** + * @brief + * This field is used on platforms with SoundWire, otherwise ignored. + */ + uint32_t pdmsm; + /** + * @brief Index of another PDMCtrlCfg to be used as a source of FIR coefficients. + */ + uint32_t reuse_fir_from_pdm; + /** + * @brief Reserved field + */ + uint32_t rsvd_1[2]; + /** + * @brief FIR configurations + */ + struct dmic_fir_cfg fir_config[2]; + /** + * @brief Array of FIR coefficients, channel A goes first, then channel B. + */ + uint32_t fir_coeffs[0]; +} __packed __aligned(4); + +/** + * @brief Structure representing the configuration blob for DMIC (Digital Microphone) settings. + * + * This structure contains various configuration settings for DMIC, including time-slot mappings, + * global configuration, PDM channel configuration, and PDM controller configuration. + */ +struct dmic_config_blob { + /** + * @brief Time-slot mappings. + */ + uint32_t ts_group[4]; + + /** + * @brief DMIC global configuration. + */ + union dmic_global_cfg global_cfg; + + /** + * @brief PDM channels to be programmed using data from channel_cfg array. + */ + uint32_t channel_ctrl_mask : 8; + + /** + * @brief Clock source for DMIC. + */ + uint32_t clock_source : 8; + + /** + * @brief Reserved field. + */ + uint32_t rsvd : 16; + + /** + * @brief PDM channel configuration settings. + */ + struct dmic_channel_cfg channel_cfg[0]; + + /** + * @brief PDM controllers to be programmed using data from pdm_ctrl_cfg array. + */ + uint32_t pdm_ctrl_mask; + + /** + * @brief PDM controller configuration settings. + */ + struct dmic_pdm_ctrl_cfg pdm_ctrl_cfg[0]; +} __packed __aligned(4); + +/** + * @brief Structure representing the configuration data for DMIC. + */ +struct dmic_config_data { + /**< Gateway attributes */ + union ipc4_gateway_attributes gtw_attributes; + /**< DMIC Configuration BLOB */ + struct dmic_config_blob dmic_blob; +} __packed __aligned(4); + +#endif /* __SOF_IPC4_DMIC_H__ */