diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 0bb2306d2a6e..9197fbd4fe28 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -40,6 +40,7 @@ #include #include #include +#include #if CONFIG_ZEPHYR_NATIVE_DRIVERS #include @@ -92,6 +93,41 @@ static int copier_init(struct processing_module *mod) } dev->pipeline = ipc_pipe->pipeline; + /* Calculation of the period in which the component should be scheduled based on + * the input buffer size. + */ + if (copier->gtw_cfg.dma_buffer_size > 0 && dev->pipeline->deep_buffering) { + /* Size of the single frame in bytes. */ + uint32_t frame_size = copier->base.audio_fmt.channels_count * + (copier->base.audio_fmt.depth >> 3); + /* Size of the one second of audio data in bytes. */ + uint32_t one_s = frame_size * copier->base.audio_fmt.sampling_frequency; + /* Size of the ten millisecond of audio data in bytes. */ + uint32_t ten_ms = DIV_ROUND_UP(one_s, 100); + /* The number of ten milliseconds chunks of data that will fit into the buffer. */ + uint32_t chunk_count = copier->gtw_cfg.dma_buffer_size / ten_ms; + + /* If buffer can fit at more than ten milliseconds of data we can try to schedule + * pipe on periods bigger than one millisecond. + */ + if (chunk_count) { + dev->deep_buffering = true; + if (chunk_count == 1) + dev->period = (5 * LL_TIMER_PERIOD_US); + else + dev->period = (10 * LL_TIMER_PERIOD_US); + + /* If a component that may run on bigger periods has already been added to + * the pipeline, the pipe must run at the lowest possible value. + */ + if (!dev->pipeline->period || dev->pipeline->period < dev->period) { + dev->pipeline->period = dev->period; + comp_cl_warn(&comp_copier, + "changing the period for the pipe (new value %u)", + dev->pipeline->period); + } + } + } node_id = copier->gtw_cfg.node_id; /* copier is linked to gateway */ diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index 82fe49bbed20..dc8eea32e399 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -302,6 +303,14 @@ int pipeline_complete(struct pipeline *p, struct comp_dev *source, data.start = source; data.p = p; + /* If a component has been added to the pipeline that cannot run on longer periods + * we need to set pipe period to one ms. + */ + if (!p->deep_buffering) { + p->period = LL_TIMER_PERIOD_US; + pipe_info(p, "setting pipe period to %llu us", LL_TIMER_PERIOD_US); + } + /* now walk downstream from source component and * complete component task and pipeline initialization */ diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 4a24d08ffb28..cb1a9d82b346 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -591,6 +591,9 @@ struct comp_dev { bool is_shared; /**< indicates whether component is shared * across cores */ + bool deep_buffering; /**< indicates whether component is able to work + * deep buffering + */ struct comp_ipc_config ipc_config; /**< Component IPC configuration */ struct tr_ctx tctx; /**< trace settings */ diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index 8dc5ea16d51d..a1a123842262 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -94,6 +94,8 @@ struct pipeline { bool aborted; /* STOP or PAUSE failed, stay active */ bool pending; /* trigger scheduled but not executed yet */ } trigger; + /* pipe can use long periods for scheduling in case of a deep buffering */ + bool deep_buffering; }; struct pipeline_walk_context { diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 91babe75b97d..e210b02fd528 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -18,7 +18,6 @@ #include #include #include -#include #include /* TODO: Remove platform-specific code, see https://github.com/thesofproject/sof/issues/7549 */ @@ -206,7 +205,8 @@ static int ipc4_create_pipeline(struct ipc4_pipeline_create *pipe_desc) } pipe->time_domain = SOF_TIME_DOMAIN_TIMER; - pipe->period = LL_TIMER_PERIOD_US; + pipe->period = 0; + pipe->deep_buffering = true; /* sched_id is set in FW so initialize it to a invalid value */ pipe->sched_id = 0xFFFFFFFF; @@ -869,6 +869,23 @@ int ipc4_add_comp_dev(struct comp_dev *dev) /* add new component to the list */ list_item_append(&icd->list, &ipc->comp_list); + /* If new component added to the pipeline is not fitted for deep buffering we need to + * inform pipeline it cannot work on long periods. + */ + if (!dev->deep_buffering) { + if (!dev->pipeline) { + const uint32_t pipe_id = dev->ipc_config.pipeline_id; + struct ipc_comp_dev *ipc_comp = + ipc_get_comp_by_ppl_id(ipc, + COMP_TYPE_PIPELINE, + pipe_id); + + dev->pipeline = ipc_comp->pipeline; + } + + dev->pipeline->deep_buffering = false; + } + return IPC4_SUCCESS; };