From 06739188ee7458189a03031b9f6a57f9576ff955 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 | 47 +++++++++++++++++++++++++++++ src/audio/base_fw_intel.c | 50 +++++++++++++++++++++++++++++++ src/include/ipc4/base_fw_vendor.h | 19 ++++++++++++ 3 files changed, 116 insertions(+) diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index ba695216a468..c6576986bc19 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -525,6 +525,51 @@ 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, 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 IPC4_ERROR_INVALID_PARAM; + } + + dma_control = (struct ipc4_dma_control *)data; + data_size = data_offset - (sizeof(struct ipc4_dma_control) - sizeof(uint32_t)); + + if (data_size < dma_control->config_length) { + tr_err(&ipc_tr, "DMA Control data too short: got %u, expected %u", + data_size, dma_control->config_length); + return IPC4_ERROR_INVALID_PARAM; + } + + + 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 IPC4_SUCCESS; +} + static int basefw_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, @@ -533,6 +578,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..e60078f7d229 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,52 @@ 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; + enum dai_type type; + + 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_i2s_link_output_class: + case ipc4_i2s_link_input_class: + type = DAI_INTEL_SSP; + break; + default: + return -EOPNOTSUPP; + } + + const struct device *dev = dai_get_device(type, 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 IPC4_INVALID_RESOURCE_ID; + } + + ret = pm_device_runtime_get(dev); + if (ret < 0) { + tr_err(&basefw_comp_tr, "Failed to get resume device, error: %d", + ret); + return IPC4_FAILURE; + } + + 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); + result = IPC4_FAILURE; + } + + 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__ */