diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 9ba6fc087606..5cede32c765a 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -483,6 +483,52 @@ static int basefw_get_large_config(struct comp_dev *dev, data_offset, data); }; +/** + * Handles the DMA Control IPC message to initialize or modify DMA gateway configuration. + * + * @param first_block Indicates if this is the first data block in the message. + * @param last_block Indicates if this is the last data block in the message. + * @param data_offset The offset of the data in the message. + * @param data Pointer to the data buffer containing the DMA Control message. + * @return 0 on success, negative error code on failure. + */ +static int basefw_dma_control(bool first_block, + bool last_block, + uint32_t data_offset, + const char *data) +{ + struct ipc4_dma_control *dma_control; + size_t data_size; + int ret; + + /* Ensure that the message is atomic and contains all necessary information */ + if (!first_block || !last_block) { + tr_err(&ipc_tr, "Non-atomic DMA Control message received"); + return -EINVAL; + } + + dma_control = (struct ipc4_dma_control *)data; + if (dma_control->config_length > 0) { + /* DMA Control is passed using a structure with the same construction as in DAI + * configuration. There is an additional section whose size is not accounted for in + * the config_length field. As a result, the configuration size will always be 0. + */ + tr_err(&ipc_tr, "The expected size of the data is 0."); + return -EINVAL; + } + + data_size = data_offset - (sizeof(struct ipc4_dma_control) - sizeof(uint32_t)); + ret = basefw_vendor_dma_control(dma_control->node_id, + (const char *)dma_control->config_data, + data_size); + if (ret < 0) { + tr_err(&ipc_tr, "DMA gateway configuration failed, error: %d", ret); + return ret; + } + + return 0; +} + static int basefw_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, @@ -491,6 +537,8 @@ static int basefw_set_large_config(struct comp_dev *dev, const char *data) { switch (param_id) { + case IPC4_DMA_CONTROL: + return basefw_dma_control(first_block, last_block, data_offset, data); case IPC4_PERF_MEASUREMENTS_STATE: return set_perf_meas_state(data); case IPC4_SYSTEM_TIME: diff --git a/src/audio/base_fw_intel.c b/src/audio/base_fw_intel.c index d5ea9f8d4f89..e449b5c17d63 100644 --- a/src/audio/base_fw_intel.c +++ b/src/audio/base_fw_intel.c @@ -18,6 +18,7 @@ #include #include #endif +#include #include #include @@ -314,3 +315,52 @@ int basefw_vendor_set_large_config(struct comp_dev *dev, return IPC4_UNKNOWN_MESSAGE_TYPE; } + +static inline bool is_ssp_node_id(uint32_t dma_type) +{ + return dma_type == ipc4_i2s_link_output_class || + dma_type == ipc4_i2s_link_input_class; +} + +int basefw_vendor_dma_control(uint32_t node_id, const char *config_data, size_t data_size) +{ + union ipc4_connector_node_id node = (union ipc4_connector_node_id)node_id; + int ret, result; + + tr_info(&basefw_comp_tr, "node_id 0x%x, config_data 0x%x, data_size %u", + node_id, (uint32_t)config_data, data_size); + if (!is_ssp_node_id(node.f.dma_type)) { + tr_err(&basefw_comp_tr, "Unsupported or invalid node_id: 0x%x for DMA Control", + node_id); + return -EOPNOTSUPP; + } + + const struct device *dev = dai_get_device(DAI_INTEL_SSP, node.f.v_index); + + if (!dev) { + tr_err(&basefw_comp_tr, + "Failed to find the SSP DAI device for node_id: 0x%x", + node_id); + return -EINVAL; + } + + ret = pm_device_runtime_get(dev); + if (ret < 0) { + tr_err(&basefw_comp_tr, "Failed to get resume device, error: %d", + ret); + return ret; + } + + result = dai_config_update(dev, config_data, data_size); + if (result < 0) + tr_err(&basefw_comp_tr, + "Failed to set DMA control for SSP DAI, error: %d", + result); + + ret = pm_device_runtime_put(dev); + if (ret < 0) + tr_err(&basefw_comp_tr, "Failed to suspend device, error: %d", + ret); + + return result; +} diff --git a/src/include/ipc4/base_fw_vendor.h b/src/include/ipc4/base_fw_vendor.h index 4b02ad89c480..60173439b502 100644 --- a/src/include/ipc4/base_fw_vendor.h +++ b/src/include/ipc4/base_fw_vendor.h @@ -83,6 +83,18 @@ int basefw_vendor_set_large_config(struct comp_dev *dev, uint32_t data_offset, const char *data); +/** + * @brief Vendor specific routine to configure DMA gateway. + * + * @param node_id The node ID of the DMA gateway to configure. + * @param config_data pointer to the configuration data. + * @param data_size Size of the configuration data. + * @return 0 if successful, error code otherwise. + */ +int basefw_vendor_dma_control(uint32_t node_id, + const char *config_data, + size_t data_size); + #else /* !CONFIG_IPC4_BASE_FW_INTEL */ static inline int basefw_vendor_fw_config(uint32_t *data_offset, char *data) @@ -133,6 +145,13 @@ static inline int basefw_vendor_set_large_config(struct comp_dev *dev, return IPC4_UNKNOWN_MESSAGE_TYPE; } +static inline int basefw_vendor_dma_control(uint32_t node_id, + const char *config_data, + size_t data_size) +{ + return IPC4_UNKNOWN_MESSAGE_TYPE; +} + #endif #endif /* __SOF_IPC4_BASE_FW_VENDOR_H__ */