Skip to content

Commit

Permalink
audio: base_fw: Implement IPC4_DMA_CONTROL message handling
Browse files Browse the repository at this point in the history
This patch introduces handling for the IPC4_DMA_CONTROL message type in
the base firmware, specifically for the SSP DAI driver. The
implementation includes a new inline function `is_ssp_node_id` to check
whether the node ID corresponds to an SSP DAI, and a new function
`basefw_vendor_dma_control` to process the DMA Control configuration.

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.

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 <tomasz.m.leman@intel.com>
  • Loading branch information
tmleman committed Jun 17, 2024
1 parent 61a1d88 commit 5c45e51
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/audio/base_fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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:
Expand Down
50 changes: 50 additions & 0 deletions src/audio/base_fw_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <zephyr/device.h>
#include <zephyr/drivers/counter.h>
#endif
#include <zephyr/pm/device_runtime.h>

#include <ipc4/base_fw.h>
#include <rimage/sof/user/manifest.h>
Expand Down Expand Up @@ -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;
}
19 changes: 19 additions & 0 deletions src/include/ipc4/base_fw_vendor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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__ */

0 comments on commit 5c45e51

Please sign in to comment.