From 913972ee52191da621aa9d7d37ea8a5a76eb4492 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Wed, 22 May 2024 12:05:42 +0200 Subject: [PATCH] audio: base_fw: Implement IPC4_DMA_CONTROL message handling This patch introduces handling for the IPC4_DMA_CONTROL message type in the base firmware. The implementation includes a new function `basefw_vendor_dma_control` to process the DMA Control configuration for any DAI type. The `basefw_dma_control` function has been added to handle the IPC4_DMA_CONTROL message. It ensures the message is atomic and contains all necessary information before casting the data buffer to the `ipc4_dma_control` structure and processing it. The function also calls `basefw_vendor_dma_control` to apply the DMA Control configuration to the hardware. The `basefw_set_large_config` function in `src/audio/base_fw.c` has been updated to call `basefw_dma_control` when an IPC4_DMA_CONTROL message is received. If the `dai_config_update` operation is not implemented by the DAI driver, the function will return `-ENOSYS`. This change allows the base firmware to initialize or modify DMA gateway configurations dynamically, improving the flexibility of DMA management in response to IPC messages. Signed-off-by: Tomasz Leman --- src/audio/base_fw.c | 48 +++++++++++++++++++++++++++++++ src/audio/base_fw_intel.c | 39 +++++++++++++++++++++++++ src/include/ipc4/base_fw_vendor.h | 19 ++++++++++++ 3 files changed, 106 insertions(+) diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index f8919a6e04ab..1a87f06a619c 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -481,6 +481,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, @@ -489,6 +535,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 9bdaf2b05b7a..992da50b5d8d 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 @@ -319,3 +320,41 @@ int basefw_vendor_set_large_config(struct comp_dev *dev, return IPC4_UNKNOWN_MESSAGE_TYPE; } + +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); + + 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 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 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__ */