Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 102 additions & 43 deletions src/audio/copier/copier_dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,96 @@ static int copier_set_alh_multi_gtw_channel_map(struct comp_dev *dev,
return 0;
}

static int copier_alh_assign_dai_index(struct comp_dev *dev,
void *gtw_cfg_data,
union ipc4_connector_node_id node_id,
struct ipc_config_dai *dai,
int *dai_index,
int *dai_count)
{
struct processing_module *mod = comp_get_drvdata(dev);
struct copier_data *cd = module_get_private_data(mod);
const struct sof_alh_configuration_blob *alh_blob = gtw_cfg_data;
uint8_t *dma_config;
size_t alh_cfg_size, dma_config_length;
int i, dai_num, ret;

if (!cd->config.gtw_cfg.config_length) {
comp_err(mod->dev, "No gateway config found in blob!");
return -EINVAL;
}

switch (dai->type) {
case SOF_DAI_INTEL_HDA:
/* We use DAI_INTEL_HDA for ACE 2.0 platforms */
alh_cfg_size = get_alh_config_size(alh_blob);
dma_config = (uint8_t *)gtw_cfg_data + alh_cfg_size;
dma_config_length = (cd->config.gtw_cfg.config_length << 2) - alh_cfg_size;

/* Here we check node_id if we need to use FW aggregation,
* in other words do we need to create multiple dai or not
*/
if (!is_multi_gateway(node_id)) {
/* Find DMA config in blob and retrieve stream_id */
ret = ipc4_find_dma_config_multiple(dai, dma_config, dma_config_length,
alh_blob->alh_cfg.mapping[0].alh_id, 0);
if (ret != 0) {
comp_err(mod->dev, "No sndw dma_config found in blob!");
return -EINVAL;
}
dai_index[0] = dai->host_dma_config[0]->stream_id;
return 0;
}

dai_num = alh_blob->alh_cfg.count;
if (dai_num > IPC4_ALH_MAX_NUMBER_OF_GTW || dai_num < 0) {
comp_err(mod->dev, "Invalid dai_count: %d", dai_num);
return -EINVAL;
}

for (i = 0; i < dai_num; i++) {
ret = ipc4_find_dma_config_multiple(dai, dma_config,
dma_config_length,
alh_blob->alh_cfg.mapping[i].alh_id, i);
if (ret != 0) {
comp_err(mod->dev, "No sndw dma_config found in blob!");
return -EINVAL;
}

/* To process data on SoundWire interface HD-A DMA is used so it seems
* logical to me to use stream tag as a dai_index instead of PDI.
*/
dai_index[i] = dai->host_dma_config[i]->stream_id;
}

*dai_count = dai_num;
break;
case SOF_DAI_INTEL_ALH:
/* Use DAI_INTEL_ALH for ACE 1.0 and older */
if (!is_multi_gateway(node_id)) {
dai_index[0] = IPC4_ALH_DAI_INDEX(node_id.f.v_index);
return 0;
}

dai_num = alh_blob->alh_cfg.count;
if (dai_num > IPC4_ALH_MAX_NUMBER_OF_GTW || dai_num < 0) {
comp_err(mod->dev, "Invalid dai_count: %d", dai_num);
return -EINVAL;
}

for (i = 0; i < dai_num; i++)
dai_index[i] = IPC4_ALH_DAI_INDEX(alh_blob->alh_cfg.mapping[i].alh_id);

*dai_count = dai_num;
break;
default:
comp_err(mod->dev, "Invalid dai type selected: %d", dai->type);
return -EINVAL;
}

return 0;
}

static int copier_dai_init(struct comp_dev *dev,
struct comp_ipc_config *config,
const struct ipc4_copier_module_cfg *copier,
Expand Down Expand Up @@ -100,7 +190,8 @@ static int copier_dai_init(struct comp_dev *dev,
}

/* save the channel map and count for ALH multi-gateway */
if (type == ipc4_gtw_alh && is_multi_gateway(copier->gtw_cfg.node_id)) {
if ((type == ipc4_gtw_alh || type == ipc4_gtw_link) &&
is_multi_gateway(copier->gtw_cfg.node_id)) {
ret = copier_set_alh_multi_gtw_channel_map(dev, copier, index);
if (ret < 0)
return ret;
Expand Down Expand Up @@ -182,50 +273,19 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd,
break;
case ipc4_alh_link_output_class:
case ipc4_alh_link_input_class:
#if defined(CONFIG_ACE_VERSION_2_0)
dai.type = SOF_DAI_INTEL_HDA;
dai.is_config_blob = true;
type = ipc4_gtw_link;
#else
dai.type = SOF_DAI_INTEL_ALH;
dai.is_config_blob = true;
type = ipc4_gtw_alh;

/* copier
* {
* gtw_cfg
* {
* gtw_node_id;
* config_length;
* config_data
* {
* count;
* {
* node_id; \\ normal gtw id
* mask;
* } mapping[MAX_ALH_COUNT];
* }
* }
* }
*/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this... description not valid any more? I'm not entirely sure what it meant, but some documentation is often better than no documentation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment belongs to struct ipc4_copier_gateway_cfg for ALH node_id. This structure is well commented in alh.h an copier.h headers. So I think it's not necessary to have it here.

/* get gtw node id in config data */
if (is_multi_gateway(node_id)) {
if (copier->gtw_cfg.config_length) {
const struct sof_alh_configuration_blob *alh_blob =
(const struct sof_alh_configuration_blob *)
copier->gtw_cfg.config_data;

dai_count = alh_blob->alh_cfg.count;
if (dai_count > IPC4_ALH_MAX_NUMBER_OF_GTW || dai_count < 0) {
comp_err(dev, "Invalid dai_count: %d", dai_count);
return -EINVAL;
}
for (i = 0; i < dai_count; i++)
dai_index[i] =
IPC4_ALH_DAI_INDEX(alh_blob->alh_cfg.mapping[i].alh_id);
} else {
comp_err(dev, "No ipc4_alh_multi_gtw_cfg found in blob!");
return -EINVAL;
}
} else {
dai_index[dai_count - 1] = IPC4_ALH_DAI_INDEX(node_id.f.v_index);
}

#endif /* defined(CONFIG_ACE_VERSION_2_0) */
ret = copier_alh_assign_dai_index(dev, cd->gtw_cfg, node_id,
&dai, dai_index, &dai_count);
if (ret)
return ret;
break;
case ipc4_dmic_link_input_class:
dai.type = SOF_DAI_INTEL_DMIC;
Expand Down Expand Up @@ -425,7 +485,6 @@ int copier_dai_params(struct copier_data *cd, struct comp_dev *dev,
cd->converter[IPC4_COPIER_GATEWAY_PIN];
return ret;
}

/* For ALH multi-gateway case, params->channels is a total multiplexed
* number of channels. Demultiplexed number of channels for each individual
* gateway comes in blob's struct ipc4_alh_multi_gtw_cfg.
Expand Down
8 changes: 8 additions & 0 deletions src/include/ipc4/alh.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,12 @@ struct sof_alh_configuration_blob {
struct ipc4_alh_multi_gtw_cfg alh_cfg;
} __attribute__((packed, aligned(4)));

static inline size_t
get_alh_config_size(const struct sof_alh_configuration_blob *alh_blob)
{
return sizeof(alh_blob->gtw_attributes) +
sizeof(alh_blob->alh_cfg.count) +
sizeof(alh_blob->alh_cfg.mapping[0]) * alh_blob->alh_cfg.count;
}

#endif
3 changes: 2 additions & 1 deletion src/include/sof/audio/ipc-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ struct ipc_config_dai {
uint32_t feature_mask; /**< copier feature mask (set directly from
* ipc4_copier_module_cfg on init)
*/
struct ipc_dma_config *host_dma_config; /**< DMA config - required for ACE 2.0 and newer */
/**< DMA configs - required for ACE 2.0 and newer */
struct ipc_dma_config *host_dma_config[GTW_DMA_DEVICE_MAX_COUNT];
const struct ipc4_audio_format *out_fmt;/**< audio format for output pin 0 - required
* for ACE 2.0 and newer
*/
Expand Down
3 changes: 2 additions & 1 deletion src/include/sof/ipc/topology.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ int ipc4_pipeline_complete(struct ipc *ipc, uint32_t comp_id, uint32_t cmd);
int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint32_t size);
int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd);
int ipc4_pipeline_trigger(struct ipc_comp_dev *ppl_icd, uint32_t cmd, bool *delayed);

int ipc4_find_dma_config_multiple(struct ipc_config_dai *dai, uint8_t *data_buffer,
uint32_t size, uint32_t device_id, int dma_cfg_idx);
#else
#error "No or invalid IPC MAJOR version selected."
#endif
Expand Down
21 changes: 21 additions & 0 deletions src/include/sof/tlv.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ struct sof_tlv {
*/
static inline struct sof_tlv *tlv_next(const struct sof_tlv *tlv)
{
if (tlv->length % sizeof(uint32_t) != 0)
return NULL;

return (struct sof_tlv *)((char *)(tlv) + sizeof(*tlv) + tlv->length);
}

Expand Down Expand Up @@ -94,4 +97,22 @@ static inline void tlv_value_get(const void *data,
}
}

/**
* @brief Retrieves pointer to the TLV Structure value of the specified type
*
* @param tlv TLV struct pointer.
* @param type Value type.
* @return Value pointer
*/
static inline void *tlv_value_ptr_get(struct sof_tlv *tlv, uint32_t type)
{
if ((uintptr_t)tlv % sizeof(uint32_t) != 0)
return NULL;

if (tlv->type != type)
return NULL;

return (void *)tlv->value;
}

#endif /* __SOF_TLV_H__ */
32 changes: 28 additions & 4 deletions src/ipc/ipc4/dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <sof/audio/module_adapter/module/generic.h>

#include "../audio/copier/copier.h"
#include "../audio/copier/dai_copier.h"
Expand All @@ -44,7 +45,7 @@ void dai_set_link_hda_config(uint16_t *link_config,
case SOF_DAI_INTEL_SSP:
link_cfg.full = 0;
link_cfg.part.dir = common_config->direction;
link_cfg.part.stream = common_config->host_dma_config->stream_id;
link_cfg.part.stream = common_config->host_dma_config[0]->stream_id;
break;
case SOF_DAI_INTEL_DMIC:
link_cfg.full = 0;
Expand All @@ -57,7 +58,7 @@ void dai_set_link_hda_config(uint16_t *link_config,
} else {
link_cfg.part.hchan = out_fmt->channels_count - 1;
}
link_cfg.part.stream = common_config->host_dma_config->stream_id;
link_cfg.part.stream = common_config->host_dma_config[0]->stream_id;
break;
default:
/* other types of DAIs not need link_config */
Expand All @@ -79,11 +80,34 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void
case SOF_DAI_INTEL_DMIC:
channel = 0;
#if defined(CONFIG_ACE_VERSION_2_0)
if (dai->host_dma_config->pre_allocated_by_host)
channel = dai->host_dma_config->dma_channel_id;
if (dai->host_dma_config[0]->pre_allocated_by_host)
channel = dai->host_dma_config[0]->dma_channel_id;
#endif
break;
case SOF_DAI_INTEL_HDA:
#if defined(CONFIG_ACE_VERSION_2_0)
if (copier_cfg->gtw_cfg.node_id.f.dma_type == ipc4_alh_link_output_class ||
copier_cfg->gtw_cfg.node_id.f.dma_type == ipc4_alh_link_input_class) {
struct processing_module *mod = comp_get_drvdata(dev);
struct copier_data *cd = module_get_private_data(mod);

if (!cd->gtw_cfg) {
comp_err(dev, "No gateway config found!");
return DMA_CHAN_INVALID;
}

channel = DMA_CHAN_INVALID;
const struct sof_alh_configuration_blob *alh_blob = cd->gtw_cfg;

for (int i = 0; i < alh_blob->alh_cfg.count; i++) {
if (dai->host_dma_config[i]->stream_id == dai->dai_index) {
channel = dai->host_dma_config[i]->dma_channel_id;
break;
}
}
break;
}
#endif /* defined(CONFIG_ACE_VERSION_2_0) */
channel = copier_cfg->gtw_cfg.node_id.f.v_index;
break;
case SOF_DAI_INTEL_ALH:
Expand Down
32 changes: 31 additions & 1 deletion src/ipc/ipc4/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <ipc4/module.h>
#include <ipc4/error_status.h>
#include <sof/lib_manager.h>
#include <sof/tlv.h>

#include <errno.h>
#include <stdbool.h>
Expand Down Expand Up @@ -1043,11 +1044,40 @@ int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint3
if (*dma_config_id != GTW_DMA_CONFIG_ID)
return IPC4_INVALID_REQUEST;

dai->host_dma_config = GET_IPC_DMA_CONFIG(data_buffer, size);
dai->host_dma_config[0] = GET_IPC_DMA_CONFIG(data_buffer, size);
#endif
return IPC4_SUCCESS;
}

int ipc4_find_dma_config_multiple(struct ipc_config_dai *dai, uint8_t *data_buffer,
uint32_t size, uint32_t device_id, int dma_cfg_idx)
{
uint32_t end_addr = (uint32_t)data_buffer + size;
struct ipc_dma_config *dma_cfg;
struct sof_tlv *tlvs;

for (tlvs = (struct sof_tlv *)data_buffer; (uint32_t)tlvs < end_addr;
tlvs = tlv_next(tlvs)) {
dma_cfg = tlv_value_ptr_get(tlvs, GTW_DMA_CONFIG_ID);
if (!dma_cfg)
continue;

/* To be able to retrieve proper DMA config we need to check if
* device_id value (which is alh_id) is equal to device_address.
* They both contain SNDW master id and PDI. If they match then
* proper config is found.
*/
for (uint32_t i = 0; i < dma_cfg->channel_map.device_count; i++) {
if (dma_cfg->channel_map.map[i].device_address == device_id) {
dai->host_dma_config[dma_cfg_idx] = dma_cfg;
return IPC4_SUCCESS;
}
}
}

return IPC4_INVALID_REQUEST;
}

void ipc4_base_module_cfg_to_stream_params(const struct ipc4_base_module_cfg *base_cfg,
struct sof_ipc_stream_params *params)
{
Expand Down