diff --git a/src/audio/copier.c b/src/audio/copier.c index e71ce332c..40698c76a 100644 --- a/src/audio/copier.c +++ b/src/audio/copier.c @@ -399,12 +399,17 @@ static int create_dai(struct comp_dev *parent_dev, struct copier_data *cd, return ret; } -static int init_pipeline_reg(struct copier_data *cd) +static int init_pipeline_reg(struct comp_dev *dev) { + struct copier_data *cd = comp_get_drvdata(dev); struct ipc4_pipeline_registers pipe_reg; - uint8_t gateway_id; + uint32_t gateway_id; + int ret; + + ret = comp_get_attribute(dev, COMP_ATTR_VDMA_INDEX, &gateway_id); + if (ret) + return ret; - gateway_id = cd->config.gtw_cfg.node_id.f.v_index; if (gateway_id >= IPC4_MAX_PIPELINE_REG_SLOTS) { comp_cl_err(&comp_copier, "gateway_id %u out of array bounds.", gateway_id); return -EINVAL; @@ -483,7 +488,7 @@ static struct comp_dev *copier_new(const struct comp_driver *drv, if (cd->direction == SOF_IPC_STREAM_PLAYBACK) { ipc_pipe->pipeline->source_comp = dev; - if (init_pipeline_reg(cd)) + if (init_pipeline_reg(dev)) goto error_cd; } else { ipc_pipe->pipeline->sink_comp = dev; @@ -692,9 +697,9 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) if (ret < 0 || !cd->endpoint_num || !cd->pipeline_reg_offset) return ret; - dai_copier = pipeline_get_dai_comp(dev->pipeline->pipeline_id, &latency); + dai_copier = pipeline_get_dai_comp_latency(dev->pipeline->pipeline_id, &latency); if (!dai_copier) { - comp_err(dev, "failed to find dai comp"); + comp_err(dev, "failed to find dai comp or sink pipeline not running."); return ret; } @@ -713,7 +718,7 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) return 0; } - comp_position(dai_cd->endpoint[IPC4_COPIER_GATEWAY_PIN], &posn); + comp_position(dai_copier, &posn); /* update stream start and end offset for running message in host copier * host driver uses DMA link counter to calculate stream position, but it is @@ -1239,6 +1244,33 @@ static uint64_t copier_get_processed_data(struct comp_dev *dev, uint32_t stream_ return ret; } +static int copier_get_attribute(struct comp_dev *dev, uint32_t type, void *value) +{ + struct copier_data *cd = comp_get_drvdata(dev); + + switch (type) { + case COMP_ATTR_VDMA_INDEX: + *(uint32_t *)value = cd->config.gtw_cfg.node_id.f.v_index; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int copier_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) +{ + struct copier_data *cd = comp_get_drvdata(dev); + + /* Exit if no endpoints */ + if (!cd->endpoint_num) + return -EINVAL; + + /* Return position from the default gateway pin */ + return comp_position(cd->endpoint[IPC4_COPIER_GATEWAY_PIN], posn); +} + static const struct comp_driver comp_copier = { .uid = SOF_RT_UUID(copier_comp_uuid), .tctx = &copier_comp_tr, @@ -1253,6 +1285,8 @@ static const struct comp_driver comp_copier = { .prepare = copier_prepare, .reset = copier_reset, .get_total_data_processed = copier_get_processed_data, + .get_attribute = copier_get_attribute, + .position = copier_position, }, }; diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index 6baa7ae20..e3a900d46 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -422,48 +422,94 @@ int pipeline_for_each_comp(struct comp_dev *current, return 0; } -/* visit connected pipeline to find the dai comp and latency */ -struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id, uint32_t *latency) +/* visit connected pipeline to find the dai comp */ +struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id) { struct ipc_comp_dev *sink; struct ipc *ipc = ipc_get(); - *latency = 0; - sink = ipc_get_ppl_sink_comp(ipc, pipeline_id); - if (!sink) - return NULL; - while (sink) { - struct comp_dev *buff_comp; struct comp_buffer *buffer; + struct comp_dev *comp; - *latency += sink->cd->pipeline->period; /* dai is found */ - if (list_is_empty(&sink->cd->bsink_list)) { - struct list_item *list; - - list = comp_buffer_list(sink->cd, PPL_DIR_UPSTREAM); - buffer = buffer_from_list(list->next, struct comp_buffer, PPL_DIR_UPSTREAM); - break; - } + if (list_is_empty(&sink->cd->bsink_list)) + return sink->cd; buffer = buffer_from_list(comp_buffer_list(sink->cd, PPL_DIR_DOWNSTREAM)->next, struct comp_buffer, PPL_DIR_DOWNSTREAM); - buff_comp = buffer_get_comp(buffer, PPL_DIR_DOWNSTREAM); + comp = buffer_get_comp(buffer, PPL_DIR_DOWNSTREAM); /* buffer_comp is in another pipeline and it is not complete */ - if (!buff_comp->pipeline) + if (!comp->pipeline) return NULL; - sink = ipc_get_ppl_sink_comp(ipc, buff_comp->pipeline->pipeline_id); - - if (!sink) - return NULL; + sink = ipc_get_ppl_sink_comp(ipc, comp->pipeline->pipeline_id); } - /* convert it to ms */ - *latency /= 1000; - - return sink->cd; + return NULL; } + +#if CONFIG_IPC_MAJOR_4 +/* visit connected pipeline to find the dai comp and latency. + * This function walks down through a pipelines chain looking for the target dai component. + * Calculates the delay of each pipeline by determining the number of buffered blocks. + */ +struct comp_dev *pipeline_get_dai_comp_latency(uint32_t pipeline_id, uint32_t *latency) +{ + struct ipc_comp_dev *ipc_sink; + struct ipc_comp_dev *ipc_source; + struct comp_dev *source; + struct ipc *ipc = ipc_get(); + + *latency = 0; + + /* Walks through the ipc component list and get source endpoint component of the given + * pipeline. + */ + ipc_source = ipc_get_ppl_src_comp(ipc, pipeline_id); + if (!ipc_source) + return NULL; + source = ipc_source->cd; + + /* Walks through the ipc component list and get sink endpoint component of the given + * pipeline. This function returns the first sink. We assume that dai is connected to pin 0. + */ + ipc_sink = ipc_get_ppl_sink_comp(ipc, pipeline_id); + while (ipc_sink) { + struct comp_buffer *buffer; + uint64_t input_data, output_data; + struct ipc4_base_module_cfg *input_base_cfg; + struct ipc4_base_module_cfg *output_base_cfg; + + /* Calculate pipeline latency */ + input_data = comp_get_total_data_processed(source, 0, true); + output_data = comp_get_total_data_processed(ipc_sink->cd, 0, false); + if (!input_data || !output_data) + return NULL; + + input_base_cfg = ipc4_comp_get_base_module_cfg(source); + output_base_cfg = ipc4_comp_get_base_module_cfg(ipc_sink->cd); + *latency += input_data / input_base_cfg->ibs - output_data / output_base_cfg->obs; + + /* If the component doesn't have a sink buffer, this is a dai. */ + if (list_is_empty(&ipc_sink->cd->bsink_list)) + return ipc_sink->cd; + + /* Get a component connected to our sink buffer - hop to a next pipeline */ + buffer = buffer_from_list(comp_buffer_list(ipc_sink->cd, PPL_DIR_DOWNSTREAM)->next, + struct comp_buffer, PPL_DIR_DOWNSTREAM); + source = buffer_get_comp(buffer, PPL_DIR_DOWNSTREAM); + + /* buffer_comp is in another pipeline and it is not complete */ + if (!source->pipeline) + return NULL; + + /* Get a next sink component */ + ipc_sink = ipc_get_ppl_sink_comp(ipc, source->pipeline->pipeline_id); + } + + return NULL; +} +#endif diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 684817b80..ce3d5474e 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -128,6 +128,7 @@ enum { #define COMP_ATTR_COPY_TYPE 0 /**< Comp copy type attribute */ #define COMP_ATTR_HOST_BUFFER 1 /**< Comp host buffer attribute */ #define COMP_ATTR_COPY_DIR 2 /**< Comp copy direction */ +#define COMP_ATTR_VDMA_INDEX 3 /**< Comp index of the virtual DMA at the gateway. */ /** @}*/ /** \name Trace macros diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index 045077343..02891b716 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -200,13 +200,22 @@ int pipeline_reset(struct pipeline *p, struct comp_dev *host_cd); int pipeline_for_each_comp(struct comp_dev *current, struct pipeline_walk_context *ctx, int dir); +/** + * \brief Walks pipeline graph to find dai component. + * \param[in] pipeline_id is the start pipeline id. + * \return dai component. + */ +struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id); + +#if CONFIG_IPC_MAJOR_4 /** * \brief Walks pipeline graph to find dai component and latency. * \param[in] pipeline_id is the start pipeline id. * \param[out] latency to dai. * \return dai component. */ -struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id, uint32_t *latency); +struct comp_dev *pipeline_get_dai_comp_latency(uint32_t pipeline_id, uint32_t *latency); +#endif /** * Retrieves pipeline id from pipeline. diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index 835d91155..21c42e13b 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -396,12 +396,12 @@ static int update_dir_to_pipeline_component(uint32_t *ppl_id, uint32_t count) struct comp_dev *dai; struct list_item *clist; struct ipc *ipc; - uint32_t latency, i; + uint32_t i; ipc = ipc_get(); /* only dai has direction based on gateway type */ - dai = pipeline_get_dai_comp(ppl_id[0], &latency); + dai = pipeline_get_dai_comp(ppl_id[0]); /* skip host copier to host copier case */ if (!dai) { tr_info(&ipc_tr, "no dai is found");