From 61f22ae69b58541402e2711187959da62554a003 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Thu, 26 Jan 2023 22:32:56 +0100 Subject: [PATCH 01/94] platform: ace: notifying about idle thread readiness Informing the primary core that the Idle thread on secondary core is ready. During the D3 exit flow thread is not initialize again, but restored from previously saved context. Signed-off-by: Tomasz Leman --- src/platform/intel/ace/platform.c | 9 +++++++++ zephyr/include/sof/lib/cpu.h | 10 ++++++++-- zephyr/lib/cpu.c | 16 +++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/platform/intel/ace/platform.c b/src/platform/intel/ace/platform.c index 86afbfa80fef..0fbf364931e2 100644 --- a/src/platform/intel/ace/platform.c +++ b/src/platform/intel/ace/platform.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -74,6 +75,11 @@ int platform_boot_complete(uint32_t boot_message) return ipc_platform_send_msg(&msg); } +static struct pm_notifier pm_state_notifier = { + .state_entry = NULL, + .state_exit = cpu_notify_state_exit, +}; + /* Runs on the primary core only */ int platform_init(struct sof *sof) { @@ -114,6 +120,9 @@ int platform_init(struct sof *sof) if (ret < 0) return ret; + /* register power states entry / exit notifiers */ + pm_notifier_register(&pm_state_notifier); + /* initialize the host IPC mechanisms */ trace_point(TRACE_BOOT_PLATFORM_IPC); ipc_init(sof); diff --git a/zephyr/include/sof/lib/cpu.h b/zephyr/include/sof/lib/cpu.h index 41328ee9ebe4..81a8840742b8 100644 --- a/zephyr/include/sof/lib/cpu.h +++ b/zephyr/include/sof/lib/cpu.h @@ -20,10 +20,16 @@ #include -//#include - #include +#if CONFIG_PM + +#include + +void cpu_notify_state_exit(enum pm_state state); + +#endif /* CONFIG_PM */ + /* let the compiler optimise when in single core mode */ #if CONFIG_MULTICORE && CONFIG_SMP diff --git a/zephyr/lib/cpu.c b/zephyr/lib/cpu.c index 882a7c8baf47..702845971271 100644 --- a/zephyr/lib/cpu.c +++ b/zephyr/lib/cpu.c @@ -59,12 +59,26 @@ static FUNC_NORETURN void secondary_init(void *arg) #if CONFIG_ZEPHYR_NATIVE_DRIVERS #include #include -#include LOG_MODULE_DECLARE(zephyr, CONFIG_SOF_LOG_LEVEL); extern struct tr_ctx zephyr_tr; +/* notifier called after every power state transition */ +void cpu_notify_state_exit(enum pm_state state) +{ + if (state == PM_STATE_SOFT_OFF) { +#if CONFIG_MULTICORE + if (!cpu_is_primary(arch_proc_id())) { + /* Notifying primary core that secondary core successfully exit the D3 + * state and is back in the Idle thread. + */ + atomic_set(&ready_flag, 1); + } +#endif + } +} + int cpu_enable_core(int id) { /* only called from single core, no RMW lock */ From d5e580521897f6ebedd53a8ea93858c9047131fb Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Thu, 30 Mar 2023 10:02:16 +0200 Subject: [PATCH 02/94] zephyr: cpu: secondary core idle thread init Idle thread should be initialize only when core it booting for the first time. Doing this again would overwrite the kernel structs and the idle thread stack. Signed-off-by: Tomasz Leman --- zephyr/lib/cpu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/zephyr/lib/cpu.c b/zephyr/lib/cpu.c index 702845971271..448697bfd6b8 100644 --- a/zephyr/lib/cpu.c +++ b/zephyr/lib/cpu.c @@ -93,7 +93,13 @@ int cpu_enable_core(int id) return 0; #if ZEPHYR_VERSION(3, 0, 99) <= ZEPHYR_VERSION_CODE - z_init_cpu(id); + /* During kernel initialization, the next pm state is set to ACTIVE. By checking this + * value, we determine if this is the first core boot, if not, we need to skip idle thread + * initialization. By reinitializing the idle thread, we would overwrite the kernel structs + * and the idle thread stack. + */ + if (pm_state_next_get(id)->state == PM_STATE_ACTIVE) + z_init_cpu(id); #endif atomic_clear(&start_flag); From 42b84272bc01070875a439911985c739f675b940 Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Wed, 16 Nov 2022 15:21:32 +0100 Subject: [PATCH 03/94] platform: ace: Add pm notifiers to support Zephyr's D3 transition During PowerOff (D3) transition Zephyr Power Manager must have a pointer in IMR to save the LP/HPSRAM memory before powering off. As zephyr has no access to IMR heap, the memory must be allocated by SOF Signed-off-by: Marcin Szkudlinski --- src/platform/intel/ace/platform.c | 71 ++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/src/platform/intel/ace/platform.c b/src/platform/intel/ace/platform.c index 0fbf364931e2..0118dcc4632a 100644 --- a/src/platform/intel/ace/platform.c +++ b/src/platform/intel/ace/platform.c @@ -25,6 +25,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -75,9 +79,72 @@ int platform_boot_complete(uint32_t boot_message) return ipc_platform_send_msg(&msg); } +/* address where zephyr PM will save memory during D3 transition */ +#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE +extern void *global_imr_ram_storage; +#endif + +/** + * @brief Notifier called before every power state transition. + * Works on Primary Core only. + * @param state Power state being entered. + */ +static void notify_pm_state_entry(enum pm_state state) +{ + if (!cpu_is_primary(arch_proc_id())) + return; + + if (state == PM_STATE_SOFT_OFF) { +#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE + size_t storage_buffer_size; + + /* allocate IMR global_imr_ram_storage */ + const struct device *tlb_dev = DEVICE_DT_GET(DT_NODELABEL(tlb)); + + __ASSERT_NO_MSG(tlb_dev); + const struct intel_adsp_tlb_api *tlb_api = + (struct intel_adsp_tlb_api *)tlb_dev->api; + + /* get HPSRAM storage buffer size */ + storage_buffer_size = tlb_api->get_storage_size(); + + /* add space for LPSRAM */ + storage_buffer_size += LP_SRAM_SIZE; + + /* allocate IMR buffer and store it in the global pointer */ + global_imr_ram_storage = rmalloc(SOF_MEM_ZONE_SYS, + 0, + SOF_MEM_CAPS_L3, + storage_buffer_size); +#endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */ + } +} + +/** + * @brief Notifier called after every power state transition. + * Works on Primary Core only. + * @param state Power state being exited. + */ +static void notify_pm_state_exit(enum pm_state state) +{ + if (!cpu_is_primary(arch_proc_id())) + return; + + if (state == PM_STATE_SOFT_OFF) { +#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE + /* free global_imr_ram_storage */ + rfree(global_imr_ram_storage); + global_imr_ram_storage = NULL; + + /* send FW Ready message */ + platform_boot_complete(0); +#endif + } +} + static struct pm_notifier pm_state_notifier = { - .state_entry = NULL, - .state_exit = cpu_notify_state_exit, + .state_entry = notify_pm_state_entry, + .state_exit = notify_pm_state_exit, }; /* Runs on the primary core only */ From de1d6c073782e8ee826c60ba49cb6e17d76f8691 Mon Sep 17 00:00:00 2001 From: Andrey Borisovich Date: Wed, 8 Feb 2023 13:36:38 +0100 Subject: [PATCH 04/94] ipc4: added D3 support using Zephyr Power Manager API Added IPC, timer and memory window power state change to and from D3 in the Zephyr Power Manager notifier functions. Added IPC4 callbacks 'suspend_handler' and 'resume_handler' to control Zepyr IPC driver. Co-developed-by: Tomasz Leman Signed-off-by: Tomasz Leman Signed-off-by: Andrey Borisovich --- src/ipc/ipc-zephyr.c | 63 +++++++++++++++++++++++++++++-- src/platform/intel/ace/platform.c | 33 +++++++++++++++- 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/src/ipc/ipc-zephyr.c b/src/ipc/ipc-zephyr.c index 975fa503ee4c..06f1fa3988bd 100644 --- a/src/ipc/ipc-zephyr.c +++ b/src/ipc/ipc-zephyr.c @@ -17,11 +17,15 @@ #include #include #include -#if defined(CONFIG_PM_POLICY_CUSTOM) +#if defined(CONFIG_PM) #include +#include +#include +#include +#include #else #include -#endif +#endif /* CONFIG_PM */ #include #include #include @@ -79,6 +83,51 @@ static bool message_handler(const struct device *dev, void *arg, uint32_t data, return false; } +#ifdef CONFIG_PM_DEVICE +/** + * @brief IPC device suspend handler callback function. + * Checks whether device power state should be actually changed. + * + * @param dev IPC device. + * @param arg IPC struct pointer. + */ +static int ipc_device_suspend_handler(const struct device *dev, void *arg) +{ + struct ipc *ipc = (struct ipc *)arg; + + /* we are not entering D3 - return error code bad message */ + if (!(ipc->task_mask & IPC_TASK_POWERDOWN)) + return -EBADMSG; + + return 0; +} + +/** + * @brief IPC device resume handler callback function. + * Resets IPC control after context restore. + * + * @param dev IPC device. + * @param arg IPC struct pointer. + */ +static int ipc_device_resume_handler(const struct device *dev, void *arg) +{ + struct ipc *ipc = (struct ipc *)arg; + + ipc_set_drvdata(ipc, NULL); + ipc->task_mask = 0; + ipc->pm_prepare_D3 = false; + + /* attach handlers */ + intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, message_handler, ipc); + + /* schedule task */ + schedule_task_init_edf(&ipc->ipc_task, SOF_UUID(ipc_task_uuid), + &ipc_task_ops, ipc, 0, 0); + + return 0; +} +#endif /* CONFIG_PM_DEVICE */ + #if CONFIG_DEBUG_IPC_COUNTERS static inline void increment_ipc_received_counter(void) @@ -130,7 +179,7 @@ enum task_state ipc_platform_do_cmd(struct ipc *ipc) if (ipc->task_mask & IPC_TASK_POWERDOWN || ipc_get()->pm_prepare_D3) { -#if defined(CONFIG_PM_POLICY_CUSTOM) +#if defined(CONFIG_PM) /** * @note For primary core this function * will only force set lower power state @@ -145,7 +194,7 @@ enum task_state ipc_platform_do_cmd(struct ipc *ipc) * powered off and IPC sent. */ platform_pm_runtime_power_off(); -#endif /* CONFIG_PM_POLICY_CUSTOM */ +#endif /* CONFIG_PM */ } return SOF_TASK_STATE_COMPLETED; @@ -188,6 +237,12 @@ int platform_ipc_init(struct ipc *ipc) /* attach handlers */ intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, message_handler, ipc); +#ifdef CONFIG_PM + intel_adsp_ipc_set_suspend_handler(INTEL_ADSP_IPC_HOST_DEV, + ipc_device_suspend_handler, ipc); + intel_adsp_ipc_set_resume_handler(INTEL_ADSP_IPC_HOST_DEV, + ipc_device_resume_handler, ipc); +#endif return 0; } diff --git a/src/platform/intel/ace/platform.c b/src/platform/intel/ace/platform.c index 0118dcc4632a..316343aabab6 100644 --- a/src/platform/intel/ace/platform.c +++ b/src/platform/intel/ace/platform.c @@ -28,7 +28,11 @@ #include #include #include -#include +#include +#include +#include +#include +#include #include #include @@ -84,6 +88,14 @@ int platform_boot_complete(uint32_t boot_message) extern void *global_imr_ram_storage; #endif +/* Reports error message during power state transitions */ +static void power_state_failure_report(int ret, bool enter, enum pm_state state) +{ + const char *action_name = enter ? "enter" : "leave"; + + __ASSERT(!ret, "Failed to %s power state: %d. Error: %d", action_name, state, ret); +} + /** * @brief Notifier called before every power state transition. * Works on Primary Core only. @@ -116,6 +128,13 @@ static void notify_pm_state_entry(enum pm_state state) 0, SOF_MEM_CAPS_L3, storage_buffer_size); + + /* change power state and check if IPC subsystem is prepared to enter D3 */ + int ret = pm_device_action_run(INTEL_ADSP_IPC_HOST_DEV, PM_DEVICE_ACTION_SUSPEND); + + if (ret) + power_state_failure_report(ret, true, PM_STATE_SOFT_OFF); + #endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */ } } @@ -136,7 +155,17 @@ static void notify_pm_state_exit(enum pm_state state) rfree(global_imr_ram_storage); global_imr_ram_storage = NULL; - /* send FW Ready message */ + int ret = pm_device_action_run(INTEL_ADSP_IPC_HOST_DEV, PM_DEVICE_ACTION_RESUME); + + if (ret) + power_state_failure_report(ret, false, PM_STATE_SOFT_OFF); + + enum pm_device_state ipc_state = PM_DEVICE_STATE_SUSPENDING; + + pm_device_state_get(INTEL_ADSP_IPC_HOST_DEV, &ipc_state); + __ASSERT_NO_MSG(ipc_state == PM_DEVICE_STATE_ACTIVE); + + /* sends fw-ready message signalling successful exit from D3 state */ platform_boot_complete(0); #endif } From 6c57b64b3494b371a60fa974ffebc03d7977decc Mon Sep 17 00:00:00 2001 From: Andrey Borisovich Date: Wed, 21 Dec 2022 11:25:49 +0100 Subject: [PATCH 05/94] board: intel_adsp_ace15_mtpm: Enabled MTL IMR context save Enabled CONFIG_ADSP_IMR_CONTEXT_SAVE option in Kconfig in the board configuration. Signed-off-by: Andrey Borisovich --- app/boards/intel_adsp_ace15_mtpm.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/boards/intel_adsp_ace15_mtpm.conf b/app/boards/intel_adsp_ace15_mtpm.conf index 2fd25da7db9f..69629e543ffa 100644 --- a/app/boards/intel_adsp_ace15_mtpm.conf +++ b/app/boards/intel_adsp_ace15_mtpm.conf @@ -20,6 +20,8 @@ CONFIG_PM_POLICY_CUSTOM=y CONFIG_POWER_DOMAIN=y CONFIG_POWER_DOMAIN_INTEL_ADSP=y +CONFIG_ADSP_IMR_CONTEXT_SAVE=y + # enable Zephyr drivers CONFIG_ZEPHYR_NATIVE_DRIVERS=y CONFIG_DAI=y From a88521d74eddad38b55d14bf50cf137270436c40 Mon Sep 17 00:00:00 2001 From: Krzysztof Frydryk Date: Fri, 24 Feb 2023 16:46:41 +0100 Subject: [PATCH 06/94] platform: register basefw CPS consumption on boot On init, register consumption of 10MCPS fot base fw Signed-off-by: Krzysztof Frydryk --- src/platform/intel/ace/platform.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/platform/intel/ace/platform.c b/src/platform/intel/ace/platform.c index 316343aabab6..e839ee7f900a 100644 --- a/src/platform/intel/ace/platform.c +++ b/src/platform/intel/ace/platform.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -176,6 +177,9 @@ static struct pm_notifier pm_state_notifier = { .state_exit = notify_pm_state_exit, }; +/* Value to be determined experimentaly */ +#define BASE_CPS_USAGE 10000 + /* Runs on the primary core only */ int platform_init(struct sof *sof) { @@ -183,13 +187,8 @@ int platform_init(struct sof *sof) trace_point(TRACE_BOOT_PLATFORM_CLOCK); platform_clock_init(sof); - - /* Set DSP clock to MAX using KCPS API. Value should be lowered when KCPS API - * for modules is implemented - */ - ret = core_kcps_adjust(cpu_get_id(), CLK_MAX_CPU_HZ / 1000); - if (ret < 0) - return ret; + kcps_budget_init(); + core_kcps_adjust(0, BASE_CPS_USAGE); trace_point(TRACE_BOOT_PLATFORM_SCHED); scheduler_init_edf(); From afd3dcdbba51a495f2bf1320b1279fe2da3a4c66 Mon Sep 17 00:00:00 2001 From: Krzysztof Frydryk Date: Fri, 24 Feb 2023 16:48:09 +0100 Subject: [PATCH 07/94] pipeline: Register and unregister pipelines CPS consumption on run/pause Register and unregister pipelines CPS consumption on run/pause Signed-off-by: Krzysztof Frydryk --- src/audio/pipeline/pipeline-stream.c | 99 +++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index ab60c11b3c16..2c8475f7b55d 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -24,6 +26,7 @@ #include LOG_MODULE_DECLARE(pipe, CONFIG_SOF_LOG_LEVEL); +// LOG_MODULE_REGISTER(cpsBudget, CONFIG_SOF_LOG_LEVEL); /* * Check whether pipeline is incapable of acquiring data for capture. @@ -266,24 +269,109 @@ static void pipeline_trigger_xrun(struct pipeline *p, struct comp_dev **host) } while (true); } +static int add_pipeline_cps_consumption(struct comp_dev *current, + struct comp_buffer *calling_buf, + struct pipeline_walk_context *ctx, int dir) +{ + struct pipeline_data *ppl_data = ctx->comp_data; + struct ipc4_base_module_cfg *cd = NULL; + + pipe_dbg(ppl_data->p, "pipeline_comp_complete(), current->comp.id = %u, dir = %u", + dev_comp_id(current), dir); + + if (!comp_is_single_pipeline(current, ppl_data->start)) { + pipe_dbg(ppl_data->p, "pipeline_comp_complete(), current is from another pipeline"); + return 0; + } + + /* complete component init */ + current->pipeline = ppl_data->p; + + /* modules created throug module adapter have different priv_data */ + if(current->drv->type != SOF_COMP_MODULE_ADAPTER) { + cd = comp_get_drvdata(current); + } else { + struct processing_module *mod = comp_get_drvdata(current); + struct module_data *md = &mod->priv; + cd = &md->cfg.base_cfg; + } + + int kcps = cd->cpc * 1000 / ppl_data->p->period; + core_kcps_adjust(0, kcps); + tr_err(pipe, "Registering KCPS consumption: %d, core: %d", kcps, ppl_data->p->core); + int summary_cps = core_kcps_get(0); + tr_err(pipe, "Sum of KCPS consumption: %d, core: %d", summary_cps, ppl_data->p->core); + return pipeline_for_each_comp(current, ctx, dir); +} + +static int remove_pipeline_cps_consumption(struct comp_dev *current, + struct comp_buffer *calling_buf, + struct pipeline_walk_context *ctx, int dir) +{ + struct pipeline_data *ppl_data = ctx->comp_data; + struct ipc4_base_module_cfg *cd = NULL; + + pipe_dbg(ppl_data->p, "pipeline_comp_complete(), current->comp.id = %u, dir = %u", + dev_comp_id(current), dir); + + if (!comp_is_single_pipeline(current, ppl_data->start)) { + pipe_dbg(ppl_data->p, "pipeline_comp_complete(), current is from another pipeline"); + return 0; + } + + /* complete component init */ + current->pipeline = ppl_data->p; + + /* modules created throug module adapter have different priv_data */ + if(current->drv->type != SOF_COMP_MODULE_ADAPTER) { + cd = comp_get_drvdata(current); + } else { + struct processing_module *mod = comp_get_drvdata(current); + struct module_data *md = &mod->priv; + cd = &md->cfg.base_cfg; + } + + int kcps = cd->cpc * 1000/ppl_data->p->period; + core_kcps_adjust(0, -kcps); /* 1000 chunks per second, so cpc value matches kcps? */ + tr_err(pipe, "Unregistering KCPS consumption: %d, core: %d", kcps, ppl_data->p->core); + int summary_cps = core_kcps_get(0); + tr_err(pipe, "Sum of KCPS consumption: %d, core: %d", summary_cps, ppl_data->p->core); + return pipeline_for_each_comp(current, ctx, dir); +} + + + + /* trigger pipeline in IPC context */ int pipeline_trigger(struct pipeline *p, struct comp_dev *host, int cmd) { int ret; - + bool clocks_handled = false; + struct pipeline_data data; + struct pipeline_walk_context walk_ctx = { + .comp_func = remove_pipeline_cps_consumption, + .comp_data = &data, + }; pipe_info(p, "pipe trigger cmd %d", cmd); p->trigger.aborted = false; switch (cmd) { case COMP_TRIGGER_PAUSE: + /* dirty - dont add kcps on fallthrough */ + clocks_handled = true; + /* setup walking ctx for adding consumption */ + data.start = p->source_comp; + data.p = p; + walk_ctx.comp_func = remove_pipeline_cps_consumption; + + ret = walk_ctx.comp_func(p->source_comp, NULL, &walk_ctx, PPL_DIR_DOWNSTREAM); case COMP_TRIGGER_STOP: if (p->status == COMP_STATE_PAUSED || p->xrun_bytes) { /* The task isn't running, trigger inline */ ret = pipeline_trigger_run(p, host, cmd); return ret < 0 ? ret : 0; } - COMPILER_FALLTHROUGH; case COMP_TRIGGER_XRUN: if (cmd == COMP_TRIGGER_XRUN) @@ -293,6 +381,13 @@ int pipeline_trigger(struct pipeline *p, struct comp_dev *host, int cmd) case COMP_TRIGGER_PRE_RELEASE: case COMP_TRIGGER_PRE_START: /* Add all connected pipelines to the list and trigger them all */ + /* setup walking ctx for removing consumption */ + data.start = p->source_comp; + data.p = p; + walk_ctx.comp_func = add_pipeline_cps_consumption; + + if(!clocks_handled) + ret = walk_ctx.comp_func(p->source_comp, NULL, &walk_ctx, PPL_DIR_DOWNSTREAM); ret = pipeline_trigger_list(p, host, cmd); if (ret < 0) return ret; From 38b4cb1475fb3f3828cbd7a117ec020ae2f57a12 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Mon, 6 Mar 2023 13:04:44 +0100 Subject: [PATCH 08/94] platform: mtl: lowest clock as default This patch sets lowest clock as default for Meteorlake platform. In current version FW does unnecessary clocks switching operations. FW should start from low value and scale-up if necessary. Signed-off-by: Tomasz Leman --- src/platform/meteorlake/include/platform/lib/clk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/meteorlake/include/platform/lib/clk.h b/src/platform/meteorlake/include/platform/lib/clk.h index 2eb1732aad55..e76a626e8a1a 100644 --- a/src/platform/meteorlake/include/platform/lib/clk.h +++ b/src/platform/meteorlake/include/platform/lib/clk.h @@ -24,7 +24,7 @@ #define CPU_LOWEST_FREQ_IDX CPU_WOVCRO_FREQ_IDX -#define CPU_DEFAULT_IDX CPU_HPRO_FREQ_IDX +#define CPU_DEFAULT_IDX CPU_LOWEST_FREQ_IDX #define SSP_DEFAULT_IDX 1 From 924f0d26db2cc68c819185dd42cd491de72f8b5d Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Fri, 10 Mar 2023 08:37:52 +0100 Subject: [PATCH 09/94] pipeline: print warning if 0 KCPS received This will clear cps error logs and print warning only if 0 KCPS received Signed-off-by: Adrian Bonislawski --- src/audio/pipeline/pipeline-stream.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index 2c8475f7b55d..1b2e8a1ddf24 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -297,10 +297,15 @@ static int add_pipeline_cps_consumption(struct comp_dev *current, } int kcps = cd->cpc * 1000 / ppl_data->p->period; - core_kcps_adjust(0, kcps); - tr_err(pipe, "Registering KCPS consumption: %d, core: %d", kcps, ppl_data->p->core); + if (kcps == 0) { + tr_warn(pipe, "0 KCPS for module: %#x, core: %d", current->ipc_config.id, ppl_data->p->core); + } else { + core_kcps_adjust(0, kcps); + tr_info(pipe, "Registering KCPS consumption: %d, core: %d", kcps, ppl_data->p->core); + } + int summary_cps = core_kcps_get(0); - tr_err(pipe, "Sum of KCPS consumption: %d, core: %d", summary_cps, ppl_data->p->core); + tr_info(pipe, "Sum of KCPS consumption: %d, core: %d", summary_cps, ppl_data->p->core); return pipeline_for_each_comp(current, ctx, dir); } @@ -333,9 +338,9 @@ static int remove_pipeline_cps_consumption(struct comp_dev *current, int kcps = cd->cpc * 1000/ppl_data->p->period; core_kcps_adjust(0, -kcps); /* 1000 chunks per second, so cpc value matches kcps? */ - tr_err(pipe, "Unregistering KCPS consumption: %d, core: %d", kcps, ppl_data->p->core); + tr_info(pipe, "Unregistering KCPS consumption: %d, core: %d", kcps, ppl_data->p->core); int summary_cps = core_kcps_get(0); - tr_err(pipe, "Sum of KCPS consumption: %d, core: %d", summary_cps, ppl_data->p->core); + tr_info(pipe, "Sum of KCPS consumption: %d, core: %d", summary_cps, ppl_data->p->core); return pipeline_for_each_comp(current, ctx, dir); } From 010746170da9707ca73b0663747a44d0e08ca8db Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Wed, 1 Mar 2023 12:48:26 +0100 Subject: [PATCH 10/94] ace: pm_runtime: force L1 exit if requested IMPORTANT: PM part should be moved to zephyr! This will add possibility to force host L1 exit Signed-off-by: Adrian Bonislawski --- src/audio/host-zephyr.c | 24 ++++++++++++- zephyr/lib/pm_runtime.c | 79 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index cda7cf8a79f3..e33246ab5a12 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -467,6 +468,9 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev) if (!copy_bytes) return 0; + /* Register Host DMA usage */ + pm_runtime_get(PM_RUNTIME_HOST_DMA_L1, 0); + struct dma_cb_data next = { .channel = hd->chan, .elem = { .size = copy_bytes }, @@ -537,6 +541,12 @@ static int create_local_elems(struct host_data *hd, struct comp_dev *dev, uint32 return 0; } +static void hda_dma_l1_exit_notify(void *arg, enum notify_id type, void *data) +{ + /* Force Host DMA to exit L1 if needed */ + pm_runtime_put(PM_RUNTIME_HOST_DMA_L1, 0); +} + /** * \brief Command handler. * \param[in,out] dev Device @@ -569,6 +579,10 @@ int host_zephyr_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) if (ret < 0) comp_err(dev, "host_trigger(): dma_start() failed, ret = %u", ret); + /* Register common L1 exit for all channels */ + ret = notifier_register(NULL, scheduler_get_data(SOF_SCHEDULE_LL_TIMER), + NOTIFIER_ID_LL_POST_RUN, hda_dma_l1_exit_notify, + NOTIFIER_FLAG_AGGREGATE); break; case COMP_TRIGGER_STOP: case COMP_TRIGGER_XRUN: @@ -577,6 +591,9 @@ int host_zephyr_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) if (ret < 0) comp_err(dev, "host_trigger(): dma stop failed: %d", ret); + /* Unregister L1 exit */ + notifier_unregister(NULL, scheduler_get_data(SOF_SCHEDULE_LL_TIMER), + NOTIFIER_ID_LL_POST_RUN); } break; @@ -1033,8 +1050,13 @@ static int host_position(struct comp_dev *dev, void host_zephyr_reset(struct host_data *hd, uint16_t state) { if (hd->chan) { - if (state == COMP_STATE_ACTIVE) + if (state == COMP_STATE_ACTIVE) { dma_stop(hd->chan->dma->z_dev, hd->chan->index); + /* Unregister L1 exit */ + notifier_unregister(NULL, scheduler_get_data(SOF_SCHEDULE_LL_TIMER), + NOTIFIER_ID_LL_POST_RUN); + } + dma_release_channel(hd->dma->z_dev, hd->chan->index); hd->chan = NULL; } diff --git a/zephyr/lib/pm_runtime.c b/zephyr/lib/pm_runtime.c index ab8adea565c0..36ff254b9d9d 100644 --- a/zephyr/lib/pm_runtime.c +++ b/zephyr/lib/pm_runtime.c @@ -9,6 +9,12 @@ #include #include #include +#include +#include +#include + +#include +#include #include LOG_MODULE_REGISTER(power, CONFIG_SOF_LOG_LEVEL); @@ -19,6 +25,11 @@ DECLARE_SOF_UUID("power", power_uuid, 0x76cc9773, 0x440c, 0x4df9, DECLARE_TR_CTX(power_tr, SOF_UUID(power_uuid), LOG_LEVEL_INFO); +/** \brief ACE specific runtime power management data. */ +struct ace_pm_runtime_data { + int host_dma_l1_sref; /**< ref counter for Host DMA accesses */ +}; + #if defined(CONFIG_PM_POLICY_CUSTOM) const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks) { @@ -93,16 +104,78 @@ void platform_pm_runtime_disable(uint32_t context, uint32_t index) } } +/** + * \brief Registers Host DMA usage that should not trigger + * transition to L0 via forced L1 exit. + */ +static void ace_pm_runtime_host_dma_l1_get(void) +{ + struct pm_runtime_data *prd = pm_runtime_data_get(); + struct ace_pm_runtime_data *pprd = prd->platform_data; + k_spinlock_key_t key; + + key = k_spin_lock(&prd->lock); + + pprd->host_dma_l1_sref++; + + k_spin_unlock(&prd->lock, key); +} + +/** + * \brief Releases Host DMA usage preventing L1 exit. If this + * the last user, forced L1 exit is performed. + */ +static inline void ace_pm_runtime_host_dma_l1_put(void) +{ + struct pm_runtime_data *prd = pm_runtime_data_get(); + struct ace_pm_runtime_data *pprd = prd->platform_data; + k_spinlock_key_t key; + + key = k_spin_lock(&prd->lock); + + if (pprd->host_dma_l1_sref) { + ACE_DfPMCCH.svcfg |= ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT; + wait_delay(ADSP_FORCE_L1_EXIT_TIME); + ACE_DfPMCCH.svcfg &= ~(ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT); + } + pprd->host_dma_l1_sref = 0; + + k_spin_unlock(&prd->lock, key); +} + void platform_pm_runtime_init(struct pm_runtime_data *prd) -{ } +{ + struct ace_pm_runtime_data *pprd; + + pprd = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*pprd)); + prd->platform_data = pprd; +} void platform_pm_runtime_get(enum pm_runtime_context context, uint32_t index, uint32_t flags) -{ } +{ + /* Action based on context */ + switch (context) { + case PM_RUNTIME_HOST_DMA_L1: + ace_pm_runtime_host_dma_l1_get(); + break; + default: + break; + } +} void platform_pm_runtime_put(enum pm_runtime_context context, uint32_t index, uint32_t flags) -{ } +{ + /* Action based on context */ + switch (context) { + case PM_RUNTIME_HOST_DMA_L1: + ace_pm_runtime_host_dma_l1_put(); + break; + default: + break; + } +} void platform_pm_runtime_prepare_d0ix_en(uint32_t index) { } From 124e61e3e1ddc27185e4b75d390cb06f5523cbdc Mon Sep 17 00:00:00 2001 From: "Dobrowolski, PawelX" Date: Thu, 9 Mar 2023 11:42:14 +0100 Subject: [PATCH 11/94] loadable module: module api version structure Building system for iadk modules and for native sof modules has built in information about used api. That information we use to switch between two different methods of registering modules. Signed-off-by: Dobrowolski, PawelX --- .../module_adapter/library/module_api_ver.h | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/include/sof/audio/module_adapter/library/module_api_ver.h diff --git a/src/include/sof/audio/module_adapter/library/module_api_ver.h b/src/include/sof/audio/module_adapter/library/module_api_ver.h new file mode 100644 index 000000000000..842f3a42e3f1 --- /dev/null +++ b/src/include/sof/audio/module_adapter/library/module_api_ver.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Pawel Dobrowolski + */ + +#ifndef __MODULE_API_VER_H__ +#define __MODULE_API_VER_H__ + +/* + * Api version 5.0.0 for sof loadable modules + */ + +#define _MAJOR_API_MODULE_VERSION 5 +#define _MIDDLE_API_MODULE_VERSION 0 +#define _MINOR_API_MODULE_VERSION 0 + +typedef union sof_module_api_version { + uint32_t full; + struct { + uint32_t minor : 10; + uint32_t middle : 10; + uint32_t major : 10; + uint32_t reserved : 2; + } fields; +} sof_module_api_version; + +typedef const struct { + uint32_t format; + sof_module_api_version api_version_number; +} sof_module_build_info; + +#endif /* __MODULE_API_VER_H__ */ From 8e4f38378c67e22326fda61c8079c6adb7f3158e Mon Sep 17 00:00:00 2001 From: "Dobrowolski, PawelX" Date: Thu, 2 Feb 2023 15:30:56 +0100 Subject: [PATCH 12/94] module_adapter: native_system_agent: Introduce call and interface This is part of fw which helps loaded module in communication with adsp Also it provides basic operations for creation of component driver Signed-off-by: Dobrowolski, PawelX --- .../library/native_system_agent.c | 71 +++++++++++++++++++ .../library/native_system_agent.h | 27 +++++++ .../sof/audio/module_adapter/module/generic.h | 3 + zephyr/CMakeLists.txt | 2 + 4 files changed, 103 insertions(+) create mode 100644 src/audio/module_adapter/library/native_system_agent.c create mode 100644 src/include/sof/audio/module_adapter/library/native_system_agent.h diff --git a/src/audio/module_adapter/library/native_system_agent.c b/src/audio/module_adapter/library/native_system_agent.c new file mode 100644 index 000000000000..8d932320ef05 --- /dev/null +++ b/src/audio/module_adapter/library/native_system_agent.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Pawel Dobrowolski + */ + +#include +#include +#include +#include + +/* The create_instance_f is a function call type known in module. The module entry_point + * points to this type of function which starts module creation. + */ + +void SystemServiceLogMessage(AdspLogPriority log_priority, uint32_t log_entry, + AdspLogHandle const *log_handle, uint32_t param1, + uint32_t param2, uint32_t param3, uint32_t param4); + +AdspErrorCode SystemServiceSafeMemcpy(void *RESTRICT dst, size_t maxlen, + const void *RESTRICT src, size_t len); + +AdspErrorCode SystemServiceSafeMemmove(void *dst, size_t maxlen, + const void *src, size_t len); + +void *SystemServiceVecMemset(void *dst, int c, size_t len); + +AdspErrorCode SystemServiceCreateNotification(NotificationParams *params, + uint8_t *notification_buffer, + uint32_t notification_buffer_size, + AdspNotificationHandle *handle); + +AdspErrorCode SystemServiceSendNotificationMessage(NotificationTarget notification_target, + AdspNotificationHandle message, + uint32_t actual_payload_size); + +AdspErrorCode SystemServiceGetInterface(AdspIfaceId id, SystemServiceIface **iface); + +typedef void* (*native_create_instance_f)(void *mod_cfg, void *parent_ppl, + void **mod_ptr); + +struct native_system_agent native_sys_agent = { + .system_service = { + .LogMessage = SystemServiceLogMessage, + .SafeMemcpy = SystemServiceSafeMemcpy, + .SafeMemmove = SystemServiceSafeMemmove, + .VecMemset = SystemServiceVecMemset, + .NotificationCreate = SystemServiceCreateNotification, + .NotificationSend = SystemServiceSendNotificationMessage, + .GetInterface = SystemServiceGetInterface + }, + }; + +void *native_system_agent_start(struct adsp_system_service **sys_service, uint32_t entry_point, + uint32_t module_id, uint32_t instance_id, + uint32_t core_id, uint32_t log_handle, void *mod_cfg) +{ + native_sys_agent.module_id = module_id; + native_sys_agent.instance_id = instance_id; + native_sys_agent.core_id = core_id; + native_sys_agent.log_handle = log_handle; + + void *system_agent_p = &native_sys_agent; + + *sys_service = &native_sys_agent.system_service; + + native_create_instance_f ci = (native_create_instance_f)(entry_point); + + return ci(mod_cfg, NULL, &system_agent_p); +} diff --git a/src/include/sof/audio/module_adapter/library/native_system_agent.h b/src/include/sof/audio/module_adapter/library/native_system_agent.h new file mode 100644 index 000000000000..8ddac301d5e5 --- /dev/null +++ b/src/include/sof/audio/module_adapter/library/native_system_agent.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Pawel Dobrowolski + */ + +#ifndef __NATIVE_SYSTEM_AGENT_H__ +#define __NATIVE_SYSTEM_AGENT_H__ + +#include +#include + +struct native_system_agent { + AdspSystemService system_service; + uint32_t log_handle; + uint32_t core_id; + uint32_t module_id; + uint32_t instance_id; + uint32_t module_size; +}; + +void *native_system_agent_start(struct adsp_system_service **sys_service, uint32_t entry_point, + uint32_t module_id, uint32_t instance_id, uint32_t core_id, + uint32_t log_handle, void *mod_cfg); + +#endif /* __NATIVE_SYSTEM_AGENT_H__ */ diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index a12e7f857f4e..3dc8989bacb6 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -207,6 +207,9 @@ struct processing_module { */ bool skip_src_buffer_invalidate; + /* pointer to system services for loadable modules */ + struct adsp_system_service *sys_service; + /* table containing the list of connected sources */ struct module_source_info *source_info; }; diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 8e8ec41bde37..813f6550c4f2 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -539,6 +539,7 @@ zephyr_library_sources_ifdef(CONFIG_LIBRARY_MANAGER zephyr_include_directories_ifdef(CONFIG_INTEL_MODULES ${SOF_SRC_PATH}/include/sof/audio/module_adapter/iadk/ + ${SOF_SRC_PATH}/include/sof/audio/module_adapter/library/ ) zephyr_library_sources_ifdef(CONFIG_INTEL_MODULES @@ -547,6 +548,7 @@ zephyr_library_sources_ifdef(CONFIG_INTEL_MODULES ${SOF_AUDIO_PATH}/module_adapter/iadk/module_initial_settings_concrete.cpp ${SOF_AUDIO_PATH}/module_adapter/iadk/iadk_module_adapter.cpp ${SOF_AUDIO_PATH}/module_adapter/iadk/system_agent.cpp + ${SOF_AUDIO_PATH}/module_adapter/library/native_system_agent.c ) if (CONFIG_COMP_MODULE_ADAPTER) From e4a3f9cc2c460a0288da5e21b7a63e49d5db0303 Mon Sep 17 00:00:00 2001 From: "Dobrowolski, PawelX" Date: Tue, 31 Jan 2023 09:34:16 +0100 Subject: [PATCH 13/94] iadk_modules: module_init: checking type of module In manifest is information about version of API and depending on it we load IADK or SOF module. Flag is showing if module is loadable. According to this information different api is being used in loading module. Signed-off-by: Dobrowolski, PawelX --- .../module_adapter/module/iadk_modules.c | 101 ++++++++++++++++-- .../sof/audio/module_adapter/module/generic.h | 3 + .../module_adapter/module/iadk_modules.h | 7 +- 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/src/audio/module_adapter/module/iadk_modules.c b/src/audio/module_adapter/module/iadk_modules.c index 8c728bba5594..81e8fdb56cf9 100644 --- a/src/audio/module_adapter/module/iadk_modules.c +++ b/src/audio/module_adapter/module/iadk_modules.c @@ -8,7 +8,10 @@ #include #include #include +#include #include +#include +#include /* Intel module adapter is an extension to SOF module adapter component that allows to integrate * modules developed under IADK (Intel Audio Development Kit) Framework. IADK modules uses uniform @@ -80,8 +83,32 @@ static int iadk_modules_init(struct processing_module *mod) uint32_t instance_id = IPC4_INST_ID(mod->dev->ipc_config.id); uint32_t log_handle = (uint32_t) mod->dev->drv->tctx; /* Connect loadable module interfaces with module adapter entity. */ - void *mod_adp = system_agent_start(md->module_entry_point, module_id, - instance_id, 0, log_handle, &mod_cfg); + /* Check if native Zephyr lib is loaded */ + struct sof_man_fw_desc *desc; + + desc = lib_manager_get_library_module_desc(module_id); + if (!desc) { + comp_err(dev, "iadk_modules_init(): Failed to load manifest"); + return -ENOMEM; + } + struct sof_man_module *module_entry = + (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(0)); + + sof_module_build_info *mod_buildinfo = + (sof_module_build_info *)(module_entry->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr); + + void *mod_adp; + + /* Check if module is FDK*/ + if (mod_buildinfo->api_version_number.fields.major < _MAJOR_API_MODULE_VERSION) { + mod_adp = system_agent_start(md->module_entry_point, module_id, + instance_id, 0, log_handle, &mod_cfg); + } else { + /* If not start agent for sof loadable */ + mod->is_native_sof = true; + mod_adp = native_system_agent_start(&mod->sys_service, md->module_entry_point, module_id, instance_id, + 0, log_handle, &mod_cfg); + } md->module_adapter = mod_adp; @@ -102,7 +129,14 @@ static int iadk_modules_init(struct processing_module *mod) md->mpd.out_buff_size = src_cfg->obs; /* Call module specific init function if exists. */ - ret = iadk_wrapper_init(md->module_adapter); + if (mod->is_native_sof) { + struct module_interface *mod_in = + (struct module_interface *)md->module_adapter; + + ret = mod_in->init(mod); + } else { + ret = iadk_wrapper_init(md->module_adapter); + } return ret; } @@ -125,8 +159,15 @@ static int iadk_modules_prepare(struct processing_module *mod) comp_info(dev, "iadk_modules_prepare()"); /* Call module specific prepare function if exists. */ - ret = iadk_wrapper_prepare(mod->priv.module_adapter); - return 0; + if (mod->is_native_sof) { + struct module_interface *mod_in = + (struct module_interface *)mod->priv.module_adapter; + + ret = mod_in->prepare(mod); + } else { + ret = iadk_wrapper_prepare(mod->priv.module_adapter); + } + return ret; } static int iadk_modules_init_process(struct processing_module *mod) @@ -171,10 +212,17 @@ static int iadk_modules_process(struct processing_module *mod, i++; } /* Call module specific process function. */ - ret = iadk_wrapper_process(mod->priv.module_adapter, - input_buffers, num_input_buffers, - output_buffers, num_output_buffers); - + if (mod->is_native_sof) { + struct module_interface *mod_in = + (struct module_interface *)mod->priv.module_adapter; + + ret = mod_in->process(mod, input_buffers, num_input_buffers, output_buffers, + num_output_buffers); + } else { + ret = iadk_wrapper_process(mod->priv.module_adapter, input_buffers, + num_input_buffers, output_buffers, + num_output_buffers); + } return ret; } @@ -193,7 +241,14 @@ static int iadk_modules_free(struct processing_module *mod) int ret = 0; comp_info(dev, "iadk_modules_free()"); - ret = iadk_wrapper_free(mod->priv.module_adapter); + if (mod->is_native_sof) { + struct module_interface *mod_in = + (struct module_interface *)mod->priv.module_adapter; + + ret = mod_in->free(mod); + } else { + ret = iadk_wrapper_free(mod->priv.module_adapter); + } rfree(md->mpd.in_buff); rfree(md->mpd.out_buff); @@ -226,6 +281,13 @@ static int iadk_modules_set_configuration(struct processing_module *mod, uint32_ size_t fragment_size, uint8_t *response, size_t response_size) { + if (mod->is_native_sof) { + struct module_interface *mod_in = + (struct module_interface *)mod->priv.module_adapter; + + return mod_in->set_configuration(mod, config_id, pos, data_offset_size, fragment, + fragment_size, response, response_size); + } return iadk_wrapper_set_configuration(mod->priv.module_adapter, config_id, pos, data_offset_size, fragment, fragment_size, response, response_size); @@ -247,6 +309,13 @@ static int iadk_modules_get_configuration(struct processing_module *mod, uint32_ uint32_t *data_offset_size, uint8_t *fragment, size_t fragment_size) { + if (mod->is_native_sof) { + struct module_interface *mod_in = + (struct module_interface *)mod->priv.module_adapter; + + return mod_in->get_configuration(mod, config_id, data_offset_size, + fragment, fragment_size); + } return iadk_wrapper_get_configuration(mod->priv.module_adapter, config_id, MODULE_CFG_FRAGMENT_SINGLE, *data_offset_size, fragment, fragment_size); @@ -262,6 +331,12 @@ static int iadk_modules_get_configuration(struct processing_module *mod, uint32_ static int iadk_modules_set_processing_mode(struct processing_module *mod, enum module_processing_mode mode) { + if (mod->is_native_sof) { + struct module_interface *mod_in = + (struct module_interface *)mod->priv.module_adapter; + + return mod_in->set_processing_mode(mod, mode); + } return iadk_wrapper_set_processing_mode(mod->priv.module_adapter, mode); } @@ -285,6 +360,12 @@ static enum module_processing_mode iadk_modules_get_processing_mode(struct proce */ static int iadk_modules_reset(struct processing_module *mod) { + if (mod->is_native_sof) { + struct module_interface *mod_in = + (struct module_interface *)mod->priv.module_adapter; + + return mod_in->reset(mod); + } return iadk_wrapper_reset(mod->priv.module_adapter); } diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index 3dc8989bacb6..b8e885e41576 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -207,6 +207,9 @@ struct processing_module { */ bool skip_src_buffer_invalidate; + /* flag to insure that module is loadable */ + bool is_native_sof; + /* pointer to system services for loadable modules */ struct adsp_system_service *sys_service; diff --git a/src/include/sof/audio/module_adapter/module/iadk_modules.h b/src/include/sof/audio/module_adapter/module/iadk_modules.h index 712b85d55d44..d2718652d219 100644 --- a/src/include/sof/audio/module_adapter/module/iadk_modules.h +++ b/src/include/sof/audio/module_adapter/module/iadk_modules.h @@ -11,7 +11,8 @@ #include /* Intel module adapter is an extension to SOF module adapter component that allows to integrate - * modules developed under IADK (Intel Audio Development Kit) Framework. IADK modules uses uniform + * modules developed under IADK (Intel Audio Development Kit) + * and LMDK (Loadable Modules Dev Kit) Framework. Modules uses uniform * set of interfaces and are linked into separate library. These modules are loaded in runtime * through library_manager and then after registration into SOF component infrastructure are * interfaced through module adapter API. @@ -32,6 +33,10 @@ * connect both sides of ProcessingModuleInterface and System Service. * - System Service - exposes of SOF base FW services to the module. * - Processing Module Adapter - SOF base FW side of ProcessingModuleInterface API + * + * Using the same philosofy loadable modules are using module adapter to interact with SOF FW. + * Module recognision is done by checking module API version defined in module_api_ver.h + * with version read from elf file. */ From c6b99e83f9def9cc57cc3069b94f21020b725762 Mon Sep 17 00:00:00 2001 From: "Dobrowolski, PawelX" Date: Thu, 9 Mar 2023 15:16:29 +0100 Subject: [PATCH 14/94] change AdspSystemService to adsp_system_service Code reafactor due to wrong text formatting Signed-off-by: Dobrowolski, PawelX --- src/audio/module_adapter/iadk/system_agent.cpp | 2 +- src/audio/module_adapter/module/iadk_modules.c | 6 +++--- src/include/sof/audio/module_adapter/iadk/logger.h | 4 ++-- .../sof/audio/module_adapter/iadk/system_agent.h | 2 +- .../sof/audio/module_adapter/iadk/system_service.h | 10 +++++----- .../audio/module_adapter/library/native_system_agent.h | 2 +- .../sof/audio/module_adapter/module/iadk_modules.h | 7 ++++--- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/audio/module_adapter/iadk/system_agent.cpp b/src/audio/module_adapter/iadk/system_agent.cpp index 6e03a065d49f..b739501017a5 100644 --- a/src/audio/module_adapter/iadk/system_agent.cpp +++ b/src/audio/module_adapter/iadk/system_agent.cpp @@ -63,7 +63,7 @@ namespace system { /* Structure storing handles to system service operations */ -AdspSystemService SystemAgent::system_service_ = { +adsp_system_service SystemAgent::system_service_ = { SystemServiceLogMessage, SystemServiceSafeMemcpy, SystemServiceSafeMemmove, diff --git a/src/audio/module_adapter/module/iadk_modules.c b/src/audio/module_adapter/module/iadk_modules.c index 81e8fdb56cf9..5e915fce6380 100644 --- a/src/audio/module_adapter/module/iadk_modules.c +++ b/src/audio/module_adapter/module/iadk_modules.c @@ -26,9 +26,9 @@ * Therefore C++ function, structures and variables definition are here kept with original form from * IADK Framework. This provides binary compatibility for already developed 3rd party modules. * - * Since IADK modules uses ProcessingModuleInterface to control/data transfer and AdspSystemService - * to use base FW services from internal module code, there is a communication shim layer defined - * in intel directory. + * Since IADK modules uses ProcessingModuleInterface to control/data transfer + * and adsp_system_service to use base FW services from internal module code, + * there is a communication shim layer defined in intel directory. * * Since ProcessingModuleInterface consists of virtual functions, there are C++ -> C wrappers * defined to access the interface calls from SOF code. diff --git a/src/include/sof/audio/module_adapter/iadk/logger.h b/src/include/sof/audio/module_adapter/iadk/logger.h index dc97f321ae06..89f8666595ec 100644 --- a/src/include/sof/audio/module_adapter/iadk/logger.h +++ b/src/include/sof/audio/module_adapter/iadk/logger.h @@ -21,7 +21,7 @@ class Logger { public: /*! \cond INTERNAL */ - Logger(AdspSystemService const &system_service, AdspLogHandle const &log_handle) + Logger(adsp_system_service const &system_service, AdspLogHandle const &log_handle) : system_service_(system_service), log_handle_(log_handle) @@ -38,7 +38,7 @@ class Logger /*! \endcond INTERNAL */ private: - AdspSystemService const &system_service_; + adsp_system_service const &system_service_; AdspLogHandle const &log_handle_; }; diff --git a/src/include/sof/audio/module_adapter/iadk/system_agent.h b/src/include/sof/audio/module_adapter/iadk/system_agent.h index 7c44845f044e..d5f32730b1b8 100644 --- a/src/include/sof/audio/module_adapter/iadk/system_agent.h +++ b/src/include/sof/audio/module_adapter/iadk/system_agent.h @@ -55,7 +55,7 @@ namespace system } private: - static AdspSystemService system_service_; + static adsp_system_service system_service_; uint32_t log_handle_; uint32_t const core_id_; uint32_t module_id_; diff --git a/src/include/sof/audio/module_adapter/iadk/system_service.h b/src/include/sof/audio/module_adapter/iadk/system_service.h index 63cf84913612..1b6d15bbdefe 100644 --- a/src/include/sof/audio/module_adapter/iadk/system_service.h +++ b/src/include/sof/audio/module_adapter/iadk/system_service.h @@ -167,14 +167,14 @@ typedef struct _SystemServiceIface {} SystemServiceIface; */ typedef AdspErrorCode (*SystemServiceGetInterfaceFct) (AdspIfaceId id, SystemServiceIface **iface); -/*! \brief The AdspSystemService is actually a set of C-function pointers gathered in a C-struct +/*! \brief The adsp_system_service is actually a set of C-function pointers gathered in a C-struct * which brings some basic functionalities to module in runtime. * * The system service can be retrieved with help of either the * intel_adsp::ProcessingModuleFactory::GetSystemService() method * or the intel_adsp::ProcessingModule::GetSysstemService() method. */ -typedef struct AdspSystemService { +typedef struct adsp_system_service { /*! The SystemService::LogMessage function provides capability to send some log message to * the host for debugging purposes. This log can be caught by the FDK Tools and displayed * in the Debug window. The prototype of this function is given by the @@ -223,14 +223,14 @@ typedef struct AdspSystemService { */ const SystemServiceGetInterfaceFct GetInterface; -} AdspSystemService; +} adsp_system_service; #ifdef __cplusplus namespace intel_adsp { -/*! \brief Alias type of AdspSystemService which can be used in C++. +/*! \brief Alias type of adsp_system_service which can be used in C++. */ -struct SystemService : public AdspSystemService {}; +struct SystemService : public adsp_system_service {}; } #endif diff --git a/src/include/sof/audio/module_adapter/library/native_system_agent.h b/src/include/sof/audio/module_adapter/library/native_system_agent.h index 8ddac301d5e5..edaa8ad0d040 100644 --- a/src/include/sof/audio/module_adapter/library/native_system_agent.h +++ b/src/include/sof/audio/module_adapter/library/native_system_agent.h @@ -12,7 +12,7 @@ #include struct native_system_agent { - AdspSystemService system_service; + adsp_system_service system_service; uint32_t log_handle; uint32_t core_id; uint32_t module_id; diff --git a/src/include/sof/audio/module_adapter/module/iadk_modules.h b/src/include/sof/audio/module_adapter/module/iadk_modules.h index d2718652d219..3acdb40581b8 100644 --- a/src/include/sof/audio/module_adapter/module/iadk_modules.h +++ b/src/include/sof/audio/module_adapter/module/iadk_modules.h @@ -16,9 +16,10 @@ * set of interfaces and are linked into separate library. These modules are loaded in runtime * through library_manager and then after registration into SOF component infrastructure are * interfaced through module adapter API. - * Since IADK modules uses ProcessingModuleInterface to control/data transfer and AdspSystemService - * to use base FW services from internal module code, there is a communication shim layer defined - * in intel directory. + * + * Since IADK modules uses ProcessingModuleInterface to control/data transfer + * and adsp_system_service to use base FW services from internal module code, + * there is a communication shim layer defined in intel directory. * * Since ProcessingModuleInterface consists of virtual functions, there are C++ -> C wrappers * defined to access the interface calls from SOF code. From 5ad91a29216397b124366ebe0d2d6062450a0a63 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Thu, 30 Mar 2023 18:12:29 +0200 Subject: [PATCH 15/94] LMDK: Loadable Modules Dev Kit build scripts Initial commit with set of cmake and linker scripts to build loadable modules binary. Things yet TODO: add all necessary Dev Kit header files to include dir, replace dummy example with somewhat useful module example. Signed-off-by: Serhiy Katsyuba --- lmdk/README.md | 15 ++++ lmdk/cmake/build.cmake | 53 ++++++++++++ lmdk/cmake/config.cmake | 25 ++++++ lmdk/cmake/ldscripts.cmake | 49 +++++++++++ lmdk/cmake/ldscripts/bss_linker_script.txt | 20 +++++ .../ldscripts/common_rodata_linker_script.txt | 38 ++++++++ .../ldscripts/common_text_linker_script.txt | 24 ++++++ lmdk/cmake/ldscripts/data_linker_script.txt | 30 +++++++ lmdk/cmake/ldscripts/guard_linker_script.txt | 12 +++ .../memory_header_linker_script.txt.in | 8 ++ lmdk/cmake/ldscripts/text_linker_script.txt | 31 +++++++ lmdk/cmake/ldscripts/xt_linker_script.txt | 55 ++++++++++++ lmdk/cmake/xtensa-toolchain.cmake | 25 ++++++ lmdk/include/todo.txt | 1 + lmdk/libraries/dummy/CMakeLists.txt | 19 ++++ lmdk/libraries/dummy/dummy_mtl.toml | 86 +++++++++++++++++++ lmdk/modules/dummy/CMakeLists.txt | 6 ++ lmdk/modules/dummy/dummy.c | 56 ++++++++++++ 18 files changed, 553 insertions(+) create mode 100644 lmdk/README.md create mode 100644 lmdk/cmake/build.cmake create mode 100644 lmdk/cmake/config.cmake create mode 100644 lmdk/cmake/ldscripts.cmake create mode 100644 lmdk/cmake/ldscripts/bss_linker_script.txt create mode 100644 lmdk/cmake/ldscripts/common_rodata_linker_script.txt create mode 100644 lmdk/cmake/ldscripts/common_text_linker_script.txt create mode 100644 lmdk/cmake/ldscripts/data_linker_script.txt create mode 100644 lmdk/cmake/ldscripts/guard_linker_script.txt create mode 100644 lmdk/cmake/ldscripts/memory_header_linker_script.txt.in create mode 100644 lmdk/cmake/ldscripts/text_linker_script.txt create mode 100644 lmdk/cmake/ldscripts/xt_linker_script.txt create mode 100644 lmdk/cmake/xtensa-toolchain.cmake create mode 100644 lmdk/include/todo.txt create mode 100644 lmdk/libraries/dummy/CMakeLists.txt create mode 100644 lmdk/libraries/dummy/dummy_mtl.toml create mode 100644 lmdk/modules/dummy/CMakeLists.txt create mode 100644 lmdk/modules/dummy/dummy.c diff --git a/lmdk/README.md b/lmdk/README.md new file mode 100644 index 000000000000..5d8b4b3037c2 --- /dev/null +++ b/lmdk/README.md @@ -0,0 +1,15 @@ +# Loadable Modules Dev Kit + +***TODO: add link to the documentation repo!*** + +To build dummy loadable library execute: + + cd libraries/dummy + mkdir build + cd build + + cmake -DRIMAGE_COMMAND="/path/to/rimage" -DSIGNING_KEY="/path/to/signing/key.pem" .. + cmake --build . + +Here RIMAGE_COMMAND is path to rimage executable binary, SIGNING_KEY is path to +signing key for rimage. diff --git a/lmdk/cmake/build.cmake b/lmdk/cmake/build.cmake new file mode 100644 index 000000000000..ba6d5d0427e0 --- /dev/null +++ b/lmdk/cmake/build.cmake @@ -0,0 +1,53 @@ +# This file is intended to be included from project's CMakeLists.txt. +# Prior to include, MODULES_LIST variable should be initialised with list +# of modules (subdirectories in modules dir) that should be built into +# project's loadable library. + +if(NOT DEFINED MODULES_LIST) + message(FATAL_ERROR "Please define MODULES_LIST: list of modules to be built into loadable library") +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/config.cmake) + +foreach(MODULE ${MODULES_LIST}) + add_executable(${MODULE}) + add_subdirectory(${LMDK_BASE}/modules/${MODULE} ${MODULE}_module) + +### set_target_properties(${MODULE} PROPERTIES OUTPUT_NAME ${MODULE}.mod) + + target_include_directories(${MODULE} PRIVATE + "${LMDK_BASE}/include" + "${RIMAGE_INCLUDE_DIR}" + ) + + # generate linker script + get_target_property(HPSRAM_ADDR ${MODULE} HPSRAM_ADDR) + + if(NOT DEFINED HPSRAM_ADDR) + message(FATAL_ERROR "Please define HPSRAM_ADDR for module ${MODULE}") + endif() + + add_custom_command(TARGET ${MODULE} PRE_LINK + COMMAND ${CMAKE_COMMAND} + -DMODULE=${MODULE} + -DHPSRAM_ADDR=${HPSRAM_ADDR} + -P ${CMAKE_CURRENT_LIST_DIR}/ldscripts.cmake + ) + + target_link_options(${MODULE} PRIVATE + "-nostdlib" "-nodefaultlibs" + "-Wl,--no-undefined" "-Wl,--unresolved-symbols=report-all" "-Wl,--error-unresolved-symbols" + #"-Wl,--gc-sections" # may remove .bss and that will result in rimage error, do not use for now + "-Wl,-Map,$.map" # optional: just for debug + "-T" "${MODULE}_ldscripts/elf32xtensa.x" + ) +endforeach() + +set(RIMAGE_OUTPUT_FILE ${PROJECT_NAME}_noextmft) +set(OUTPUT_FILE ${PROJECT_NAME}.bin) + +add_custom_target(${PROJECT_NAME}_target ALL + DEPENDS ${MODULES_LIST} + COMMAND ${RIMAGE_COMMAND} -k ${SIGNING_KEY} -f 2.0.0 -b 1 -o ${RIMAGE_OUTPUT_FILE} -c ${TOML} -e ${MODULES_LIST} + COMMAND ${CMAKE_COMMAND} -E cat ${RIMAGE_OUTPUT_FILE}.xman ${RIMAGE_OUTPUT_FILE} > ${OUTPUT_FILE} +) diff --git a/lmdk/cmake/config.cmake b/lmdk/cmake/config.cmake new file mode 100644 index 000000000000..a326df87ea4d --- /dev/null +++ b/lmdk/cmake/config.cmake @@ -0,0 +1,25 @@ + +if(NOT DEFINED RIMAGE_COMMAND) + message(FATAL_ERROR + " Please define RIMAGE_COMMAND: path to rimage executable.\n" + " E.g. using cmake -DRIMAGE_COMMAND=/path/rimage command line parameter." + ) +endif() + +if(NOT DEFINED SIGNING_KEY) + message(FATAL_ERROR + " Please define SIGNING_KEY: path to signing key for rimage.\n" + " E.g. using cmake -DSIGNING_KEY=/path/to/key.pem command line parameter." + ) +endif() + +# This Loadable Modules Dev Kit root dir +set(LMDK_BASE ${CMAKE_CURRENT_LIST_DIR}/..) +cmake_path(ABSOLUTE_PATH LMDK_BASE NORMALIZE) + +# thesofproject root dir +set(SOF_BASE ${LMDK_BASE}/..) +cmake_path(ABSOLUTE_PATH SOF_BASE NORMALIZE) + +set(RIMAGE_INCLUDE_DIR ${SOF_BASE}/rimage/src/include) +cmake_path(ABSOLUTE_PATH RIMAGE_INCLUDE_DIR NORMALIZE) diff --git a/lmdk/cmake/ldscripts.cmake b/lmdk/cmake/ldscripts.cmake new file mode 100644 index 000000000000..917dd4b02d09 --- /dev/null +++ b/lmdk/cmake/ldscripts.cmake @@ -0,0 +1,49 @@ +# Linker scripts generator + +# These linker scripts are based on those found in https://github.com/thesofproject/converged-sof-modules +# +# There are few things these scripts ensure: +# +# (1) Each module has its own reserved (virtual) address space. This is specified as +# HPSRAM_ADDR in module's CMakeLists.txt and goes to memory_header_linker_script.txt. +# +# (2) .buildinfo section must be put at 0 offset of .text section. .buildinfo contains +# module loadable libraries API version. That API version is verified by base FW. +# Base FW accesses it simply as 0 offset from module's code. +# +# (3) .module section contains module manifest description. This section is used by +# rimage to generate module manifest. Scripts ensure that this section is not garbage +# collected by linker. + +# Required parameters MODULE and HPSRAM_ADDR should be specified in command line. + +if(NOT DEFINED MODULE) + message(FATAL_ERROR "MODULE not defined") +endif() + +if(NOT DEFINED HPSRAM_ADDR) + message(FATAL_ERROR "HPSRAM_ADDR not defined") +endif() + +# reserve space for manifest? +math(EXPR HPSRAM "${HPSRAM_ADDR} + 9 * 4096" OUTPUT_FORMAT HEXADECIMAL) + +set(LDSCRIPTS_DIR ${MODULE}_ldscripts) +set(LDSCRIPT_FILE ${LDSCRIPTS_DIR}/elf32xtensa.x) + +file(MAKE_DIRECTORY ${LDSCRIPTS_DIR}) +file(WRITE ${LDSCRIPT_FILE} "") + +file(APPEND ${LDSCRIPT_FILE} "INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/${LDSCRIPTS_DIR}/memory_header_linker_script.txt\n") +configure_file( + ${CMAKE_CURRENT_LIST_DIR}/ldscripts/memory_header_linker_script.txt.in + ${CMAKE_CURRENT_BINARY_DIR}/${LDSCRIPTS_DIR}/memory_header_linker_script.txt +) + +file(APPEND ${LDSCRIPT_FILE} "INCLUDE ${CMAKE_CURRENT_LIST_DIR}/ldscripts/text_linker_script.txt\n") +file(APPEND ${LDSCRIPT_FILE} "INCLUDE ${CMAKE_CURRENT_LIST_DIR}/ldscripts/common_text_linker_script.txt\n") +file(APPEND ${LDSCRIPT_FILE} "INCLUDE ${CMAKE_CURRENT_LIST_DIR}/ldscripts/data_linker_script.txt\n") +file(APPEND ${LDSCRIPT_FILE} "INCLUDE ${CMAKE_CURRENT_LIST_DIR}/ldscripts/common_rodata_linker_script.txt\n") +file(APPEND ${LDSCRIPT_FILE} "INCLUDE ${CMAKE_CURRENT_LIST_DIR}/ldscripts/bss_linker_script.txt\n") +file(APPEND ${LDSCRIPT_FILE} "INCLUDE ${CMAKE_CURRENT_LIST_DIR}/ldscripts/xt_linker_script.txt\n") +file(APPEND ${LDSCRIPT_FILE} "INCLUDE ${CMAKE_CURRENT_LIST_DIR}/ldscripts/guard_linker_script.txt\n") diff --git a/lmdk/cmake/ldscripts/bss_linker_script.txt b/lmdk/cmake/ldscripts/bss_linker_script.txt new file mode 100644 index 000000000000..c214d4662978 --- /dev/null +++ b/lmdk/cmake/ldscripts/bss_linker_script.txt @@ -0,0 +1,20 @@ + +PHDRS { + bss_phdr PT_LOAD; +} + +SECTIONS { + max_instances = 1; + max_instances-1 = max_instances - 1; + + .bss (NOLOAD) : ALIGN(4096) { + _first_start = ABSOLUTE(.); + *(.first) + _first_end = ABSOLUTE(.); + _next_start = ABSOLUTE(.); + . += (_first_end - _first_start) * max_instances-1; + _next_end = ABSOLUTE(.); + *(.bss) + *(.bss.*) + } >HPSRAM_seg : bss_phdr +} diff --git a/lmdk/cmake/ldscripts/common_rodata_linker_script.txt b/lmdk/cmake/ldscripts/common_rodata_linker_script.txt new file mode 100644 index 000000000000..2f3e4bfad4d9 --- /dev/null +++ b/lmdk/cmake/ldscripts/common_rodata_linker_script.txt @@ -0,0 +1,38 @@ + +PHDRS { + rodata_phdr PT_LOAD; +} + +SECTIONS { + .common.rodata : ALIGN(4096) { + _rodata_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + KEEP (*(.xt_except_table)) + KEEP (*(.gcc_except_table)) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + KEEP (*(.eh_frame)) + /* C++ constructor and destructor tables properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _rodata_end = ABSOLUTE(.); + } >HPSRAM_seg : rodata_phdr +} diff --git a/lmdk/cmake/ldscripts/common_text_linker_script.txt b/lmdk/cmake/ldscripts/common_text_linker_script.txt new file mode 100644 index 000000000000..10468dc4bf3a --- /dev/null +++ b/lmdk/cmake/ldscripts/common_text_linker_script.txt @@ -0,0 +1,24 @@ + +PHDRS { + text_phdr PT_LOAD; +} + +SECTIONS { + .common.text : ALIGN(4096){ + _common_text_start = ABSOLUTE(.); + *(.entry.text) + *(.init.literal) + KEEP(*(.init)) + *(.literal .text) + *(.literal.* .text.*) + *(.stub) + *(.gnu.warning) + *(.gnu.linkonce.literal*) + *(.gnu.linkonce.t.*.literal*) + *(.gnu.linkonce.t*) + *(.fini.literal) + KEEP(*(.fini)) + *(.gnu.version) + _common_text_end = ABSOLUTE(.); + } >HPSRAM_seg : text_phdr +} diff --git a/lmdk/cmake/ldscripts/data_linker_script.txt b/lmdk/cmake/ldscripts/data_linker_script.txt new file mode 100644 index 000000000000..08b75bbf5b53 --- /dev/null +++ b/lmdk/cmake/ldscripts/data_linker_script.txt @@ -0,0 +1,30 @@ + +PHDRS { + data_phdr PT_LOAD; + rodata_phdr PT_LOAD; +} + +EXTERN(HPSRAM) + +SECTIONS { + .data : ALIGN(4096) { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + _data_end = ABSOLUTE(.); + } >HPSRAM_seg : data_phdr + + .rodata : ALIGN(4096) { + _rodata_start = ABSOLUTE(.); + *(.gnu.linkonce.r.*) + *(.rodata) + *(.rodata.*) + KEEP (*(.eh_frame)) + _rodata_end = ABSOLUTE(.); + } >HPSRAM_seg : rodata_phdr + + /* Module manifest is here */ + .module : ALIGN(4096) { + KEEP(*(.module)) + } >HPSRAM_seg : rodata_phdr +} diff --git a/lmdk/cmake/ldscripts/guard_linker_script.txt b/lmdk/cmake/ldscripts/guard_linker_script.txt new file mode 100644 index 000000000000..4d0ea5f03dbe --- /dev/null +++ b/lmdk/cmake/ldscripts/guard_linker_script.txt @@ -0,0 +1,12 @@ + +PHDRS { + guard_phdr PT_LOAD; +} + +SECTIONS { + .guard : ALIGN(4096) { + _guard_section_start = ABSOLUTE(.); + *(.*) + _guard_section_end = ABSOLUTE(.); + } >HPSRAM_seg : guard_phdr +} diff --git a/lmdk/cmake/ldscripts/memory_header_linker_script.txt.in b/lmdk/cmake/ldscripts/memory_header_linker_script.txt.in new file mode 100644 index 000000000000..c505a503c2fb --- /dev/null +++ b/lmdk/cmake/ldscripts/memory_header_linker_script.txt.in @@ -0,0 +1,8 @@ + +MEMORY { + HPSRAM_seg : org = ${HPSRAM}, len = 0xFFFFFFFF +} + +PHDRS { + HPSRAM_phdr PT_LOAD; +} diff --git a/lmdk/cmake/ldscripts/text_linker_script.txt b/lmdk/cmake/ldscripts/text_linker_script.txt new file mode 100644 index 000000000000..cd4412efccae --- /dev/null +++ b/lmdk/cmake/ldscripts/text_linker_script.txt @@ -0,0 +1,31 @@ + +/* EXTERN(${PACKAGE_ENTRY_POINT}) */ + +PHDRS { + text_phdr PT_LOAD; + cmi_text_phdr PT_LOAD; +} + +/* .buildinfo should be put at the beginning of .text segment! API version is defined there. */ + +SECTIONS { + .text : ALIGN(4096) { + _text_start = ABSOLUTE(.); + *(.buildinfo) + *(.gnu.linkonce.literal.*) + *(.gnu.linkonce.lit4) + *(.literal) + *(.literal.*) + *(.gnu.linkonce.t*) + *(.text) + *(.text.*) + *(.cmi.literal) + _text_end = ABSOLUTE(.); + } >HPSRAM_seg : text_phdr + + .cmi.text : ALIGN(4096) { + _cmi_text_start = ABSOLUTE(.); + *(.cmi.text) + _cmi_text_end = ABSOLUTE(.); + } >HPSRAM_seg : cmi_text_phdr +} diff --git a/lmdk/cmake/ldscripts/xt_linker_script.txt b/lmdk/cmake/ldscripts/xt_linker_script.txt new file mode 100644 index 000000000000..75137467376f --- /dev/null +++ b/lmdk/cmake/ldscripts/xt_linker_script.txt @@ -0,0 +1,55 @@ + +SECTIONS { + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + .xtensa.info 0 : { *(.xtensa.info) } + .comment 0 : { *(.comment) } + .debug_ranges 0 : { *(.debug_ranges) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .xt.insn 0 : + { + KEEP (*(.xt.insn)) + KEEP (*(.gnu.linkonce.x.*)) + } + .xt.prop 0 : + { + KEEP (*(.xt.prop)) + KEEP (*(.xt.prop.*)) + KEEP (*(.gnu.linkonce.prop.*)) + } + .xt.lit 0 : + { + KEEP (*(.xt.lit)) + KEEP (*(.xt.lit.*)) + KEEP (*(.gnu.linkonce.p.*)) + } + .xt.profile_range 0 : + { + KEEP (*(.xt.profile_range)) + KEEP (*(.gnu.linkonce.profile_range.*)) + } + .xt.profile_ranges 0 : + { + KEEP (*(.xt.profile_ranges)) + KEEP (*(.gnu.linkonce.xt.profile_ranges.*)) + } + .xt.profile_files 0 : + { + KEEP (*(.xt.profile_files)) + KEEP (*(.gnu.linkonce.xt.profile_files.*)) + } +} diff --git a/lmdk/cmake/xtensa-toolchain.cmake b/lmdk/cmake/xtensa-toolchain.cmake new file mode 100644 index 000000000000..6cda6274aeb8 --- /dev/null +++ b/lmdk/cmake/xtensa-toolchain.cmake @@ -0,0 +1,25 @@ +# Xtensa CMake toolchain file. Apply it using CMAKE_TOOLCHAIN_FILE variable. + +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_VERSION 1) + +cmake_path(CONVERT $ENV{XTENSA_TOOLCHAIN_PATH} TO_CMAKE_PATH_LIST XTENSA_TOOLCHAIN_PATH) +set(TOOLCHAIN_BASE ${XTENSA_TOOLCHAIN_PATH}/XtensaTools) +set(CROSS_COMPILE ${TOOLCHAIN_BASE}/bin/xt-) + +# clang or xcc +find_program(CMAKE_C_COMPILER NAMES ${CROSS_COMPILE}xcc NO_DEFAULT_PATH) +# clang++ or xc++ +find_program(CMAKE_CXX_COMPILER NAMES ${CROSS_COMPILE}xc++ NO_DEFAULT_PATH) + +find_program(CMAKE_LD NAMES ${CROSS_COMPILE}ld NO_DEFAULT_PATH) +find_program(CMAKE_AR NAMES ${CROSS_COMPILE}ar NO_DEFAULT_PATH) +find_program(CMAKE_RANLIB NAMES ${CROSS_COMPILE}ranlib NO_DEFAULT_PATH) +find_program(CMAKE_OBJCOPY NAMES ${CROSS_COMPILE}objcopy NO_DEFAULT_PATH) +find_program(CMAKE_OBJDUMP NAMES ${CROSS_COMPILE}objdump NO_DEFAULT_PATH) +find_program(CMAKE_NM NAMES ${CROSS_COMPILE}nm NO_DEFAULT_PATH) + +set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_BASE}/xtensa-elf) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/lmdk/include/todo.txt b/lmdk/include/todo.txt new file mode 100644 index 000000000000..83011e8c8236 --- /dev/null +++ b/lmdk/include/todo.txt @@ -0,0 +1 @@ +TODO: add SOF Loadable Modules Dev Kit headers here \ No newline at end of file diff --git a/lmdk/libraries/dummy/CMakeLists.txt b/lmdk/libraries/dummy/CMakeLists.txt new file mode 100644 index 000000000000..32cbd134dfae --- /dev/null +++ b/lmdk/libraries/dummy/CMakeLists.txt @@ -0,0 +1,19 @@ + +cmake_minimum_required(VERSION 3.20) +set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/../../cmake/xtensa-toolchain.cmake") + +project(dummy) + +# list of modules to be built and included into this loadable library +set(MODULES_LIST dummy) + +# toml file for rimage to generate manifets +set(TOML "${CMAKE_CURRENT_LIST_DIR}/dummy_mtl.toml") + +# TODO: Move it somewhere?! This probably should be defined in some API header file! +# SOF loadable modules API version +add_definitions(-DMAJOR_IADSP_API_VERSION=5) +add_definitions(-DMIDDLE_IADSP_API_VERSION=0) +add_definitions(-DMINOR_IADSP_API_VERSION=0) + +include(../../cmake/build.cmake) diff --git a/lmdk/libraries/dummy/dummy_mtl.toml b/lmdk/libraries/dummy/dummy_mtl.toml new file mode 100644 index 000000000000..7f984d2a2382 --- /dev/null +++ b/lmdk/libraries/dummy/dummy_mtl.toml @@ -0,0 +1,86 @@ +version = [3, 0] + +[adsp] +name = "mtl" +image_size = "0x2C0000" # (22) bank * 128KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0x1FF80000" +size = "0x400" +[[adsp.mem_zone]] +type = "IMR" +base = "0xA104A000" +size = "0x2000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xa00f0000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x40000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xA0000000" + +[cse] +partition_name = "ADSP" +[[cse.entry]] +name = "ADSP.man" +offset = "0x5c" +length = "0x464" +[[cse.entry]] +name = "ADSP.met" +offset = "0x4c0" +length = "0x70" +[[cse.entry]] +name = "ADSP" +offset = "0x540" +length = "0x0" # calculated by rimage + +[css] + +[signed_pkg] +name = "ADSP" +partition_usage = "0x23" +[[signed_pkg.module]] +name = "ADSP.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x40000" + +[module] +count = 1 + + [[module.entry]] + name = "DUMMY" + uuid = "01010101-0101-0101-0101-010101010101" + affinity_mask = "0x1" + instance_count = "15" + domain_types = "0" + load_type = "0" + module_type = "5" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xffff, 0xc, 0x8, 0x05ff, + 1, 0, 0xffff, 0xc, 0x8, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 216, 706000, 12, 16, 0, 0, 0, + 1, 0, 0, 0, 216, 1271000, 8, 8, 0, 0, 0, + 2, 0, 0, 0, 216, 1839000, 89, 118, 0, 0, 0, + 3, 0, 0, 0, 216, 2435000, 48, 64, 0, 0, 0, + 4, 0, 0, 0, 216, 3343000, 192, 192, 0, 0, 0, + 5, 0, 0, 0, 216, 3961000, 177, 177, 0, 0, 0, + 6, 0, 0, 0, 216, 4238000, 192, 256, 0, 0, 0, + 7, 0, 0, 0, 216, 6691000, 192, 256, 0, 0, 0] + diff --git a/lmdk/modules/dummy/CMakeLists.txt b/lmdk/modules/dummy/CMakeLists.txt new file mode 100644 index 000000000000..a4903aa0e39d --- /dev/null +++ b/lmdk/modules/dummy/CMakeLists.txt @@ -0,0 +1,6 @@ + +target_sources(dummy PRIVATE dummy.c) + +set_target_properties(dummy PROPERTIES + HPSRAM_ADDR "0xa06a1000" +) diff --git a/lmdk/modules/dummy/dummy.c b/lmdk/modules/dummy/dummy.c new file mode 100644 index 000000000000..3d8b3e787f07 --- /dev/null +++ b/lmdk/modules/dummy/dummy.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright 2023 Intel Corporation. All rights reserved. + +#include + +/* rimage fails if no .bss section found */ +int bss_workaround; + +#define ADSP_BUILD_INFO_FORMAT 0 + +/* these supposed to be defined in some API header file which is not yet available */ +union adsp_api_version { + uint32_t full; + struct { + uint32_t minor : 10; + uint32_t middle : 10; + uint32_t major : 10; + uint32_t reserved : 2; + } fields; +}; + +struct adsp_build_info { + uint32_t format; + union adsp_api_version api_version_number; +}; + +struct adsp_build_info dummy_build_info __attribute__((section(".buildinfo"))) = { + ADSP_BUILD_INFO_FORMAT, + { + ((0x3FF & MAJOR_IADSP_API_VERSION) << 20) | + ((0x3FF & MIDDLE_IADSP_API_VERSION) << 10) | + ((0x3FF & MINOR_IADSP_API_VERSION) << 0) + } +}; + +__attribute__((section(".cmi.text"))) +void *dummyPackageEntryPoint(int a, int b) +{ + /* supposed to return here a pointer to module interface implementation */ + return (void *)0x12345678; +} + +__attribute__((section(".module"))) +const struct sof_man_module_manifest dummy_module_manifest = { + .module = { + .name = "DUMMY", + .uuid = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + .entry_point = (uint32_t)dummyPackageEntryPoint, + .type = { + .load_type = SOF_MAN_MOD_TYPE_MODULE, + .domain_ll = 1 + }, + .affinity_mask = 3, + } +}; From befed4f4660f2675a078e42bcb42ef47359c6c31 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Tue, 18 Apr 2023 10:31:59 +0200 Subject: [PATCH 16/94] ipc4: copier: Fix memory leak Adds forgotten buffer_free() for copier multi_endpoint_buffer. Signed-off-by: Serhiy Katsyuba --- src/audio/copier/copier.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 3f8139f44330..809613f8a42b 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -715,6 +715,9 @@ static void copier_free(struct comp_dev *dev) rfree(cd->hd); } + if (cd->multi_endpoint_buffer) + buffer_free(cd->multi_endpoint_buffer); + for (i = 0; i < cd->endpoint_num; i++) { if (dev->ipc_config.type != SOF_COMP_HOST || cd->ipc_gtw) { cd->endpoint[i]->drv->ops.free(cd->endpoint[i]); From 6bb5c7b2cf58f549ed3aacbee528a817d00d250a Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Tue, 25 Apr 2023 07:49:14 +0200 Subject: [PATCH 17/94] west: update rimage and zephyr to MTL-005 update rimage to 375218cc0b37 update zephyr to d11ba34ddad4 Signed-off-by: Adrian Bonislawski --- rimage | 2 +- west.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rimage b/rimage index ab0429fdbe56..375218cc0b37 160000 --- a/rimage +++ b/rimage @@ -1 +1 @@ -Subproject commit ab0429fdbe563ef6abe499c69b2483e96c4762d0 +Subproject commit 375218cc0b3795bf4242a46fa05486647b93ff2d diff --git a/west.yml b/west.yml index 5aa993135b7e..a01b6d18479c 100644 --- a/west.yml +++ b/west.yml @@ -34,7 +34,7 @@ manifest: - name: rimage repo-path: rimage path: sof/rimage - revision: ab0429fdbe563ef6abe499c69b2483e96c4762d0 + revision: 375218cc0b3795bf4242a46fa05486647b93ff2d - name: tomlc99 repo-path: tomlc99 @@ -43,8 +43,8 @@ manifest: - name: zephyr repo-path: zephyr - revision: e59e65dc75e4fc7c359712cd7ad7387c0323eb75 - remote: zephyrproject + revision: d11ba34ddad459f8244ae6adc217533d90c2ca0f + remote: thesofproject # Import some projects listed in zephyr/west.yml@revision # From f21588736cc6ae54017cf37c8182b522a455bf79 Mon Sep 17 00:00:00 2001 From: "Kwasowiec, Fabiola" Date: Thu, 13 Apr 2023 08:48:19 +0200 Subject: [PATCH 18/94] dma: disable hda when pipeline is reset DGCS_GEN bit should be set to 0 on a pipeline state change to reset Signed-off-by: Kwasowiec, Fabiola --- src/audio/host-zephyr.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index e33246ab5a12..caf51591a8d3 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -1050,12 +1050,10 @@ static int host_position(struct comp_dev *dev, void host_zephyr_reset(struct host_data *hd, uint16_t state) { if (hd->chan) { - if (state == COMP_STATE_ACTIVE) { - dma_stop(hd->chan->dma->z_dev, hd->chan->index); - /* Unregister L1 exit */ - notifier_unregister(NULL, scheduler_get_data(SOF_SCHEDULE_LL_TIMER), - NOTIFIER_ID_LL_POST_RUN); - } + dma_stop(hd->chan->dma->z_dev, hd->chan->index); + /* Unregister L1 exit */ + notifier_unregister(NULL, scheduler_get_data(SOF_SCHEDULE_LL_TIMER), + NOTIFIER_ID_LL_POST_RUN); dma_release_channel(hd->dma->z_dev, hd->chan->index); hd->chan = NULL; From ac4b0ab9c74dcbde447016b4285c8845045b1244 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Wed, 26 Apr 2023 12:06:36 +0200 Subject: [PATCH 19/94] fix: platform: mtl: secondary core d3 exit Add D3 exit notify for secondary core. Signed-off-by: Tomasz Leman --- src/platform/intel/ace/platform.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/platform/intel/ace/platform.c b/src/platform/intel/ace/platform.c index e839ee7f900a..cc811a8503d0 100644 --- a/src/platform/intel/ace/platform.c +++ b/src/platform/intel/ace/platform.c @@ -147,8 +147,10 @@ static void notify_pm_state_entry(enum pm_state state) */ static void notify_pm_state_exit(enum pm_state state) { - if (!cpu_is_primary(arch_proc_id())) + if (!cpu_is_primary(arch_proc_id())) { + cpu_notify_state_exit(state); return; + } if (state == PM_STATE_SOFT_OFF) { #ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE From dcc95505c19403e647d59c6e8b6671cd25138406 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Thu, 27 Apr 2023 21:00:11 +0200 Subject: [PATCH 20/94] [DEBUG] clk: remove unnecessary freq change notifications Such notification currently is used only in non-zephyr code (ll sched) so it is safe to remove for MTL because of some idc issues Signed-off-by: Adrian Bonislawski --- src/lib/clk.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/lib/clk.c b/src/lib/clk.c index a3439b2a01ae..6a57966b9be5 100644 --- a/src/lib/clk.c +++ b/src/lib/clk.c @@ -28,8 +28,6 @@ DECLARE_TR_CTX(clock_tr, SOF_UUID(clock_uuid), LOG_LEVEL_INFO); SHARED_DATA struct k_spinlock clk_lock; -struct clock_notify_data clk_notify_data; - static inline uint32_t clock_get_nearest_freq_idx(const struct freq_table *tab, uint32_t size, uint32_t hz) { @@ -59,39 +57,21 @@ void clock_set_freq(int clock, uint32_t hz) uint32_t idx; k_spinlock_key_t key; - clk_notify_data.old_freq = - clk_info->freqs[clk_info->current_freq_idx].freq; - clk_notify_data.old_ticks_per_msec = - clk_info->freqs[clk_info->current_freq_idx].ticks_per_msec; - /* atomic context for changing clocks */ key = clock_lock(); /* get nearest frequency that is >= requested Hz */ idx = clock_get_nearest_freq_idx(clk_info->freqs, clk_info->freqs_num, hz); - clk_notify_data.freq = clk_info->freqs[idx].freq; tr_info(&clock_tr, "clock %d set freq %dHz freq_idx %d", clock, hz, idx); - /* tell anyone interested we are about to change freq */ - clk_notify_data.message = CLOCK_NOTIFY_PRE; - notifier_event(clk_info, clk_info->notification_id, - clk_info->notification_mask, &clk_notify_data, - sizeof(clk_notify_data)); - if (!clk_info->set_freq || clk_info->set_freq(clock, idx) == 0) /* update clock frequency */ clk_info->current_freq_idx = idx; - /* tell anyone interested we have now changed freq */ - clk_notify_data.message = CLOCK_NOTIFY_POST; - notifier_event(clk_info, clk_info->notification_id, - clk_info->notification_mask, &clk_notify_data, - sizeof(clk_notify_data)); - clock_unlock(key); } From 7bb6e7ef3ba93d6406226a5fbe8476f0dc1098c7 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Thu, 27 Apr 2023 21:15:21 +0200 Subject: [PATCH 21/94] pipeline: register CPS consumption for a proper core This will register CPS consumption based on a pipeline core rather than fixed core 0 Signed-off-by: Adrian Bonislawski --- src/audio/pipeline/pipeline-stream.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index 1b2e8a1ddf24..1b9badada45e 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -300,11 +300,11 @@ static int add_pipeline_cps_consumption(struct comp_dev *current, if (kcps == 0) { tr_warn(pipe, "0 KCPS for module: %#x, core: %d", current->ipc_config.id, ppl_data->p->core); } else { - core_kcps_adjust(0, kcps); + core_kcps_adjust(ppl_data->p->core, kcps); tr_info(pipe, "Registering KCPS consumption: %d, core: %d", kcps, ppl_data->p->core); } - int summary_cps = core_kcps_get(0); + int summary_cps = core_kcps_get(ppl_data->p->core); tr_info(pipe, "Sum of KCPS consumption: %d, core: %d", summary_cps, ppl_data->p->core); return pipeline_for_each_comp(current, ctx, dir); } @@ -337,9 +337,9 @@ static int remove_pipeline_cps_consumption(struct comp_dev *current, } int kcps = cd->cpc * 1000/ppl_data->p->period; - core_kcps_adjust(0, -kcps); /* 1000 chunks per second, so cpc value matches kcps? */ + core_kcps_adjust(ppl_data->p->core, -kcps); /* 1000 chunks per second, so cpc value matches kcps? */ tr_info(pipe, "Unregistering KCPS consumption: %d, core: %d", kcps, ppl_data->p->core); - int summary_cps = core_kcps_get(0); + int summary_cps = core_kcps_get(ppl_data->p->core); tr_info(pipe, "Sum of KCPS consumption: %d, core: %d", summary_cps, ppl_data->p->core); return pipeline_for_each_comp(current, ctx, dir); } From 3d56dcd3705d9e2bafc861a4c6d2aa77019546a8 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Fri, 28 Apr 2023 20:55:54 +0200 Subject: [PATCH 22/94] [DEBUG] idc: increase p4wq work items for idc per core [TEST VERSION] This will allow to rapidly submit several p4wq work items because the same work item cannot be added if it still exist in rb tree and such situation will lead to tree crash Signed-off-by: Adrian Bonislawski --- src/idc/zephyr_idc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/idc/zephyr_idc.c b/src/idc/zephyr_idc.c index 769e1a32d4ca..72fd455c4041 100644 --- a/src/idc/zephyr_idc.c +++ b/src/idc/zephyr_idc.c @@ -48,6 +48,9 @@ void idc_init_thread(void) K_P4WQ_ARRAY_DEFINE(q_zephyr_idc, CONFIG_CORE_COUNT, SOF_STACK_SIZE, K_P4WQ_USER_CPU_MASK); +#define WQ_PER_C 30 +static int w_idx = 0; + struct zephyr_idc_msg { struct k_p4wq_work work; struct idc_msg msg; @@ -96,14 +99,14 @@ static void idc_handler(struct k_p4wq_work *work) * Used for *target* CPUs, since the initiator (usually core 0) can launch * several IDC messages at once */ -static struct zephyr_idc_msg idc_work[CONFIG_CORE_COUNT]; +static struct zephyr_idc_msg idc_work[CONFIG_CORE_COUNT * WQ_PER_C]; int idc_send_msg(struct idc_msg *msg, uint32_t mode) { struct idc *idc = *idc_get(); struct idc_payload *payload = idc_payload_get(idc, msg->core); unsigned int target_cpu = msg->core; - struct zephyr_idc_msg *zmsg = idc_work + target_cpu; + struct zephyr_idc_msg *zmsg = idc_work + target_cpu * WQ_PER_C + w_idx; struct idc_msg *msg_cp = &zmsg->msg; struct k_p4wq_work *work = &zmsg->work; int ret; @@ -141,6 +144,9 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode) ret = 0; } + if (++w_idx >= WQ_PER_C) + w_idx = 0; + return ret; } From d2b0b4716be7f5371d48993833e198c27d8c5d7e Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Fri, 28 Apr 2023 16:10:19 +0200 Subject: [PATCH 23/94] ipc4: Fix Host gtw conversion to/from 24_4LE audio Fixes audio format conversions on Host gateway between 16/16 and 24/32 (and vice versa) and between 32/32 and 24/32 (and vice versa). Signed-off-by: Serhiy Katsyuba --- .../pcm_converter/pcm_converter_generic.c | 28 ++++++++++++++++--- src/audio/pcm_converter/pcm_converter_hifi3.c | 28 ++++++++++++++++--- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/audio/pcm_converter/pcm_converter_generic.c b/src/audio/pcm_converter/pcm_converter_generic.c index 1cc7dc38685d..b9581dd8c3ae 100644 --- a/src/audio/pcm_converter/pcm_converter_generic.c +++ b/src/audio/pcm_converter/pcm_converter_generic.c @@ -854,24 +854,44 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, - ipc4_gtw_all, ipc4_bidirection, pcm_convert_s24_to_s32}, + ipc4_gtw_all & ~ipc4_gtw_host, ipc4_bidirection, pcm_convert_s24_to_s32}, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, + ipc4_gtw_host, ipc4_playback, audio_stream_copy}, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, + ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s32}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh), ipc4_bidirection, + ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host), ipc4_bidirection, pcm_convert_s32_to_s24 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_playback, pcm_convert_s32_to_s24_be }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_capture, pcm_convert_s32_to_s24 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, + ipc4_gtw_host, ipc4_playback, pcm_convert_s32_to_s24 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, + ipc4_gtw_host, ipc4_capture, pcm_convert_s32_to_s24_be }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE, ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh), + SOF_IPC_FRAME_S24_4LE, + ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host), ipc4_bidirection, pcm_convert_s16_to_s24 }, { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_playback, pcm_convert_s16_to_s32}, + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, + SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, + ipc4_playback, pcm_convert_s16_to_s24 }, + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, + SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, + ipc4_capture, pcm_convert_s16_to_s32 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, + SOF_IPC_FRAME_S16_LE, ipc4_gtw_all & ~ipc4_gtw_host, + ipc4_bidirection, pcm_convert_s24_to_s16 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, + SOF_IPC_FRAME_S16_LE, ipc4_gtw_host, ipc4_playback, pcm_convert_s32_to_s16 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S16_LE, ipc4_gtw_all, ipc4_bidirection, pcm_convert_s24_to_s16 }, + SOF_IPC_FRAME_S16_LE, ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s16 }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S32_LE, diff --git a/src/audio/pcm_converter/pcm_converter_hifi3.c b/src/audio/pcm_converter/pcm_converter_hifi3.c index b727fdae209b..9790b85c4dce 100644 --- a/src/audio/pcm_converter/pcm_converter_hifi3.c +++ b/src/audio/pcm_converter/pcm_converter_hifi3.c @@ -1248,24 +1248,44 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, - ipc4_gtw_all, ipc4_bidirection, pcm_convert_s24_to_s32}, + ipc4_gtw_all & ~ipc4_gtw_host, ipc4_bidirection, pcm_convert_s24_to_s32}, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, + ipc4_gtw_host, ipc4_playback, audio_stream_copy}, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, + ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s32}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh), ipc4_bidirection, + ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host), ipc4_bidirection, pcm_convert_s32_to_s24 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_playback, pcm_convert_s32_to_s24_be }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_capture, pcm_convert_s32_to_s24 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, + ipc4_gtw_host, ipc4_playback, pcm_convert_s32_to_s24 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, + ipc4_gtw_host, ipc4_capture, pcm_convert_s32_to_s24_be }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE, ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh), + SOF_IPC_FRAME_S24_4LE, + ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host), ipc4_bidirection, pcm_convert_s16_to_s24 }, { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_playback, pcm_convert_s16_to_s32}, + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, + SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, + ipc4_playback, pcm_convert_s16_to_s24 }, + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, + SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, + ipc4_capture, pcm_convert_s16_to_s32 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, + SOF_IPC_FRAME_S16_LE, ipc4_gtw_all & ~ipc4_gtw_host, + ipc4_bidirection, pcm_convert_s24_to_s16 }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, + SOF_IPC_FRAME_S16_LE, ipc4_gtw_host, ipc4_playback, pcm_convert_s32_to_s16 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S16_LE, ipc4_gtw_all, ipc4_bidirection, pcm_convert_s24_to_s16 }, + SOF_IPC_FRAME_S16_LE, ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s16 }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S32_LE, From 3e6a3fdf152500aafd59d9aba3bb768f81ab125e Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Mon, 8 May 2023 16:20:09 +0200 Subject: [PATCH 24/94] dmic: Use the correct 24 bit conversion function The DMIC interface places 24-bit samples on the most significant bits of a 32-bit container. The correct conversion function for this gateway was used. Signed-off-by: Adrian Warecki --- src/audio/pcm_converter/pcm_converter_generic.c | 7 ++++--- src/audio/pcm_converter/pcm_converter_hifi3.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/audio/pcm_converter/pcm_converter_generic.c b/src/audio/pcm_converter/pcm_converter_generic.c index b9581dd8c3ae..23a2e23d511b 100644 --- a/src/audio/pcm_converter/pcm_converter_generic.c +++ b/src/audio/pcm_converter/pcm_converter_generic.c @@ -843,12 +843,13 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host), ipc4_bidirection, - audio_stream_copy}, + ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host | ipc4_gtw_dmic), + ipc4_bidirection, audio_stream_copy}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_playback, pcm_convert_s24_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_link | ipc4_gtw_alh, ipc4_capture, pcm_convert_s32_to_s24 }, + ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_dmic, ipc4_capture, + pcm_convert_s32_to_s24 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, ipc4_playback, pcm_convert_s32_to_s24 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, diff --git a/src/audio/pcm_converter/pcm_converter_hifi3.c b/src/audio/pcm_converter/pcm_converter_hifi3.c index 9790b85c4dce..0523454d746b 100644 --- a/src/audio/pcm_converter/pcm_converter_hifi3.c +++ b/src/audio/pcm_converter/pcm_converter_hifi3.c @@ -1237,12 +1237,13 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host), ipc4_bidirection, - audio_stream_copy}, + ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host | ipc4_gtw_dmic), + ipc4_bidirection, audio_stream_copy}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_playback, pcm_convert_s24_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_link | ipc4_gtw_alh, ipc4_capture, pcm_convert_s32_to_s24 }, + ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_dmic, ipc4_capture, + pcm_convert_s32_to_s24 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, ipc4_playback, pcm_convert_s32_to_s24 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, From f4af8cadde62680f83d9b52b6ef2d849e653a675 Mon Sep 17 00:00:00 2001 From: Andrey Borisovich Date: Tue, 9 May 2023 14:36:53 +0200 Subject: [PATCH 25/94] fix: zephyr logging macro comp_cl_err accesses const struct member Zephyr logging macro comp_cl_err expands to many different logging frameworks depending on log configuration selected (possible z_log_minimal_printk, z_log_printf_arg_checker, cbprintf_package or even syscalls). There is no warranty that a format specifier passed as argument to %x will not be modified. Constant struct members should not be passed to this logging macro. Fixed by provoding macro with value copy. Signed-off-by: Andrey Borisovich --- src/audio/ipcgtw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/audio/ipcgtw.c b/src/audio/ipcgtw.c index 7d96aec94d54..28d83c44f171 100644 --- a/src/audio/ipcgtw.c +++ b/src/audio/ipcgtw.c @@ -180,8 +180,9 @@ int ipcgtw_process_cmd(const struct ipc4_ipcgtw_cmd *cmd, dev = find_ipcgtw_by_node_id(in->node_id); if (!dev) { + uint32_t nodeid_connector_val = in->node_id.dw; comp_cl_err(&comp_ipcgtw, "ipcgtw_process_cmd(): node_id not found: %x", - in->node_id.dw); + nodeid_connector_val); return -EINVAL; } From 5f0c4e4c3160252d3794feec7d1ac1303f5f9cd1 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 9 May 2023 15:12:07 +0200 Subject: [PATCH 26/94] [PATCH] pipeline: make CPC data "opt-in" with fallback CPC is used to select the correct clock for the desired pipeline workload. In the case where the CPC data is not available from the manifest and the kernel driver sends a CPC of 0 then SOF should pick a platform safe level to ensure operational glitch free audio at the expense of power consumption. i.e. it's better to prioritize and preserve audio quality over audio power when CPC data is missing. Signed-off-by: Liam Girdwood Signed-off-by: Peter Ujfalusi --- src/audio/pipeline/pipeline-stream.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index 1b9badada45e..0a29ab8601d7 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -296,14 +296,18 @@ static int add_pipeline_cps_consumption(struct comp_dev *current, cd = &md->cfg.base_cfg; } - int kcps = cd->cpc * 1000 / ppl_data->p->period; - if (kcps == 0) { - tr_warn(pipe, "0 KCPS for module: %#x, core: %d", current->ipc_config.id, ppl_data->p->core); - } else { - core_kcps_adjust(ppl_data->p->core, kcps); - tr_info(pipe, "Registering KCPS consumption: %d, core: %d", kcps, ppl_data->p->core); + if (cd->cpc == 0) { + /* Use maximum clock budget, assume 1ms chunk size */ + cd->cpc = CLK_MAX_CPU_HZ / 1000; + tr_warn(pipe, + "0 CPS requested for module: %#x, core: %d using safe max CPC: %u", + current->ipc_config.id, ppl_data->p->core, cd->cpc); } + int kcps = cd->cpc * 1000 / ppl_data->p->period; + tr_info(pipe, "Registering KCPS consumption: %d, core: %d", kcps, ppl_data->p->core); + core_kcps_adjust(ppl_data->p->core, kcps); + int summary_cps = core_kcps_get(ppl_data->p->core); tr_info(pipe, "Sum of KCPS consumption: %d, core: %d", summary_cps, ppl_data->p->core); return pipeline_for_each_comp(current, ctx, dir); From 8fb9dbec75481a4b0bad211c0f927b2bf8d30c32 Mon Sep 17 00:00:00 2001 From: Andrula Song Date: Wed, 26 Apr 2023 13:09:52 +0800 Subject: [PATCH 27/94] Smart_amp: Split dummy smart_amp to IPC3/IPC4 version Split smart_amp_test.c to IPC3 version smart_amp_test_ipc3.c and IPC4 version smart_amp_test_ipc4.c Signed-off-by: Andrula Song (cherry picked from commit 6ac3409ac85a7fa64189268d0d15b592d4f3242e) --- .../sof/samples/audio/smart_amp_test.h | 5 - src/samples/audio/CMakeLists.txt | 13 +- src/samples/audio/smart_amp_test_ipc3.c | 596 ++++++++++++++++++ ...smart_amp_test.c => smart_amp_test_ipc4.c} | 210 +----- zephyr/CMakeLists.txt | 12 +- 5 files changed, 619 insertions(+), 217 deletions(-) create mode 100644 src/samples/audio/smart_amp_test_ipc3.c rename src/samples/audio/{smart_amp_test.c => smart_amp_test_ipc4.c} (76%) diff --git a/src/include/sof/samples/audio/smart_amp_test.h b/src/include/sof/samples/audio/smart_amp_test.h index 56b0c01f275a..ed4a196f266b 100644 --- a/src/include/sof/samples/audio/smart_amp_test.h +++ b/src/include/sof/samples/audio/smart_amp_test.h @@ -31,11 +31,6 @@ struct smart_amp_model_data { uint32_t data_pos; }; -typedef int(*smart_amp_proc)(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, uint32_t frames, - int8_t *chan_map); - /* Each channel map specifies which channel from input (buffer between host * and smart amp - source_chan_map[] or feedback buffer between smart amp and * demux - feedback_chan_map[]) will be copied to specific smart amp output diff --git a/src/samples/audio/CMakeLists.txt b/src/samples/audio/CMakeLists.txt index 51bc3f5d1023..328070c2bb52 100644 --- a/src/samples/audio/CMakeLists.txt +++ b/src/samples/audio/CMakeLists.txt @@ -1,9 +1,14 @@ # SPDX-License-Identifier: BSD-3-Clause - if(CONFIG_SAMPLE_SMART_AMP) - add_local_sources(sof - smart_amp_test.c - ) + if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof + smart_amp_test_ipc3.c + ) + elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof + smart_amp_test_ipc4.c + ) + endif() endif() if(CONFIG_SAMPLE_KEYPHRASE) diff --git a/src/samples/audio/smart_amp_test_ipc3.c b/src/samples/audio/smart_amp_test_ipc3.c new file mode 100644 index 000000000000..7425a0057f65 --- /dev/null +++ b/src/samples/audio/smart_amp_test_ipc3.c @@ -0,0 +1,596 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. +// +// Author: Bartosz Kokoszko + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __ZEPHYR__ +#include +#endif + +static const struct comp_driver comp_smart_amp; + +LOG_MODULE_REGISTER(smart_amp_test, CONFIG_SOF_LOG_LEVEL); + +/* 167a961e-8ae4-11ea-89f1-000c29ce1635 */ +DECLARE_SOF_RT_UUID("smart_amp-test", smart_amp_comp_uuid, 0x167a961e, 0x8ae4, + 0x11ea, 0x89, 0xf1, 0x00, 0x0c, 0x29, 0xce, 0x16, 0x35); + +DECLARE_TR_CTX(smart_amp_comp_tr, SOF_UUID(smart_amp_comp_uuid), + LOG_LEVEL_INFO); + +typedef int(*smart_amp_proc)(struct comp_dev *dev, + const struct audio_stream __sparse_cache *source, + const struct audio_stream __sparse_cache *sink, uint32_t frames, + int8_t *chan_map); + +struct smart_amp_data { + struct sof_smart_amp_config config; + struct comp_data_blob_handler *model_handler; + void *data_blob; + size_t data_blob_size; + + struct comp_buffer *source_buf; /**< stream source buffer */ + struct comp_buffer *feedback_buf; /**< feedback source buffer */ + struct comp_buffer *sink_buf; /**< sink buffer */ + + struct k_mutex lock; /**< protect feedback_buf updated */ + + smart_amp_proc process; + + uint32_t in_channels; + uint32_t out_channels; +}; + +static struct comp_dev *smart_amp_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec) +{ + const struct ipc_config_process *ipc_sa = spec; + const struct sof_smart_amp_config *cfg; + struct smart_amp_data *sad; + struct comp_dev *dev; + size_t bs; + + dev = comp_alloc(drv, sizeof(*dev)); + if (!dev) + return NULL; + dev->ipc_config = *config; + + sad = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*sad)); + if (!sad) + goto fail; + + comp_set_drvdata(dev, sad); + + /* component model data handler */ + sad->model_handler = comp_data_blob_handler_new(dev); + if (!sad->model_handler) + goto sad_fail; + + k_mutex_init(&sad->lock); + + cfg = (struct sof_smart_amp_config *)ipc_sa->data; + bs = ipc_sa->size; + + if (bs > 0 && bs < sizeof(struct sof_smart_amp_config)) { + comp_err(dev, "smart_amp_new(): failed to apply config"); + goto sad_fail; + } + + memcpy_s(&sad->config, sizeof(struct sof_smart_amp_config), cfg, bs); + + dev->state = COMP_STATE_READY; + + return dev; + +sad_fail: + comp_data_blob_handler_free(sad->model_handler); + rfree(sad); +fail: + rfree(dev); + return NULL; +} + +static void smart_amp_set_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params) +{ + /* nothing to do */ +} + +static int smart_amp_set_config(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + struct sof_smart_amp_config *cfg; + size_t bs; + + /* Copy new config, find size from header */ + cfg = (struct sof_smart_amp_config *) + ASSUME_ALIGNED(&cdata->data->data, sizeof(uint32_t)); + bs = cfg->size; + + comp_dbg(dev, "smart_amp_set_config(), actual blob size = %u, expected blob size = %u", + bs, sizeof(struct sof_smart_amp_config)); + + if (bs != sizeof(struct sof_smart_amp_config)) { + comp_err(dev, "smart_amp_set_config(): invalid blob size, actual blob size = %u, expected blob size = %u", + bs, sizeof(struct sof_smart_amp_config)); + return -EINVAL; + } + + memcpy_s(&sad->config, sizeof(struct sof_smart_amp_config), cfg, + sizeof(struct sof_smart_amp_config)); + + return 0; +} + +static int smart_amp_get_config(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata, int size) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + size_t bs; + int ret; + + /* Copy back to user space */ + bs = sad->config.size; + + comp_dbg(dev, "smart_amp_set_config(), actual blob size = %u, expected blob size = %u", + bs, sizeof(struct sof_smart_amp_config)); + + if (bs == 0 || bs > size) + return -EINVAL; + + ret = memcpy_s(cdata->data->data, size, &sad->config, bs); + assert(!ret); + + cdata->data->abi = SOF_ABI_VERSION; + cdata->data->size = bs; + + return ret; +} + +static int smart_amp_ctrl_get_bin_data(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata, + int size) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + + assert(sad); + + switch (cdata->data->type) { + case SOF_SMART_AMP_CONFIG: + return smart_amp_get_config(dev, cdata, size); + case SOF_SMART_AMP_MODEL: + return comp_data_blob_get_cmd(sad->model_handler, cdata, size); + default: + comp_warn(dev, "smart_amp_ctrl_get_bin_data(): unknown binary data type"); + break; + } + + return 0; +} + +static int smart_amp_ctrl_get_data(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata, int size) +{ + comp_info(dev, "smart_amp_ctrl_get_data() size: %d", size); + + switch (cdata->cmd) { + case SOF_CTRL_CMD_BINARY: + return smart_amp_ctrl_get_bin_data(dev, cdata, size); + default: + comp_err(dev, "smart_amp_ctrl_get_data(): invalid cdata->cmd"); + return -EINVAL; + } +} + +static int smart_amp_ctrl_set_bin_data(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + + assert(sad); + + if (dev->state < COMP_STATE_READY) { + comp_err(dev, "smart_amp_ctrl_set_bin_data(): driver in init!"); + return -EBUSY; + } + + switch (cdata->data->type) { + case SOF_SMART_AMP_CONFIG: + return smart_amp_set_config(dev, cdata); + case SOF_SMART_AMP_MODEL: + return comp_data_blob_set_cmd(sad->model_handler, cdata); + default: + comp_warn(dev, "smart_amp_ctrl_set_bin_data(): unknown binary data type"); + break; + } + + return 0; +} + +static int smart_amp_ctrl_set_data(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + /* Check version from ABI header */ + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { + comp_err(dev, "smart_amp_ctrl_set_data(): invalid version"); + return -EINVAL; + } + + switch (cdata->cmd) { + case SOF_CTRL_CMD_ENUM: + comp_info(dev, "smart_amp_ctrl_set_data(), SOF_CTRL_CMD_ENUM"); + break; + case SOF_CTRL_CMD_BINARY: + comp_info(dev, "smart_amp_ctrl_set_data(), SOF_CTRL_CMD_BINARY"); + return smart_amp_ctrl_set_bin_data(dev, cdata); + default: + comp_err(dev, "smart_amp_ctrl_set_data(): invalid cdata->cmd"); + return -EINVAL; + } + + return 0; +} + +/* used to pass standard and bespoke commands (with data) to component */ +static int smart_amp_cmd(struct comp_dev *dev, int cmd, void *data, + int max_data_size) +{ + struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4); + + comp_info(dev, "smart_amp_cmd(): cmd: %d", cmd); + + switch (cmd) { + case COMP_CMD_SET_DATA: + return smart_amp_ctrl_set_data(dev, cdata); + case COMP_CMD_GET_DATA: + return smart_amp_ctrl_get_data(dev, cdata, max_data_size); + default: + return -EINVAL; + } +} + +static void smart_amp_free(struct comp_dev *dev) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + + comp_info(dev, "smart_amp_free()"); + + comp_data_blob_handler_free(sad->model_handler); + + rfree(sad); + rfree(dev); +} + +static int smart_amp_verify_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params) +{ + int ret; + + comp_info(dev, "smart_amp_verify_params()"); + + ret = comp_verify_params(dev, BUFF_PARAMS_CHANNELS, params); + if (ret < 0) { + comp_err(dev, "smart_amp_verify_params() error: comp_verify_params() failed."); + return ret; + } + + return 0; +} + +static int smart_amp_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params) +{ + int err; + + comp_info(dev, "smart_amp_params()"); + + smart_amp_set_params(dev, params); + + err = smart_amp_verify_params(dev, params); + if (err < 0) { + comp_err(dev, "smart_amp_params(): pcm params verification failed."); + return err; + } + + return 0; +} + +static int smart_amp_trigger(struct comp_dev *dev, int cmd) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + int ret = 0; + + comp_info(dev, "smart_amp_trigger(), command = %u", cmd); + + ret = comp_set_state(dev, cmd); + + if (ret == COMP_STATUS_STATE_ALREADY_SET) + return PPL_STATUS_PATH_STOP; + + switch (cmd) { + case COMP_TRIGGER_START: + case COMP_TRIGGER_RELEASE: + k_mutex_lock(&sad->lock, K_FOREVER); + if (sad->feedback_buf) { + struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); + + buffer_zero(buf); + buffer_release(buf); + } + k_mutex_unlock(&sad->lock); + break; + case COMP_TRIGGER_PAUSE: + case COMP_TRIGGER_STOP: + break; + default: + break; + } + + return ret; +} + +static int smart_amp_process_s16(struct comp_dev *dev, + const struct audio_stream __sparse_cache *source, + const struct audio_stream __sparse_cache *sink, + uint32_t frames, int8_t *chan_map) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + int16_t *src; + int16_t *dest; + uint32_t in_frag = 0; + uint32_t out_frag = 0; + int i; + int j; + + comp_dbg(dev, "smart_amp_process_s16()"); + + for (i = 0; i < frames; i++) { + for (j = 0 ; j < sad->out_channels; j++) { + if (chan_map[j] != -1) { + src = audio_stream_read_frag_s16(source, + in_frag + + chan_map[j]); + dest = audio_stream_write_frag_s16(sink, + out_frag); + *dest = *src; + } + out_frag++; + } + in_frag += audio_stream_get_channels(source); + } + return 0; +} + +static int smart_amp_process_s32(struct comp_dev *dev, + const struct audio_stream __sparse_cache *source, + const struct audio_stream __sparse_cache *sink, + uint32_t frames, int8_t *chan_map) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + int32_t *src; + int32_t *dest; + uint32_t in_frag = 0; + uint32_t out_frag = 0; + int i; + int j; + + comp_dbg(dev, "smart_amp_process_s32()"); + + for (i = 0; i < frames; i++) { + for (j = 0 ; j < sad->out_channels; j++) { + if (chan_map[j] != -1) { + src = audio_stream_read_frag_s32(source, + in_frag + + chan_map[j]); + dest = audio_stream_write_frag_s32(sink, + out_frag); + *dest = *src; + } + out_frag++; + } + in_frag += audio_stream_get_channels(source); + } + + return 0; +} + +static smart_amp_proc get_smart_amp_process(struct comp_dev *dev, + struct comp_buffer __sparse_cache *buf) +{ + switch (audio_stream_get_frm_fmt(&buf->stream)) { + case SOF_IPC_FRAME_S16_LE: + return smart_amp_process_s16; + case SOF_IPC_FRAME_S24_4LE: + case SOF_IPC_FRAME_S32_LE: + return smart_amp_process_s32; + default: + comp_err(dev, "smart_amp_process() error: not supported frame format"); + return NULL; + } +} + +static int smart_amp_copy(struct comp_dev *dev) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + struct comp_buffer __sparse_cache *source_buf = buffer_acquire(sad->source_buf); + struct comp_buffer __sparse_cache *sink_buf = buffer_acquire(sad->sink_buf); + uint32_t avail_passthrough_frames; + uint32_t avail_feedback_frames; + uint32_t avail_frames = 0; + uint32_t source_bytes; + uint32_t sink_bytes; + uint32_t feedback_bytes; + + comp_dbg(dev, "smart_amp_copy()"); + + /* available bytes and samples calculation */ + avail_passthrough_frames = + audio_stream_avail_frames(&source_buf->stream, + &sink_buf->stream); + + k_mutex_lock(&sad->lock, K_FOREVER); + if (sad->feedback_buf) { + struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); + + if (buf->source && comp_get_state(dev, buf->source) == dev->state) { + /* feedback */ + avail_feedback_frames = + audio_stream_get_avail_frames(&buf->stream); + + avail_frames = MIN(avail_passthrough_frames, + avail_feedback_frames); + + feedback_bytes = avail_frames * + audio_stream_frame_bytes(&buf->stream); + + comp_dbg(dev, "smart_amp_copy(): processing %d feedback frames (avail_passthrough_frames: %d)", + avail_frames, avail_passthrough_frames); + + /* perform buffer writeback after source_buf process */ + buffer_stream_invalidate(buf, feedback_bytes); + sad->process(dev, &buf->stream, &sink_buf->stream, + avail_frames, sad->config.feedback_ch_map); + + comp_update_buffer_consume(buf, feedback_bytes); + } + + buffer_release(buf); + } + k_mutex_unlock(&sad->lock); + + if (!avail_frames) + avail_frames = avail_passthrough_frames; + /* bytes calculation */ + source_bytes = avail_frames * + audio_stream_frame_bytes(&source_buf->stream); + + sink_bytes = avail_frames * + audio_stream_frame_bytes(&sink_buf->stream); + + /* process data */ + buffer_stream_invalidate(source_buf, source_bytes); + sad->process(dev, &source_buf->stream, &sink_buf->stream, + avail_frames, sad->config.source_ch_map); + buffer_stream_writeback(sink_buf, sink_bytes); + + /* source/sink buffer pointers update */ + comp_update_buffer_consume(source_buf, source_bytes); + comp_update_buffer_produce(sink_buf, sink_bytes); + + buffer_release(sink_buf); + buffer_release(source_buf); + + return 0; +} + +static int smart_amp_reset(struct comp_dev *dev) +{ + comp_info(dev, "smart_amp_reset()"); + + comp_set_state(dev, COMP_TRIGGER_RESET); + + return 0; +} + +static int smart_amp_prepare(struct comp_dev *dev) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + struct comp_buffer *source_buffer; + struct comp_buffer __sparse_cache *buffer_c; + struct list_item *blist; + int ret; + + comp_info(dev, "smart_amp_prepare()"); + + ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); + if (ret < 0) + return ret; + + if (ret == COMP_STATUS_STATE_ALREADY_SET) + return PPL_STATUS_PATH_STOP; + + /* searching for stream and feedback source buffers */ + list_for_item(blist, &dev->bsource_list) { + source_buffer = container_of(blist, struct comp_buffer, + sink_list); + buffer_c = buffer_acquire(source_buffer); + + /* FIXME: how often can this loop be run? */ + if (buffer_c->source->ipc_config.type == SOF_COMP_DEMUX) + sad->feedback_buf = source_buffer; + else + sad->source_buf = source_buffer; + + buffer_release(buffer_c); + } + + sad->sink_buf = list_first_item(&dev->bsink_list, struct comp_buffer, + source_list); + + buffer_c = buffer_acquire(sad->sink_buf); + sad->out_channels = audio_stream_get_channels(&buffer_c->stream); + buffer_release(buffer_c); + + buffer_c = buffer_acquire(sad->source_buf); + sad->in_channels = audio_stream_get_channels(&buffer_c->stream); + + k_mutex_lock(&sad->lock, K_FOREVER); + if (sad->feedback_buf) { + struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); + + buf->stream.channels = sad->config.feedback_channels; + buf->stream.rate = audio_stream_get_rate(&buffer_c->stream); + buffer_release(buf); + } + k_mutex_unlock(&sad->lock); + + sad->process = get_smart_amp_process(dev, buffer_c); + if (!sad->process) { + comp_err(dev, "smart_amp_prepare(): get_smart_amp_process failed"); + ret = -EINVAL; + } + + buffer_release(buffer_c); + + return ret; +} + +static const struct comp_driver comp_smart_amp = { + .type = SOF_COMP_SMART_AMP, + .uid = SOF_RT_UUID(smart_amp_comp_uuid), + .tctx = &smart_amp_comp_tr, + .ops = { + .create = smart_amp_new, + .free = smart_amp_free, + .params = smart_amp_params, + .prepare = smart_amp_prepare, + .cmd = smart_amp_cmd, + .trigger = smart_amp_trigger, + .copy = smart_amp_copy, + .reset = smart_amp_reset, + }, +}; + +static SHARED_DATA struct comp_driver_info comp_smart_amp_info = { + .drv = &comp_smart_amp, +}; + +UT_STATIC void sys_comp_smart_amp_init(void) +{ + comp_register(platform_shared_get(&comp_smart_amp_info, + sizeof(comp_smart_amp_info))); +} + +DECLARE_MODULE(sys_comp_smart_amp_init); +SOF_MODULE_INIT(smart_amp_test, sys_comp_smart_amp_init); diff --git a/src/samples/audio/smart_amp_test.c b/src/samples/audio/smart_amp_test_ipc4.c similarity index 76% rename from src/samples/audio/smart_amp_test.c rename to src/samples/audio/smart_amp_test_ipc4.c index 10eb2e6f31e2..2c297389553a 100644 --- a/src/samples/audio/smart_amp_test.c +++ b/src/samples/audio/smart_amp_test_ipc4.c @@ -16,9 +16,7 @@ #include #endif -#if CONFIG_IPC_MAJOR_4 #include -#endif static const struct comp_driver comp_smart_amp; @@ -31,10 +29,13 @@ DECLARE_SOF_RT_UUID("smart_amp-test", smart_amp_comp_uuid, 0x167a961e, 0x8ae4, DECLARE_TR_CTX(smart_amp_comp_tr, SOF_UUID(smart_amp_comp_uuid), LOG_LEVEL_INFO); +typedef int(*smart_amp_proc)(struct comp_dev *dev, + const struct audio_stream __sparse_cache *source, + const struct audio_stream __sparse_cache *sink, uint32_t frames, + int8_t *chan_map); + struct smart_amp_data { -#if CONFIG_IPC_MAJOR_4 struct sof_smart_amp_ipc4_config ipc4_cfg; -#endif struct sof_smart_amp_config config; struct comp_data_blob_handler *model_handler; void *data_blob; @@ -56,12 +57,7 @@ static struct comp_dev *smart_amp_new(const struct comp_driver *drv, const struct comp_ipc_config *config, const void *spec) { -#if CONFIG_IPC_MAJOR_3 - const struct ipc_config_process *ipc_sa = spec; - const struct sof_smart_amp_config *cfg; -#else const struct ipc4_base_module_extended_cfg *base_cfg = spec; -#endif struct smart_amp_data *sad; struct comp_dev *dev; size_t bs; @@ -84,7 +80,6 @@ static struct comp_dev *smart_amp_new(const struct comp_driver *drv, k_mutex_init(&sad->lock); -#if CONFIG_IPC_MAJOR_4 if (base_cfg->base_cfg_ext.nb_input_pins != SMART_AMP_NUM_IN_PINS || base_cfg->base_cfg_ext.nb_output_pins != SMART_AMP_NUM_OUT_PINS) { comp_err(dev, "smart_amp_new(): Invalid pin configuration"); @@ -99,17 +94,6 @@ static struct comp_dev *smart_amp_new(const struct comp_driver *drv, bs = sizeof(sad->ipc4_cfg.input_pins) + sizeof(sad->ipc4_cfg.output_pin); memcpy_s(sad->ipc4_cfg.input_pins, bs, base_cfg->base_cfg_ext.pin_formats, bs); -#else - cfg = (struct sof_smart_amp_config *)ipc_sa->data; - bs = ipc_sa->size; - - if ((bs > 0) && (bs < sizeof(struct sof_smart_amp_config))) { - comp_err(dev, "smart_amp_new(): failed to apply config"); - goto sad_fail; - } - - memcpy_s(&sad->config, sizeof(struct sof_smart_amp_config), cfg, bs); -#endif dev->state = COMP_STATE_READY; @@ -123,7 +107,6 @@ static struct comp_dev *smart_amp_new(const struct comp_driver *drv, return NULL; } -#if CONFIG_IPC_MAJOR_4 static void smart_amp_set_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) { @@ -307,185 +290,6 @@ static int smart_amp_unbind(struct comp_dev *dev, void *data) return 0; } -#else - -static void smart_amp_set_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) -{ - //nothing to do -} - -static int smart_amp_set_config(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata) -{ - struct smart_amp_data *sad = comp_get_drvdata(dev); - struct sof_smart_amp_config *cfg; - size_t bs; - - /* Copy new config, find size from header */ - cfg = (struct sof_smart_amp_config *) - ASSUME_ALIGNED(&cdata->data->data, sizeof(uint32_t)); - bs = cfg->size; - - comp_dbg(dev, "smart_amp_set_config(), actual blob size = %u, expected blob size = %u", - bs, sizeof(struct sof_smart_amp_config)); - - if (bs != sizeof(struct sof_smart_amp_config)) { - comp_err(dev, "smart_amp_set_config(): invalid blob size, actual blob size = %u, expected blob size = %u", - bs, sizeof(struct sof_smart_amp_config)); - return -EINVAL; - } - - memcpy_s(&sad->config, sizeof(struct sof_smart_amp_config), cfg, - sizeof(struct sof_smart_amp_config)); - - return 0; -} - -static int smart_amp_get_config(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata, int size) -{ - struct smart_amp_data *sad = comp_get_drvdata(dev); - size_t bs; - int ret = 0; - - // Copy back to user space - bs = sad->config.size; - - comp_dbg(dev, "smart_amp_set_config(), actual blob size = %u, expected blob size = %u", - bs, sizeof(struct sof_smart_amp_config)); - - if (bs == 0 || bs > size) - return -EINVAL; - - ret = memcpy_s(cdata->data->data, size, &sad->config, bs); - assert(!ret); - - cdata->data->abi = SOF_ABI_VERSION; - cdata->data->size = bs; - - return ret; -} - -static int smart_amp_ctrl_get_bin_data(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata, - int size) -{ - struct smart_amp_data *sad = comp_get_drvdata(dev); - int ret = 0; - - assert(sad); - - switch (cdata->data->type) { - case SOF_SMART_AMP_CONFIG: - ret = smart_amp_get_config(dev, cdata, size); - break; - case SOF_SMART_AMP_MODEL: - ret = comp_data_blob_get_cmd(sad->model_handler, cdata, size); - break; - default: - comp_err(dev, "smart_amp_ctrl_get_bin_data(): unknown binary data type"); - break; - } - - return ret; -} - -static int smart_amp_ctrl_get_data(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata, int size) -{ - int ret = 0; - - comp_info(dev, "smart_amp_ctrl_get_data() size: %d", size); - - switch (cdata->cmd) { - case SOF_CTRL_CMD_BINARY: - ret = smart_amp_ctrl_get_bin_data(dev, cdata, size); - break; - default: - comp_err(dev, "smart_amp_ctrl_get_data(): invalid cdata->cmd"); - return -EINVAL; - } - - return ret; -} - -static int smart_amp_ctrl_set_bin_data(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata) -{ - struct smart_amp_data *sad = comp_get_drvdata(dev); - int ret = 0; - - assert(sad); - - if (dev->state < COMP_STATE_READY) { - comp_err(dev, "smart_amp_ctrl_set_bin_data(): driver in init!"); - return -EBUSY; - } - - switch (cdata->data->type) { - case SOF_SMART_AMP_CONFIG: - ret = smart_amp_set_config(dev, cdata); - break; - case SOF_SMART_AMP_MODEL: - ret = comp_data_blob_set_cmd(sad->model_handler, cdata); - break; - default: - comp_err(dev, "smart_amp_ctrl_set_bin_data(): unknown binary data type"); - break; - } - - return ret; -} - -static int smart_amp_ctrl_set_data(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata) -{ - int ret = 0; - - /* Check version from ABI header */ - if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { - comp_err(dev, "smart_amp_ctrl_set_data(): invalid version"); - return -EINVAL; - } - - switch (cdata->cmd) { - case SOF_CTRL_CMD_ENUM: - comp_info(dev, "smart_amp_ctrl_set_data(), SOF_CTRL_CMD_ENUM"); - break; - case SOF_CTRL_CMD_BINARY: - comp_info(dev, "smart_amp_ctrl_set_data(), SOF_CTRL_CMD_BINARY"); - ret = smart_amp_ctrl_set_bin_data(dev, cdata); - break; - default: - comp_err(dev, "smart_amp_ctrl_set_data(): invalid cdata->cmd"); - ret = -EINVAL; - break; - } - - return ret; -} - -/* used to pass standard and bespoke commands (with data) to component */ -static int smart_amp_cmd(struct comp_dev *dev, int cmd, void *data, - int max_data_size) -{ - struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4); - - comp_info(dev, "smart_amp_cmd(): cmd: %d", cmd); - - switch (cmd) { - case COMP_CMD_SET_DATA: - return smart_amp_ctrl_set_data(dev, cdata); - case COMP_CMD_GET_DATA: - return smart_amp_ctrl_get_data(dev, cdata, max_data_size); - default: - return -EINVAL; - } -} - -#endif /* CONFIG_IPC_MAJOR_4 */ - static void smart_amp_free(struct comp_dev *dev) { struct smart_amp_data *sad = comp_get_drvdata(dev); @@ -802,15 +606,11 @@ static const struct comp_driver comp_smart_amp = { .free = smart_amp_free, .params = smart_amp_params, .prepare = smart_amp_prepare, -#if CONFIG_IPC_MAJOR_4 .set_large_config = smart_amp_set_large_config, .get_large_config = smart_amp_get_large_config, .get_attribute = smart_amp_get_attribute, .bind = smart_amp_bind, .unbind = smart_amp_unbind, -#else - .cmd = smart_amp_cmd, -#endif /* CONFIG_IPC_MAJOR_4 */ .trigger = smart_amp_trigger, .copy = smart_amp_copy, .reset = smart_amp_reset, diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 813f6550c4f2..d00372c8cc54 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -637,9 +637,15 @@ zephyr_library_sources_ifdef(CONFIG_COMP_RTNR ${SOF_AUDIO_PATH}/rtnr/rtnr.c ) -zephyr_library_sources_ifdef(CONFIG_SAMPLE_SMART_AMP - ${SOF_SAMPLES_PATH}/audio/smart_amp_test.c -) +if(CONFIG_IPC_MAJOR_3) + zephyr_library_sources_ifdef(CONFIG_SAMPLE_SMART_AMP + ${SOF_SAMPLES_PATH}/audio/smart_amp_test_ipc3.c + ) +elseif(CONFIG_IPC_MAJOR_4) + zephyr_library_sources_ifdef(CONFIG_SAMPLE_SMART_AMP + ${SOF_SAMPLES_PATH}/audio/smart_amp_test_ipc4.c + ) +endif() zephyr_library_sources_ifdef(CONFIG_COMP_TDFB ${SOF_AUDIO_PATH}/tdfb/tdfb.c From 638b94151097ac675690bf149311687971be582c Mon Sep 17 00:00:00 2001 From: Andrula Song Date: Wed, 26 Apr 2023 13:15:57 +0800 Subject: [PATCH 28/94] Smart_amp: Remove the k_mute lock of IPC3 implementation Since smart_amp_test will always start feedback path firston IPC3 and the k_mute lock is added for IPC4 to support arbitrarily order of starting source path and feedback source. So remove the k_mute from IPC3 implementation. Signed-off-by: Andrula Song (cherry picked from commit 61bb3a08c4e29f097c1d53587c4f9dbf304e0698) --- src/samples/audio/smart_amp_test_ipc3.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/samples/audio/smart_amp_test_ipc3.c b/src/samples/audio/smart_amp_test_ipc3.c index 7425a0057f65..a8c9e0898dde 100644 --- a/src/samples/audio/smart_amp_test_ipc3.c +++ b/src/samples/audio/smart_amp_test_ipc3.c @@ -42,8 +42,6 @@ struct smart_amp_data { struct comp_buffer *feedback_buf; /**< feedback source buffer */ struct comp_buffer *sink_buf; /**< sink buffer */ - struct k_mutex lock; /**< protect feedback_buf updated */ - smart_amp_proc process; uint32_t in_channels; @@ -76,18 +74,14 @@ static struct comp_dev *smart_amp_new(const struct comp_driver *drv, if (!sad->model_handler) goto sad_fail; - k_mutex_init(&sad->lock); cfg = (struct sof_smart_amp_config *)ipc_sa->data; bs = ipc_sa->size; - if (bs > 0 && bs < sizeof(struct sof_smart_amp_config)) { comp_err(dev, "smart_amp_new(): failed to apply config"); goto sad_fail; } - memcpy_s(&sad->config, sizeof(struct sof_smart_amp_config), cfg, bs); - dev->state = COMP_STATE_READY; return dev; @@ -321,14 +315,11 @@ static int smart_amp_trigger(struct comp_dev *dev, int cmd) switch (cmd) { case COMP_TRIGGER_START: case COMP_TRIGGER_RELEASE: - k_mutex_lock(&sad->lock, K_FOREVER); if (sad->feedback_buf) { struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); - buffer_zero(buf); buffer_release(buf); } - k_mutex_unlock(&sad->lock); break; case COMP_TRIGGER_PAUSE: case COMP_TRIGGER_STOP: @@ -439,7 +430,6 @@ static int smart_amp_copy(struct comp_dev *dev) audio_stream_avail_frames(&source_buf->stream, &sink_buf->stream); - k_mutex_lock(&sad->lock, K_FOREVER); if (sad->feedback_buf) { struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); @@ -467,7 +457,6 @@ static int smart_amp_copy(struct comp_dev *dev) buffer_release(buf); } - k_mutex_unlock(&sad->lock); if (!avail_frames) avail_frames = avail_passthrough_frames; @@ -545,7 +534,6 @@ static int smart_amp_prepare(struct comp_dev *dev) buffer_c = buffer_acquire(sad->source_buf); sad->in_channels = audio_stream_get_channels(&buffer_c->stream); - k_mutex_lock(&sad->lock, K_FOREVER); if (sad->feedback_buf) { struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); @@ -553,7 +541,6 @@ static int smart_amp_prepare(struct comp_dev *dev) buf->stream.rate = audio_stream_get_rate(&buffer_c->stream); buffer_release(buf); } - k_mutex_unlock(&sad->lock); sad->process = get_smart_amp_process(dev, buffer_c); if (!sad->process) { From 2bc281ddc2dde952d18ee972177ba5b1ed129986 Mon Sep 17 00:00:00 2001 From: Andrula Song Date: Wed, 26 Apr 2023 17:27:57 +0800 Subject: [PATCH 29/94] Smart_amp: Convert IPC4 dummy smart_amp component to use the module adapter Convert the IPC4 dummy smart_amp(smart_amp_test_ipc4.c) module to use module adapter interface. And remove the k_mutex lock from struct smart_amp_data since the lock is used for bind/unbind thread and process thread. Now bind/unbind are removed, all lock reference is used in the same thread so we don't need it anymore. Signed-off-by: Andrula Song (cherry picked from commit 30a6db614c23cb30f5dc71cfd4663e3bcfac2f44) --- .../sof/samples/audio/smart_amp_test.h | 1 - src/samples/audio/smart_amp_test_ipc4.c | 530 ++++++------------ 2 files changed, 159 insertions(+), 372 deletions(-) diff --git a/src/include/sof/samples/audio/smart_amp_test.h b/src/include/sof/samples/audio/smart_amp_test.h index ed4a196f266b..7f24b5c37de8 100644 --- a/src/include/sof/samples/audio/smart_amp_test.h +++ b/src/include/sof/samples/audio/smart_amp_test.h @@ -94,7 +94,6 @@ struct sof_smart_amp_config { #define SMART_AMP_NUM_OUT_PINS 1 struct sof_smart_amp_ipc4_config { - struct ipc4_base_module_cfg base; struct ipc4_input_pin_format input_pins[SMART_AMP_NUM_IN_PINS]; struct ipc4_output_pin_format output_pin; }; diff --git a/src/samples/audio/smart_amp_test_ipc4.c b/src/samples/audio/smart_amp_test_ipc4.c index 2c297389553a..5af602fa91e2 100644 --- a/src/samples/audio/smart_amp_test_ipc4.c +++ b/src/samples/audio/smart_amp_test_ipc4.c @@ -3,9 +3,9 @@ // Copyright(c) 2020 Intel Corporation. All rights reserved. // // Author: Bartosz Kokoszko - #include #include +#include #include #include #include @@ -15,11 +15,8 @@ #ifndef __ZEPHYR__ #include #endif - #include -static const struct comp_driver comp_smart_amp; - LOG_MODULE_REGISTER(smart_amp_test, CONFIG_SOF_LOG_LEVEL); /* 167a961e-8ae4-11ea-89f1-000c29ce1635 */ @@ -28,102 +25,86 @@ DECLARE_SOF_RT_UUID("smart_amp-test", smart_amp_comp_uuid, 0x167a961e, 0x8ae4, DECLARE_TR_CTX(smart_amp_comp_tr, SOF_UUID(smart_amp_comp_uuid), LOG_LEVEL_INFO); - -typedef int(*smart_amp_proc)(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, uint32_t frames, +typedef int(*smart_amp_proc)(struct processing_module *mod, + struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames, int8_t *chan_map); - struct smart_amp_data { struct sof_smart_amp_ipc4_config ipc4_cfg; struct sof_smart_amp_config config; struct comp_data_blob_handler *model_handler; void *data_blob; size_t data_blob_size; - - struct comp_buffer *source_buf; /**< stream source buffer */ - struct comp_buffer *feedback_buf; /**< feedback source buffer */ - struct comp_buffer *sink_buf; /**< sink buffer */ - - struct k_mutex lock; /**< protect feedback_buf updated */ - smart_amp_proc process; - - uint32_t in_channels; uint32_t out_channels; }; -static struct comp_dev *smart_amp_new(const struct comp_driver *drv, - const struct comp_ipc_config *config, - const void *spec) +static int smart_amp_init(struct processing_module *mod) { - const struct ipc4_base_module_extended_cfg *base_cfg = spec; struct smart_amp_data *sad; - struct comp_dev *dev; - size_t bs; - - dev = comp_alloc(drv, sizeof(*dev)); - if (!dev) - return NULL; - dev->ipc_config = *config; + struct comp_dev *dev = mod->dev; + struct module_data *mod_data = &mod->priv; + int bs; + int ret; + const struct ipc4_base_module_extended_cfg *base_cfg = mod_data->cfg.init_data; + comp_dbg(dev, "smart_amp_init()"); sad = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*sad)); if (!sad) - goto fail; + return -ENOMEM; - comp_set_drvdata(dev, sad); + mod_data->private = sad; /* component model data handler */ sad->model_handler = comp_data_blob_handler_new(dev); - if (!sad->model_handler) + if (!sad->model_handler) { + ret = -ENOMEM; goto sad_fail; - - k_mutex_init(&sad->lock); + } if (base_cfg->base_cfg_ext.nb_input_pins != SMART_AMP_NUM_IN_PINS || base_cfg->base_cfg_ext.nb_output_pins != SMART_AMP_NUM_OUT_PINS) { - comp_err(dev, "smart_amp_new(): Invalid pin configuration"); + comp_err(dev, "smart_amp_init(): Invalid pin configuration"); + ret = -EINVAL; goto sad_fail; } - /* Copy the base_cfg */ - memcpy_s(&sad->ipc4_cfg.base, sizeof(sad->ipc4_cfg.base), - &base_cfg->base_cfg, sizeof(base_cfg->base_cfg)); - /* Copy the pin formats */ bs = sizeof(sad->ipc4_cfg.input_pins) + sizeof(sad->ipc4_cfg.output_pin); memcpy_s(sad->ipc4_cfg.input_pins, bs, base_cfg->base_cfg_ext.pin_formats, bs); - dev->state = COMP_STATE_READY; + mod->simple_copy = true; - return dev; + return 0; sad_fail: comp_data_blob_handler_free(sad->model_handler); rfree(sad); -fail: - rfree(dev); - return NULL; + return ret; } -static void smart_amp_set_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) +static void smart_amp_set_params(struct processing_module *mod) { - struct smart_amp_data *sad = comp_get_drvdata(dev); + const struct ipc4_audio_format *audio_fmt = &mod->priv.cfg.base_cfg.audio_fmt; + struct sof_ipc_stream_params *params = mod->stream_params; + struct comp_dev *dev = mod->dev; + struct smart_amp_data *sad = module_get_private_data(mod); struct comp_buffer *sink; struct comp_buffer __sparse_cache *sink_c; - - comp_dbg(dev, "smart_amp_set_params()"); + enum sof_ipc_frame frame_fmt, valid_fmt; + int i; memset(params, 0, sizeof(*params)); - params->channels = sad->ipc4_cfg.base.audio_fmt.channels_count; - params->rate = sad->ipc4_cfg.base.audio_fmt.sampling_frequency; - params->sample_container_bytes = sad->ipc4_cfg.base.audio_fmt.depth / 8; - params->sample_valid_bytes = - sad->ipc4_cfg.base.audio_fmt.valid_bit_depth / 8; - params->buffer_fmt = sad->ipc4_cfg.base.audio_fmt.interleaving_style; - params->buffer.size = sad->ipc4_cfg.base.ibs; + params->channels = audio_fmt->channels_count; + params->rate = audio_fmt->sampling_frequency; + params->sample_container_bytes = audio_fmt->depth / 8; + params->sample_valid_bytes = audio_fmt->valid_bit_depth / 8; + params->buffer_fmt = audio_fmt->interleaving_style; + params->buffer.size = mod->priv.cfg.base_cfg.ibs; + + for (i = 0; i < SOF_IPC_MAX_CHANNELS; i++) + params->chmap[i] = (audio_fmt->ch_map >> i * 4) & 0xf; /* update sink format */ if (!list_is_empty(&dev->bsink_list)) { @@ -145,236 +126,98 @@ static void smart_amp_set_params(struct comp_dev *dev, params->frame_fmt = sink_c->stream.frame_fmt; sink_c->hw_params_configured = true; - buffer_release(sink_c); } } -static inline int smart_amp_set_config(struct comp_dev *dev, const char *data, - uint32_t data_size) -{ - struct smart_amp_data *sad = comp_get_drvdata(dev); - struct sof_smart_amp_config *cfg; - uint32_t cfg_size; - - cfg = (struct sof_smart_amp_config *)data; - cfg_size = data_size; - - if (cfg_size != sizeof(struct sof_smart_amp_config)) { - comp_err(dev, "smart_amp_set_config(): invalid config size %u, expect %u", - cfg_size, sizeof(struct sof_smart_amp_config)); - return -EINVAL; - } - - comp_dbg(dev, "smart_amp_set_config(): config size = %u", cfg_size); - - memcpy_s(&sad->config, sizeof(struct sof_smart_amp_config), cfg, - sizeof(struct sof_smart_amp_config)); - - return 0; -} - -static inline int smart_amp_get_config(struct comp_dev *dev, char *data, - uint32_t *data_size) +static int smart_amp_set_config(struct processing_module *mod, uint32_t config_id, + enum module_cfg_fragment_position pos, uint32_t data_offset_size, + const uint8_t *fragment, size_t fragment_size, uint8_t *response, + size_t response_size) { - struct smart_amp_data *sad = comp_get_drvdata(dev); - uint32_t cfg_size; + struct comp_dev *dev = mod->dev; + struct smart_amp_data *sad = module_get_private_data(mod); - cfg_size = sizeof(struct sof_smart_amp_config); + comp_dbg(dev, "smart_amp_set_config()"); - if (cfg_size > *data_size) { - comp_err(dev, "smart_amp_get_config(): wrong config size %d", - *data_size); - } - - *data_size = cfg_size; - - return memcpy_s(data, cfg_size, &sad->config, cfg_size); -} - -static int smart_amp_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, - bool last_block, uint32_t data_offset, const char *data) -{ - struct smart_amp_data *sad = comp_get_drvdata(dev); - - comp_dbg(dev, "smart_amp_set_large_config()"); - - switch (param_id) { + switch (config_id) { case SMART_AMP_SET_MODEL: - return ipc4_comp_data_blob_set(sad->model_handler, - first_block, - last_block, - data_offset, - data); + return comp_data_blob_set(sad->model_handler, pos, + data_offset_size, fragment, fragment_size); case SMART_AMP_SET_CONFIG: - return smart_amp_set_config(dev, data, data_offset); - default: - return -EINVAL; - } -} - -static int smart_amp_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, - bool last_block, uint32_t *data_offset, char *data) -{ - comp_dbg(dev, "smart_amp_get_large_config()"); - - switch (param_id) { - case SMART_AMP_GET_CONFIG: - return smart_amp_get_config(dev, data, data_offset); + if (fragment_size != sizeof(sad->config)) { + comp_err(dev, "smart_amp_set_config(): invalid config size %u, expect %u", + fragment_size, sizeof(struct sof_smart_amp_config)); + return -EINVAL; + } + comp_dbg(dev, "smart_amp_set_config(): config size = %u", fragment_size); + memcpy_s(&sad->config, sizeof(sad->config), fragment, fragment_size); + return 0; default: return -EINVAL; } } -static int smart_amp_get_attribute(struct comp_dev *dev, uint32_t type, - void *value) +static inline int smart_amp_get_config(struct processing_module *mod, + uint32_t config_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) { - struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_data *sad = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + int ret; - comp_dbg(dev, "smart_amp_get_attribute()"); + comp_dbg(dev, "smart_amp_get_config()"); - switch (type) { - case COMP_ATTR_BASE_CONFIG: - *(struct ipc4_base_module_cfg *)value = sad->ipc4_cfg.base; + switch (config_id) { + case SMART_AMP_GET_CONFIG: + ret = memcpy_s(fragment, fragment_size, &sad->config, sizeof(sad->config)); + if (ret) { + comp_err(dev, "smart_amp_get_config(): wrong config size %d", + fragment_size); + return ret; + } + *data_offset_size = sizeof(sad->config); return 0; default: return -EINVAL; } } -static int smart_amp_bind(struct comp_dev *dev, void *data) -{ - struct smart_amp_data *sad = comp_get_drvdata(dev); - struct comp_buffer __sparse_cache *buffer_c; - struct comp_buffer *source_buffer; - struct list_item *blist; - - comp_dbg(dev, "smart_amp_bind()"); - - /* searching for feedback source buffers */ - list_for_item(blist, &dev->bsource_list) { - source_buffer = container_of(blist, struct comp_buffer, sink_list); - - k_mutex_lock(&sad->lock, K_FOREVER); - buffer_c = buffer_acquire(source_buffer); - if (IPC4_SINK_QUEUE_ID(buffer_c->id) == SOF_SMART_AMP_FEEDBACK_QUEUE_ID) { - sad->feedback_buf = source_buffer; - buffer_c->stream.channels = sad->config.feedback_channels; - buffer_c->stream.rate = sad->ipc4_cfg.base.audio_fmt.sampling_frequency; - - buffer_release(buffer_c); - k_mutex_unlock(&sad->lock); - break; - } - - buffer_release(buffer_c); - k_mutex_unlock(&sad->lock); - } - - return 0; -} - -static int smart_amp_unbind(struct comp_dev *dev, void *data) -{ - struct smart_amp_data *sad = comp_get_drvdata(dev); - struct ipc4_module_bind_unbind *bu = data; - - comp_dbg(dev, "smart_amp_unbind()"); - - if (bu->extension.r.dst_queue == SOF_SMART_AMP_FEEDBACK_QUEUE_ID) { - k_mutex_lock(&sad->lock, K_FOREVER); - sad->feedback_buf = NULL; - k_mutex_unlock(&sad->lock); - } - - return 0; -} - -static void smart_amp_free(struct comp_dev *dev) +static int smart_amp_free(struct processing_module *mod) { - struct smart_amp_data *sad = comp_get_drvdata(dev); - - comp_info(dev, "smart_amp_free()"); + struct smart_amp_data *sad = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + comp_dbg(dev, "smart_amp_free()"); comp_data_blob_handler_free(sad->model_handler); - rfree(sad); - rfree(dev); + return 0; } -static int smart_amp_verify_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) +static int smart_amp_params(struct processing_module *mod) { + struct sof_ipc_stream_params *params = mod->stream_params; + struct comp_dev *dev = mod->dev; int ret; - comp_info(dev, "smart_amp_verify_params()"); - + comp_dbg(dev, "smart_amp_params()"); + smart_amp_set_params(mod); ret = comp_verify_params(dev, BUFF_PARAMS_CHANNELS, params); if (ret < 0) { - comp_err(dev, "smart_amp_verify_params() error: comp_verify_params() failed."); - return ret; - } - - return 0; -} - -static int smart_amp_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) -{ - int err; - - comp_info(dev, "smart_amp_params()"); - - smart_amp_set_params(dev, params); - - err = smart_amp_verify_params(dev, params); - if (err < 0) { comp_err(dev, "smart_amp_params(): pcm params verification failed."); return -EINVAL; } - return 0; } -static int smart_amp_trigger(struct comp_dev *dev, int cmd) -{ - struct smart_amp_data *sad = comp_get_drvdata(dev); - int ret = 0; - - comp_info(dev, "smart_amp_trigger(), command = %u", cmd); - - ret = comp_set_state(dev, cmd); - - if (ret == COMP_STATUS_STATE_ALREADY_SET) - ret = PPL_STATUS_PATH_STOP; - - switch (cmd) { - case COMP_TRIGGER_START: - case COMP_TRIGGER_RELEASE: - k_mutex_lock(&sad->lock, K_FOREVER); - if (sad->feedback_buf) { - struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); - buffer_zero(buf); - buffer_release(buf); - } - k_mutex_unlock(&sad->lock); - break; - case COMP_TRIGGER_PAUSE: - case COMP_TRIGGER_STOP: - break; - default: - break; - } - - return ret; -} - -static int smart_amp_process_s16(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, +static int smart_amp_process_s16(struct processing_module *mod, + struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames, int8_t *chan_map) { - struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_data *sad = module_get_private_data(mod); + struct audio_stream __sparse_cache *source = bsource->data; + struct audio_stream __sparse_cache *sink = bsink->data; int16_t *src; int16_t *dest; uint32_t in_frag = 0; @@ -382,8 +225,7 @@ static int smart_amp_process_s16(struct comp_dev *dev, int i; int j; - comp_dbg(dev, "smart_amp_process_s16()"); - + bsource->consumed += frames * source->channels * sizeof(int16_t); for (i = 0; i < frames; i++) { for (j = 0 ; j < sad->out_channels; j++) { if (chan_map[j] != -1) { @@ -401,12 +243,14 @@ static int smart_amp_process_s16(struct comp_dev *dev, return 0; } -static int smart_amp_process_s32(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, +static int smart_amp_process_s32(struct processing_module *mod, + struct input_stream_buffer *bsource, + struct output_stream_buffer *bsink, uint32_t frames, int8_t *chan_map) { - struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_data *sad = module_get_private_data(mod); + struct audio_stream __sparse_cache *source = bsource->data; + struct audio_stream __sparse_cache *sink = bsink->data; int32_t *src; int32_t *dest; uint32_t in_frag = 0; @@ -414,8 +258,7 @@ static int smart_amp_process_s32(struct comp_dev *dev, int i; int j; - comp_dbg(dev, "smart_amp_process_s32()"); - + bsource->consumed += frames * source->channels * sizeof(int32_t); for (i = 0; i < frames; i++) { for (j = 0 ; j < sad->out_channels; j++) { if (chan_map[j] != -1) { @@ -449,183 +292,128 @@ static smart_amp_proc get_smart_amp_process(struct comp_dev *dev, } } -static int smart_amp_copy(struct comp_dev *dev) +static int smart_amp_process(struct processing_module *mod, + struct input_stream_buffer *input_buffers, int num_input_buffers, + struct output_stream_buffer *output_buffers, int num_output_buffers) { - struct smart_amp_data *sad = comp_get_drvdata(dev); - struct comp_buffer __sparse_cache *source_buf = buffer_acquire(sad->source_buf); - struct comp_buffer __sparse_cache *sink_buf = buffer_acquire(sad->sink_buf); + struct smart_amp_data *sad = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + struct comp_buffer __sparse_cache *fb_buf_c; + struct comp_buffer __sparse_cache *buf; + struct module_source_info __sparse_cache *mod_source_info; + struct input_stream_buffer *fb_input = NULL; + /* if there is only one input stream, it should be the source input */ + struct input_stream_buffer *src_input = &input_buffers[0]; uint32_t avail_passthrough_frames; - uint32_t avail_feedback_frames; uint32_t avail_frames = 0; - uint32_t source_bytes; uint32_t sink_bytes; - uint32_t feedback_bytes; + uint32_t i; - comp_dbg(dev, "smart_amp_copy()"); + mod_source_info = module_source_info_acquire(mod->source_info); - /* available bytes and samples calculation */ - avail_passthrough_frames = - audio_stream_avail_frames(&source_buf->stream, - &sink_buf->stream); + if (num_input_buffers == SMART_AMP_NUM_IN_PINS) + for (i = 0; i < num_input_buffers; i++) { + buf = attr_container_of(input_buffers[i].data, + struct comp_buffer __sparse_cache, + stream, __sparse_cache); - k_mutex_lock(&sad->lock, K_FOREVER); - if (sad->feedback_buf) { - struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); + if (IPC4_SINK_QUEUE_ID(buf->id) == SOF_SMART_AMP_FEEDBACK_QUEUE_ID) { + fb_input = &input_buffers[i]; + fb_buf_c = buf; + } else { + src_input = &input_buffers[i]; + } + } - if (buf->source && comp_get_state(dev, buf->source) == dev->state) { - /* feedback */ - avail_feedback_frames = - audio_stream_get_avail_frames(&buf->stream); + avail_passthrough_frames = src_input->size; + if (fb_input) { + if (fb_buf_c->source && comp_get_state(dev, fb_buf_c->source) == dev->state) { + /* feedback */ avail_frames = MIN(avail_passthrough_frames, - avail_feedback_frames); + fb_input->size); - feedback_bytes = avail_frames * - audio_stream_frame_bytes(&buf->stream); - - comp_dbg(dev, "smart_amp_copy(): processing %d feedback frames (avail_passthrough_frames: %d)", - avail_frames, avail_passthrough_frames); - - /* perform buffer writeback after source_buf process */ - buffer_stream_invalidate(buf, feedback_bytes); - sad->process(dev, &buf->stream, &sink_buf->stream, + sad->process(mod, fb_input, &output_buffers[0], avail_frames, sad->config.feedback_ch_map); - - comp_update_buffer_consume(buf, feedback_bytes); } - - buffer_release(buf); } - k_mutex_unlock(&sad->lock); if (!avail_frames) avail_frames = avail_passthrough_frames; - /* bytes calculation */ - source_bytes = avail_frames * - audio_stream_frame_bytes(&source_buf->stream); + /* bytes calculation */ sink_bytes = avail_frames * - audio_stream_frame_bytes(&sink_buf->stream); + audio_stream_frame_bytes(output_buffers[0].data); /* process data */ - buffer_stream_invalidate(source_buf, source_bytes); - sad->process(dev, &source_buf->stream, &sink_buf->stream, + sad->process(mod, src_input, &output_buffers[0], avail_frames, sad->config.source_ch_map); - buffer_stream_writeback(sink_buf, sink_bytes); - - /* source/sink buffer pointers update */ - comp_update_buffer_consume(source_buf, source_bytes); - comp_update_buffer_produce(sink_buf, sink_bytes); - buffer_release(sink_buf); - buffer_release(source_buf); + output_buffers[0].size = sink_bytes; + module_source_info_release(mod_source_info); return 0; } -static int smart_amp_reset(struct comp_dev *dev) +static int smart_amp_reset(struct processing_module *mod) { - comp_info(dev, "smart_amp_reset()"); + struct comp_dev *dev = mod->dev; - comp_set_state(dev, COMP_TRIGGER_RESET); + comp_dbg(dev, "smart_amp_reset()"); return 0; } -static int smart_amp_prepare(struct comp_dev *dev) +static int smart_amp_prepare(struct processing_module *mod) { - struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_data *sad = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; struct comp_buffer *source_buffer; + struct comp_buffer *sink_buffer; struct comp_buffer __sparse_cache *buffer_c; struct list_item *blist; int ret; - comp_info(dev, "smart_amp_prepare()"); - - ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); + ret = smart_amp_params(mod); if (ret < 0) return ret; - if (ret == COMP_STATUS_STATE_ALREADY_SET) - return PPL_STATUS_PATH_STOP; - + comp_dbg(dev, "smart_amp_prepare()"); /* searching for stream and feedback source buffers */ list_for_item(blist, &dev->bsource_list) { source_buffer = container_of(blist, struct comp_buffer, sink_list); buffer_c = buffer_acquire(source_buffer); - -#if CONFIG_IPC_MAJOR_3 - /* FIXME: how often can this loop be run? */ - if (buffer_c->source->ipc_config.type == SOF_COMP_DEMUX) - sad->feedback_buf = source_buffer; - else -#endif - sad->source_buf = source_buffer; - + audio_stream_init_alignment_constants(1, 1, &buffer_c->stream); + if (IPC4_SINK_QUEUE_ID(buffer_c->id) == SOF_SMART_AMP_FEEDBACK_QUEUE_ID) { + buffer_c->stream.channels = sad->config.feedback_channels; + buffer_c->stream.rate = mod->priv.cfg.base_cfg.audio_fmt.sampling_frequency; + } buffer_release(buffer_c); } - sad->sink_buf = list_first_item(&dev->bsink_list, struct comp_buffer, - source_list); - - buffer_c = buffer_acquire(sad->sink_buf); + sink_buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); + buffer_c = buffer_acquire(sink_buffer); sad->out_channels = buffer_c->stream.channels; + audio_stream_init_alignment_constants(1, 1, &buffer_c->stream); + sad->process = get_smart_amp_process(dev, buffer_c); buffer_release(buffer_c); - buffer_c = buffer_acquire(sad->source_buf); - sad->in_channels = buffer_c->stream.channels; - - k_mutex_lock(&sad->lock, K_FOREVER); - if (sad->feedback_buf) { - struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); - - buf->stream.channels = sad->config.feedback_channels; - buf->stream.rate = buffer_c->stream.rate; - buffer_release(buf); - } - k_mutex_unlock(&sad->lock); - - sad->process = get_smart_amp_process(dev, buffer_c); if (!sad->process) { comp_err(dev, "smart_amp_prepare(): get_smart_amp_process failed"); ret = -EINVAL; } - - buffer_release(buffer_c); - return ret; } -static const struct comp_driver comp_smart_amp = { - .type = SOF_COMP_SMART_AMP, - .uid = SOF_RT_UUID(smart_amp_comp_uuid), - .tctx = &smart_amp_comp_tr, - .ops = { - .create = smart_amp_new, - .free = smart_amp_free, - .params = smart_amp_params, - .prepare = smart_amp_prepare, - .set_large_config = smart_amp_set_large_config, - .get_large_config = smart_amp_get_large_config, - .get_attribute = smart_amp_get_attribute, - .bind = smart_amp_bind, - .unbind = smart_amp_unbind, - .trigger = smart_amp_trigger, - .copy = smart_amp_copy, - .reset = smart_amp_reset, - }, -}; - -static SHARED_DATA struct comp_driver_info comp_smart_amp_info = { - .drv = &comp_smart_amp, +static struct module_interface smart_amp_interface = { + .init = smart_amp_init, + .prepare = smart_amp_prepare, + .process = smart_amp_process, + .set_configuration = smart_amp_set_config, + .get_configuration = smart_amp_get_config, + .reset = smart_amp_reset, + .free = smart_amp_free }; - -UT_STATIC void sys_comp_smart_amp_init(void) -{ - comp_register(platform_shared_get(&comp_smart_amp_info, - sizeof(comp_smart_amp_info))); -} - -DECLARE_MODULE(sys_comp_smart_amp_init); -SOF_MODULE_INIT(smart_amp_test, sys_comp_smart_amp_init); +DECLARE_MODULE_ADAPTER(smart_amp_interface, smart_amp_comp_uuid, smart_amp_comp_tr); +SOF_MODULE_INIT(smart_amp_test, sys_comp_module_smart_amp_interface_init); From 5fae2cb7dee33364bbd119ee7122481b2b0ca9d4 Mon Sep 17 00:00:00 2001 From: Andrey Borisovich Date: Wed, 10 May 2023 12:35:34 +0200 Subject: [PATCH 30/94] ipc4: fixed possible null dereference Result of the function call ipc_get_comp_by_id() had been dereferenced without checking whether the pointer may be null. Returned pointer may be null when component does not exist on the list. Signed-off-by: Andrey Borisovich --- src/ipc/ipc4/helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index fa89c7abc35e..c3fc7bf96ccd 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -601,6 +601,8 @@ int ipc4_pipeline_complete(struct ipc *ipc, uint32_t comp_id) int ret; ipc_pipe = ipc_get_comp_by_id(ipc, comp_id); + if(!ipc_pipe) + return -EINVAL; /* Pass IPC to target core */ if (!cpu_is_me(ipc_pipe->core)) From 36a7a817fb8b79fb677e2e9a8fc0a0ac994af6a1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 11 May 2023 10:14:05 +0200 Subject: [PATCH 31/94] [PATCH] samples: smart_amp_test_ipc4: Split the pin configuration copy in init The original code confuses static code analyzers since it was relying on the fact that we have the 2x input and 1x output pin config in adjacent position in smart_amp_data struct similarly to the extended module configuration. While it works, it is not a good practice. Split the copy of input and output pin formats to make the code obvious and error prone. Fixes: bcc14074cd2b ("smart_amp_test: Split the module config and blob receiving for IPC4") Reported-by: Andrey Borisovich Signed-off-by: Peter Ujfalusi --- src/samples/audio/smart_amp_test_ipc4.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/samples/audio/smart_amp_test_ipc4.c b/src/samples/audio/smart_amp_test_ipc4.c index 5af602fa91e2..59b6c3a2fc9a 100644 --- a/src/samples/audio/smart_amp_test_ipc4.c +++ b/src/samples/audio/smart_amp_test_ipc4.c @@ -44,7 +44,8 @@ static int smart_amp_init(struct processing_module *mod) struct smart_amp_data *sad; struct comp_dev *dev = mod->dev; struct module_data *mod_data = &mod->priv; - int bs; + const uint8_t *src; + size_t copy_size; int ret; const struct ipc4_base_module_extended_cfg *base_cfg = mod_data->cfg.init_data; @@ -69,10 +70,17 @@ static int smart_amp_init(struct processing_module *mod) goto sad_fail; } - /* Copy the pin formats */ - bs = sizeof(sad->ipc4_cfg.input_pins) + sizeof(sad->ipc4_cfg.output_pin); - memcpy_s(sad->ipc4_cfg.input_pins, bs, - base_cfg->base_cfg_ext.pin_formats, bs); + /* + * Copy the pin formats. + * First the 2 x input formats then the following 1 x output format + */ + copy_size = sizeof(sad->ipc4_cfg.input_pins); + src = base_cfg->base_cfg_ext.pin_formats; + memcpy_s(sad->ipc4_cfg.input_pins, copy_size, src, copy_size); + + src += copy_size; + copy_size = sizeof(sad->ipc4_cfg.output_pin); + memcpy_s(&sad->ipc4_cfg.output_pin, copy_size, src, copy_size); mod->simple_copy = true; From e5056861f6a010aae53f936b70602794b3bd6d08 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Mon, 15 May 2023 12:23:52 +0200 Subject: [PATCH 32/94] module_adapter: Fix for multi-core usage ipc4_create_buffer() uses comp_get_attribute(, COMP_ATTR_BASE_CONFIG, ) which returns module's struct processing_module::priv.cfg.base_cfg. Since buffer and module could be created on different cores, this fix makes sure module's struct processing_module is allocated in non-cached memory and can be read from any core. Signed-off-by: Serhiy Katsyuba --- src/audio/module_adapter/module_adapter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 869221c83460..e53eda4212e8 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -55,7 +55,7 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv, dev->ipc_config = *config; dev->drv = drv; - mod = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*mod)); + mod = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*mod)); if (!mod) { comp_err(dev, "module_adapter_new(), failed to allocate memory for module"); rfree(dev); From 70ee7089253b94c0861d70b9d2da1ec0dd843bce Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Mon, 15 May 2023 12:38:44 +0200 Subject: [PATCH 33/94] Fix pipeline allocation for multi-core usage pipeline_get_dai_comp_latency() iterates over all pipelines and reaches to struct pipeline::pipeline_id. This fix ensures that struct pipeline can be read from any core. Signed-off-by: Serhiy Katsyuba --- src/audio/pipeline/pipeline-graph.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index 809ab7c49d40..bf22fbdf3b23 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -122,7 +122,7 @@ struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t heap_trace_all(0); /* allocate new pipeline */ - p = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*p)); + p = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*p)); if (!p) { pipe_cl_err("pipeline_new(): Out of Memory"); return NULL; From 131defb0bed2c9ab429f87413c084b9ce8c2fa46 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Tue, 16 May 2023 16:21:27 +0200 Subject: [PATCH 34/94] ipc4: mixin/mixout multi-core support Reimplementation of mixin/mixout to support multi-core case when connected mixin and mixout are running on different cores. Previous implementation had dead lock problem. Signed-off-by: Serhiy Katsyuba --- src/audio/mixin_mixout/mixin_mixout.c | 525 ++++++++++---------------- 1 file changed, 198 insertions(+), 327 deletions(-) diff --git a/src/audio/mixin_mixout/mixin_mixout.c b/src/audio/mixin_mixout/mixin_mixout.c index f549e631ba22..fd17fdf22057 100644 --- a/src/audio/mixin_mixout/mixin_mixout.c +++ b/src/audio/mixin_mixout/mixin_mixout.c @@ -46,24 +46,6 @@ DECLARE_TR_CTX(mixout_tr, SOF_UUID(mixout_uuid), LOG_LEVEL_INFO); #define MIXIN_MAX_SINKS IPC4_MIXIN_MODULE_MAX_OUTPUT_QUEUES #define MIXOUT_MAX_SOURCES IPC4_MIXOUT_MODULE_MAX_INPUT_QUEUES -/* - * Unfortunately, if we have to support a topology with a single mixin - * connected to multiple mixouts, we cannot use simple implementation as in - * mixer component. We either need to use intermediate buffer between mixin and - * mixout, or use a more complex implementation as described below. - * - * This implementation does not use buffer between mixin and mixout. Mixed - * data is written directly to mixout sink buffer. Most of the mixing is done - * by mixins in mixin_process(). Simply speaking, if no data present in mixout - * sink -- mixin just copies its source data to mixout sink. If mixout sink - * has some data (written there previously by some other mixin) -- mixin reads - * data from mixout sink, mixes it with its source data and writes back to - * mixout sink. - * - * Such implementation has less buffer reads/writes than simple implementation - * using intermediate buffer between mixin and mixout. - */ - struct mixin_sink_config { enum ipc4_mixer_mode mixer_mode; uint32_t output_channel_count; @@ -74,24 +56,16 @@ struct mixin_sink_config { /* mixin component private data */ struct mixin_data { - normal_mix_func normal_mix_channel; - remap_mix_func remap_mix_channel; - mute_func mute_channel; struct mixin_sink_config sink_config[MIXIN_MAX_SINKS]; + + void (*gain_func)(struct audio_stream *stream, uint32_t sample_count, + uint16_t gain_mul, uint8_t gain_shift); }; -/* mixout component private data. This can be accessed from different cores. */ +/* mixout component private data */ struct mixout_data { - /* number of currently mixed frames in mixout sink buffer */ - uint32_t mixed_frames; - /* - * Source data is consumed by mixins in mixin_process() but sink data cannot be - * immediately produced. Sink data is produced by mixout in mixout_process() after - * ensuring all connected mixins have mixed their data into mixout sink buffer. - * So for each connected mixin, mixout keeps knowledge of data already consumed - * by mixin but not yet produced in mixout. - */ - uint32_t pending_frames[MIXOUT_MAX_SOURCES]; + void (* mix_func)(const struct audio_stream *source, struct audio_stream *sink, + uint32_t sample_count); }; static int mixin_init(struct processing_module *mod) @@ -122,15 +96,14 @@ static int mixin_init(struct processing_module *mod) dev->ipc_config.frame_fmt = frame_fmt; mod->simple_copy = true; - mod->skip_src_buffer_invalidate = true; return 0; } static int mixout_init(struct processing_module *mod) { - struct module_source_info __sparse_cache *mod_source_info; struct comp_dev *dev = mod->dev; + struct module_data *mod_data = &mod->priv; struct mixout_data *mo_data; enum sof_ipc_frame __sparse_cache frame_fmt, valid_fmt; @@ -140,9 +113,7 @@ static int mixout_init(struct processing_module *mod) if (!mo_data) return -ENOMEM; - mod_source_info = module_source_info_acquire(mod->source_info); - mod_source_info->private = mo_data; - module_source_info_release(mod_source_info); + mod_data->private = mo_data; audio_stream_fmt_conversion(mod->priv.cfg.base_cfg.audio_fmt.depth, mod->priv.cfg.base_cfg.audio_fmt.valid_bit_depth, @@ -151,7 +122,6 @@ static int mixout_init(struct processing_module *mod) dev->ipc_config.frame_fmt = frame_fmt; mod->simple_copy = true; - mod->skip_sink_buffer_writeback = true; return 0; } @@ -169,21 +139,17 @@ static int mixin_free(struct processing_module *mod) static int mixout_free(struct processing_module *mod) { - struct module_source_info __sparse_cache *mod_source_info; + struct mixout_data *md = module_get_private_data(mod); comp_dbg(mod->dev, "mixout_free()"); - - mod_source_info = module_source_info_acquire(mod->source_info); - rfree(mod_source_info->private); - mod_source_info->private = NULL; - module_source_info_release(mod_source_info); + rfree(md); return 0; } -static int mix_and_remap(struct comp_dev *dev, const struct mixin_data *mixin_data, +/* Currently only does copy with gain. Remapping is not implemented. */ +static int copy_and_remap(struct comp_dev *dev, const struct mixin_data *mixin_data, uint16_t sink_index, struct audio_stream __sparse_cache *sink, - uint32_t start_frame, uint32_t mixed_frames, const struct audio_stream __sparse_cache *source, uint32_t frame_count) { const struct mixin_sink_config *sink_config; @@ -197,37 +163,14 @@ static int mix_and_remap(struct comp_dev *dev, const struct mixin_data *mixin_da sink_config = &mixin_data->sink_config[sink_index]; if (sink_config->mixer_mode == IPC4_MIXER_NORMAL_MODE) { - /* Mix streams. mix_channel() is reused here to mix streams, not individual - * channels. To do so, (multichannel) stream is treated as single channel: - * channel count is passed as 1, channel index is 0, frame indices (start_frame - * and mixed_frame) and frame count are multiplied by real stream channel count. - */ - mixin_data->normal_mix_channel(sink, start_frame * sink->channels, - mixed_frames * sink->channels, source, - frame_count * sink->channels, sink_config->gain); + audio_stream_copy(source, 0, sink, 0, frame_count * sink->channels); + + if (sink_config->gain != IPC4_MIXIN_UNITY_GAIN) + mixin_data->gain_func(sink, frame_count * sink->channels, + sink_config->gain, IPC4_MIXIN_GAIN_SHIFT); } else if (sink_config->mixer_mode == IPC4_MIXER_CHANNEL_REMAPPING_MODE) { - int i; - - for (i = 0; i < sink->channels; i++) { - uint8_t source_channel = - (sink_config->output_channel_map >> (i * 4)) & 0xf; - - if (source_channel == 0xf) { - mixin_data->mute_channel(sink, i, start_frame, mixed_frames, - frame_count); - } else { - if (source_channel >= source->channels) { - comp_err(dev, "Out of range chmap: 0x%x, src channels: %u", - sink_config->output_channel_map, - source->channels); - return -EINVAL; - } - mixin_data->remap_mix_channel(sink, i, sink->channels, start_frame, - mixed_frames, source, source_channel, - source->channels, frame_count, - sink_config->gain); - } - } + comp_err(dev, "Remapping mode is not implemented!"); + return -EINVAL; } else { comp_err(dev, "Unexpected mixer mode: %d", sink_config->mixer_mode); return -EINVAL; @@ -236,49 +179,6 @@ static int mix_and_remap(struct comp_dev *dev, const struct mixin_data *mixin_da return 0; } -/* mix silence into stream, i.e. set not yet mixed data in stream to zero */ -static void silence(struct audio_stream __sparse_cache *stream, uint32_t start_frame, - uint32_t mixed_frames, uint32_t frame_count) -{ - uint32_t skip_mixed_frames; - uint8_t *ptr; - uint32_t size; - int n; - - assert(mixed_frames >= start_frame); - skip_mixed_frames = mixed_frames - start_frame; - - if (frame_count <= skip_mixed_frames) - return; - - size = audio_stream_period_bytes(stream, frame_count - skip_mixed_frames); - ptr = (uint8_t *)stream->w_ptr + audio_stream_period_bytes(stream, mixed_frames); - - while (size) { - ptr = audio_stream_wrap(stream, ptr); - n = MIN(audio_stream_bytes_without_wrap(stream, ptr), size); - memset(ptr, 0, n); - size -= n; - ptr += n; - } -} - -/* Most of the mixing is done here on mixin side. mixin mixes its source data - * into each connected mixout sink buffer. Basically, if mixout sink buffer has - * no data, mixin copies its source data into mixout sink buffer. If mixout sink - * buffer has some data (written there by other mixin), mixin reads mixout sink - * buffer data, mixes it with its source data and writes back to mixout sink - * buffer. So after all mixin mixin_process() calls, mixout sink buffer contains - * mixed data. Every mixin calls xxx_consume() on its processed source data, but - * they do not call xxx_produce(). That is done on mixout side in mixout_process(). - * - * Since there is no garantie that mixout processing is done in time we have - * to account for a possibility having not yet produced data in mixout sink - * buffer that was written there on previous run(s) of mixin_process(). So for each - * mixin <--> mixout pair we track consumed_yet_not_produced data amount. - * That value is also used in mixout_process() to calculate how many data was - * actually mixed and so xxx_produce() is called for that amount. - */ static int mixin_process(struct processing_module *mod, struct input_stream_buffer *input_buffers, int num_input_buffers, struct output_stream_buffer *output_buffers, int num_output_buffers) @@ -286,11 +186,9 @@ static int mixin_process(struct processing_module *mod, struct mixin_data *mixin_data = module_get_private_data(mod); struct comp_dev *dev = mod->dev; uint32_t source_avail_frames, sinks_free_frames; - struct comp_dev *active_mixouts[MIXIN_MAX_SINKS]; uint16_t sinks_ids[MIXIN_MAX_SINKS]; uint32_t bytes_to_consume_from_source_buf; uint32_t frames_to_copy; - int source_index; int i, ret; comp_dbg(dev, "mixin_process()"); @@ -310,255 +208,224 @@ static int mixin_process(struct processing_module *mod, /* first, let's find out how many frames can be now processed -- * it is a nimimal value among frames available in source buffer - * and frames free in each connected mixout sink buffer. + * and frames free in each connected mixin sink buffer. */ for (i = 0; i < num_output_buffers; i++) { - struct comp_buffer __sparse_cache *unused_in_between_buf_c; - struct comp_dev *mixout; - uint16_t sink_id; - struct comp_buffer *sink; - struct mixout_data *mixout_data; - struct processing_module *mixout_mod; - struct module_source_info __sparse_cache *mod_source_info; struct comp_buffer __sparse_cache *sink_c; - uint32_t free_frames, pending_frames; - /* unused buffer between mixin and mixout */ - unused_in_between_buf_c = attr_container_of(output_buffers[i].data, + sink_c = attr_container_of(output_buffers[i].data, struct comp_buffer __sparse_cache, stream, __sparse_cache); - mixout = unused_in_between_buf_c->sink; - sink_id = IPC4_SRC_QUEUE_ID(unused_in_between_buf_c->id); - - active_mixouts[i] = mixout; - sinks_ids[i] = sink_id; - - sink = list_first_item(&mixout->bsink_list, struct comp_buffer, source_list); - - mixout_mod = comp_get_drvdata(mixout); - mod_source_info = module_source_info_acquire(mixout_mod->source_info); - mixout_data = mod_source_info->private; - source_index = find_module_source_index(mod_source_info, dev); - if (source_index < 0) { - comp_err(dev, "No source info"); - module_source_info_release(mod_source_info); - return -EINVAL; - } - - sink_c = buffer_acquire(sink); + sinks_ids[i] = IPC4_SRC_QUEUE_ID(sink_c->id); /* Normally this should never happen as we checked above - * that mixout is in active state and so its sink buffer - * should be already initialized in mixout .params(). + * that mixin is in active state and so its sink buffer + * should be already initialized in mixin .params(). */ if (!sink_c->hw_params_configured) { - comp_err(dev, "Uninitialized mixout sink buffer!"); - buffer_release(sink_c); - module_source_info_release(mod_source_info); + comp_err(dev, "Uninitialized mixin sink buffer!"); return -EINVAL; } - free_frames = audio_stream_get_free_frames(&sink_c->stream); - - /* mixout sink buffer may still have not yet produced data -- data - * consumed and written there by mixin on previous mixin_process() run. - * We do NOT want to overwrite that data. - */ - pending_frames = mixout_data->pending_frames[source_index]; - assert(free_frames >= pending_frames); - sinks_free_frames = MIN(sinks_free_frames, free_frames - pending_frames); - - buffer_release(sink_c); - module_source_info_release(mod_source_info); + sinks_free_frames = MIN(audio_stream_get_free_frames(output_buffers[i].data), + sinks_free_frames); } if (source_avail_frames > 0) { - struct comp_buffer __sparse_cache *source_c; - frames_to_copy = MIN(source_avail_frames, sinks_free_frames); bytes_to_consume_from_source_buf = audio_stream_period_bytes(input_buffers[0].data, frames_to_copy); - if (bytes_to_consume_from_source_buf > 0) { - input_buffers[0].consumed = bytes_to_consume_from_source_buf; - source_c = attr_container_of(input_buffers[0].data, - struct comp_buffer __sparse_cache, - stream, __sparse_cache); - buffer_stream_invalidate(source_c, bytes_to_consume_from_source_buf); - } + input_buffers[0].consumed = bytes_to_consume_from_source_buf; } else { /* if source does not produce any data -- do NOT block mixing but generate * silence as that source output. * * here frames_to_copy is silence size. */ + /* FIXME: This will not work with 44.1 kHz !!! */ frames_to_copy = MIN(dev->frames, sinks_free_frames); } - /* iterate over all connected mixouts and mix source data into each mixout sink buffer */ for (i = 0; i < num_output_buffers; i++) { - struct comp_dev *mixout; - struct comp_buffer *sink; - struct mixout_data *mixout_data; - struct module_source_info __sparse_cache *mod_source_info; - struct processing_module *mixout_mod; - uint32_t start_frame; - struct comp_buffer __sparse_cache *sink_c; - uint32_t writeback_size; - - mixout = active_mixouts[i]; - sink = list_first_item(&mixout->bsink_list, struct comp_buffer, source_list); - - mixout_mod = comp_get_drvdata(mixout); - mod_source_info = module_source_info_acquire(mixout_mod->source_info); - mixout_data = mod_source_info->private; - source_index = find_module_source_index(mod_source_info, dev); - if (source_index < 0) { - comp_err(dev, "No source info"); - module_source_info_release(mod_source_info); - return -EINVAL; - } - - /* Skip data from previous run(s) not yet produced in mixout_process(). - * Normally start_frame would be 0 unless mixout pipeline has serious - * performance problems with processing data on time in mixout. - */ - start_frame = mixout_data->pending_frames[source_index]; - - sink_c = buffer_acquire(sink); - /* if source does not produce any data but mixin is in active state -- generate * silence instead of that source data */ if (source_avail_frames == 0) { /* generate silence */ - silence(&sink_c->stream, start_frame, mixout_data->mixed_frames, - frames_to_copy); + audio_stream_set_zero(output_buffers[i].data, + audio_stream_period_bytes(output_buffers[i].data, + frames_to_copy)); } else { - /* basically, if sink buffer has no data -- copy source data there, if - * sink buffer has some data (written by another mixin) mix that data - * with source data. - */ - ret = mix_and_remap(dev, mixin_data, sinks_ids[i], &sink_c->stream, - start_frame, mixout_data->mixed_frames, + ret = copy_and_remap(dev, mixin_data, sinks_ids[i], output_buffers[i].data, input_buffers[0].data, frames_to_copy); if (ret < 0) { - buffer_release(sink_c); - module_source_info_release(mod_source_info); return ret; } } - /* it would be better to writeback memory region starting from start_frame and - * of frames_to_copy size (converted to bytes, of course). However, seems - * there is no appropreate API. Anyway, start_frame would be 0 most of the time. - */ - writeback_size = audio_stream_period_bytes(&sink_c->stream, - frames_to_copy + start_frame); - if (writeback_size > 0) - buffer_stream_writeback(sink_c, writeback_size); - buffer_release(sink_c); + output_buffers[i].size = audio_stream_period_bytes(output_buffers[i].data, + frames_to_copy); + } - mixout_data->pending_frames[source_index] += frames_to_copy; + return 0; +} - if (frames_to_copy + start_frame > mixout_data->mixed_frames) - mixout_data->mixed_frames = frames_to_copy + start_frame; +static void apply_gain_s16(struct audio_stream *stream, uint32_t sample_count, + uint16_t gain_mul, uint8_t gain_shift) +{ + int16_t *ptr = stream->w_ptr; - module_source_info_release(mod_source_info); + while (sample_count > 0) { + uint32_t i, n; + + ptr = audio_stream_wrap(stream, ptr); + n = MIN(audio_stream_samples_without_wrap_s16(stream, ptr), sample_count); + + for (i = 0; i < n; i++) { + *ptr = ((int32_t)*ptr * gain_mul) >> gain_shift; + ptr++; + } + + sample_count -= n; } +} - return 0; +static void apply_gain_s32(struct audio_stream *stream, uint32_t sample_count, + uint16_t gain_mul, uint8_t gain_shift) +{ + int32_t *ptr = stream->w_ptr; + + while (sample_count > 0) { + uint32_t i, n; + + ptr = audio_stream_wrap(stream, ptr); + n = MIN(audio_stream_samples_without_wrap_s32(stream, ptr), sample_count); + + for (i = 0; i < n; i++) { + *ptr = ((int64_t)*ptr * gain_mul) >> gain_shift; + ptr++; + } + + sample_count -= n; + } +} + +static void mix_s16(const struct audio_stream *source, struct audio_stream *sink, + uint32_t sample_count) +{ + int16_t *src = source->r_ptr; + int16_t *dst = sink->w_ptr; + + while (sample_count > 0) { + uint32_t i, n; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + n = MIN(audio_stream_samples_without_wrap_s16(source, src), + audio_stream_samples_without_wrap_s16(sink, dst)); + n = MIN(n, sample_count); + + for (i = 0; i < n; i++) { + *dst = sat_int16((int32_t)*src + (int32_t)*dst); + src++; + dst++; + } + + sample_count -= n; + } +} + +static void mix_s24(const struct audio_stream *source, struct audio_stream *sink, + uint32_t sample_count) +{ + int32_t *src = source->r_ptr; + int32_t *dst = sink->w_ptr; + + while (sample_count > 0) { + uint32_t i, n; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + n = MIN(audio_stream_samples_without_wrap_s32(source, src), + audio_stream_samples_without_wrap_s32(sink, dst)); + n = MIN(n, sample_count); + + for (i = 0; i < n; i++) { + *dst = sat_int24(*src + *dst); + src++; + dst++; + } + + sample_count -= n; + } +} + +static void mix_s32(const struct audio_stream *source, struct audio_stream *sink, + uint32_t sample_count) +{ + int32_t *src = source->r_ptr; + int32_t *dst = sink->w_ptr; + + while (sample_count > 0) { + uint32_t i, n; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + n = MIN(audio_stream_samples_without_wrap_s32(source, src), + audio_stream_samples_without_wrap_s32(sink, dst)); + n = MIN(n, sample_count); + + for (i = 0; i < n; i++) { + *dst = sat_int32((int64_t)*src + (int64_t)*dst); + src++; + dst++; + } + + sample_count -= n; + } } -/* mixout just calls xxx_produce() on data mixed into its sink buffer by - * mixins. - */ static int mixout_process(struct processing_module *mod, struct input_stream_buffer *input_buffers, int num_input_buffers, struct output_stream_buffer *output_buffers, int num_output_buffers) { - struct module_source_info __sparse_cache *mod_source_info; struct comp_dev *dev = mod->dev; - struct mixout_data *md; - uint32_t frames_to_produce = INT32_MAX; - uint32_t pending_frames; - uint32_t sink_bytes; + struct mixout_data *md = module_get_private_data(mod); + uint32_t avail_samples = INT32_MAX; int i; comp_dbg(dev, "mixout_process()"); - mod_source_info = module_source_info_acquire(mod->source_info); - md = mod_source_info->private; - - /* iterate over all connected mixins to find minimal value of frames they consumed - * (i.e., mixed into mixout sink buffer). That is the amount that can/should be - * produced now. - */ for (i = 0; i < num_input_buffers; i++) { - const struct audio_stream __sparse_cache *source_stream; - struct comp_buffer __sparse_cache *unused_in_between_buf; - struct comp_dev *source; - int source_index; - - source_stream = input_buffers[i].data; - unused_in_between_buf = attr_container_of(source_stream, - struct comp_buffer __sparse_cache, - stream, __sparse_cache); - - source = unused_in_between_buf->source; + avail_samples = MIN(audio_stream_get_avail_samples(input_buffers[i].data), + avail_samples); + } - source_index = find_module_source_index(mod_source_info, source); - /* this shouldn't happen but skip even if it does and move to the next source */ - if (source_index < 0) - continue; + if (avail_samples > 0 && avail_samples < INT32_MAX) { + uint32_t samples_to_mix = MIN(audio_stream_get_free_samples(output_buffers[0].data), avail_samples); + uint32_t bytes_to_mix = samples_to_mix * audio_stream_sample_bytes(output_buffers[0].data); - pending_frames = md->pending_frames[source_index]; + audio_stream_copy(input_buffers[0].data, 0, output_buffers[0].data, 0, samples_to_mix); + input_buffers[0].consumed = bytes_to_mix; - if (source->state == COMP_STATE_ACTIVE || pending_frames) - frames_to_produce = MIN(frames_to_produce, pending_frames); - } - - if (frames_to_produce > 0 && frames_to_produce < INT32_MAX) { - for (i = 0; i < num_input_buffers; i++) { - const struct audio_stream __sparse_cache *source_stream; - struct comp_buffer __sparse_cache *unused_in_between_buf; - struct comp_dev *source; - int source_index; - uint32_t pending_frames; - - source_stream = input_buffers[i].data; - unused_in_between_buf = attr_container_of(source_stream, - struct comp_buffer __sparse_cache, - stream, __sparse_cache); - - source = unused_in_between_buf->source; - - source_index = find_module_source_index(mod_source_info, source); - if (source_index < 0) - continue; - - pending_frames = md->pending_frames[source_index]; - if (pending_frames >= frames_to_produce) - md->pending_frames[source_index] -= frames_to_produce; - else - md->pending_frames[source_index] = 0; + for (i = 1; i < num_input_buffers; i++) { + md->mix_func(input_buffers[i].data, output_buffers[0].data, samples_to_mix); + input_buffers[i].consumed = bytes_to_mix; } - assert(md->mixed_frames >= frames_to_produce); - md->mixed_frames -= frames_to_produce; - - sink_bytes = frames_to_produce * - audio_stream_frame_bytes(output_buffers[0].data); - output_buffers[0].size = sink_bytes; + output_buffers[0].size = bytes_to_mix; } else { - sink_bytes = dev->frames * audio_stream_frame_bytes(output_buffers[0].data); + /* FIXME: That will not work with 44.1 kHz !!! */ + uint32_t sink_bytes = MIN(audio_stream_get_free_frames(output_buffers[0].data), dev->frames) * audio_stream_frame_bytes(output_buffers[0].data); if (!audio_stream_set_zero(output_buffers[0].data, sink_bytes)) output_buffers[0].size = sink_bytes; else output_buffers[0].size = 0; } - module_source_info_release(mod_source_info); - return 0; } @@ -569,20 +436,21 @@ static int mixin_reset(struct processing_module *mod) comp_dbg(dev, "mixin_reset()"); - mixin_data->normal_mix_channel = NULL; - mixin_data->remap_mix_channel = NULL; - mixin_data->mute_channel = NULL; + mixin_data->gain_func = NULL; return 0; } static int mixout_reset(struct processing_module *mod) { + struct mixout_data *mixout_data = module_get_private_data(mod); struct comp_dev *dev = mod->dev; struct list_item *blist; comp_dbg(dev, "mixout_reset()"); + mixout_data->mix_func = NULL; + /* FIXME: move this to module_adapter_reset() */ if (dev->pipeline->source_comp->direction == SOF_IPC_STREAM_PLAYBACK) { list_for_item(blist, &dev->bsource_list) { @@ -622,9 +490,6 @@ static int mixin_params(struct processing_module *mod) base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); - /* Buffers between mixins and mixouts are not used (mixin writes data directly to mixout - * sink). But, anyway, let's setup these buffers properly just in case. - */ list_for_item(blist, &dev->bsink_list) { struct comp_buffer *sink; struct comp_buffer __sparse_cache *sink_c; @@ -701,22 +566,17 @@ static int mixin_prepare(struct processing_module *mod) /* currently inactive so setup mixer */ switch (fmt) { case SOF_IPC_FRAME_S16_LE: + md->gain_func = apply_gain_s16; + break; case SOF_IPC_FRAME_S24_4LE: case SOF_IPC_FRAME_S32_LE: - md->normal_mix_channel = normal_mix_get_processing_function(fmt); - md->remap_mix_channel = remap_mix_get_processing_function(fmt); - md->mute_channel = mute_mix_get_processing_function(fmt); + md->gain_func = apply_gain_s32; break; default: comp_err(dev, "unsupported data format %d", fmt); return -EINVAL; } - if (!md->normal_mix_channel || !md->remap_mix_channel || !md->mute_channel) { - comp_err(dev, "have not found the suitable processing function"); - return -EINVAL; - } - return 0; } @@ -796,10 +656,12 @@ static int mixout_params(struct processing_module *mod) static int mixout_prepare(struct processing_module *mod) { - struct module_source_info __sparse_cache *mod_source_info; struct comp_dev *dev = mod->dev; - struct mixout_data *md; - int ret, i; + struct mixout_data *md = module_get_private_data(mod); + struct comp_buffer *sink; + struct comp_buffer __sparse_cache *sink_c; + enum sof_ipc_frame fmt; + int ret; ret = mixout_params(mod); if (ret < 0) @@ -807,17 +669,26 @@ static int mixout_prepare(struct processing_module *mod) comp_dbg(dev, "mixout_prepare()"); - /* - * Since mixout sink buffer stream is reset on .prepare(), let's - * reset counters for not yet produced frames in that buffer. - */ - mod_source_info = module_source_info_acquire(mod->source_info); - md = mod_source_info->private; - md->mixed_frames = 0; + sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); + sink_c = buffer_acquire(sink); + fmt = sink_c->stream.valid_sample_fmt; + buffer_release(sink_c); - for (i = 0; i < MIXOUT_MAX_SOURCES; i++) - md->pending_frames[i] = 0; - module_source_info_release(mod_source_info); + /* currently inactive so setup mixout */ + switch (fmt) { + case SOF_IPC_FRAME_S16_LE: + md->mix_func = mix_s16; + break; + case SOF_IPC_FRAME_S24_4LE: + md->mix_func = mix_s24; + break; + case SOF_IPC_FRAME_S32_LE: + md->mix_func = mix_s32; + break; + default: + comp_err(dev, "unsupported data format %d", fmt); + return -EINVAL; + } return 0; } From 87dc723abd965caeba19ead34f6d754f60e5672c Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Wed, 10 May 2023 14:28:18 +0200 Subject: [PATCH 35/94] dai: always reload dma ll chain Reload the dma descriptor chain even if there are no bytes to copy. This may result in the loss of some data, but at least the dma will not stop. Signed-off-by: Adrian Warecki --- src/audio/dai-zephyr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 92a16501a327..034f10945b87 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -1287,6 +1287,7 @@ static int dai_copy(struct comp_dev *dev) /* return if nothing to copy */ if (!copy_bytes) { comp_warn(dev, "dai_copy(): nothing to copy"); + dma_reload(dd->chan->dma->z_dev, dd->chan->index, 0, 0, 0); return 0; } From a2ce0d116521d54ea9cb205929806741dc8ad0f9 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Thu, 18 May 2023 09:58:56 +0200 Subject: [PATCH 36/94] west: update rimage to 01af253b5965 update rimage to 01af253b5965 Signed-off-by: Adrian Bonislawski --- rimage | 2 +- west.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rimage b/rimage index 375218cc0b37..01af253b5965 160000 --- a/rimage +++ b/rimage @@ -1 +1 @@ -Subproject commit 375218cc0b3795bf4242a46fa05486647b93ff2d +Subproject commit 01af253b59655c7823d40cc1e393859c628055ea diff --git a/west.yml b/west.yml index a01b6d18479c..a148948ff48b 100644 --- a/west.yml +++ b/west.yml @@ -34,7 +34,7 @@ manifest: - name: rimage repo-path: rimage path: sof/rimage - revision: 375218cc0b3795bf4242a46fa05486647b93ff2d + revision: 01af253b59655c7823d40cc1e393859c628055ea - name: tomlc99 repo-path: tomlc99 From f2fec7476d1f625c11c9383f921d5a1e6bf06c75 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Tue, 16 May 2023 19:26:28 +0200 Subject: [PATCH 37/94] ipc4: multi pipeline set state on different cores This will allow to correctly set multiple pipelines state even if they are allocated on different cores. ipc4_set_pipeline_state will check if several cores are involved - set ppl state if only current core requested - process IPC on another core if only single secondary core requested - send IDC messages if several secondary cores involved Signed-off-by: Adrian Bonislawski --- src/idc/idc.c | 30 +++++++++++++++++++++++++++ src/ipc/ipc4/handler.c | 43 +++++++++++++++++++++++++++++++-------- zephyr/include/rtos/idc.h | 4 ++++ 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/idc/idc.c b/src/idc/idc.c index 3f5ef1f57f02..9796fce1922b 100644 --- a/src/idc/idc.c +++ b/src/idc/idc.c @@ -265,6 +265,33 @@ static int idc_reset(uint32_t comp_id) return ret; } +/** + * \brief Executes IDC pipeline set state message. + * \param[in] ppl_id Pipeline id to be triggered. + * \return Error code. + */ +static int idc_ppl_state(uint32_t ppl_id) +{ + struct ipc *ipc = ipc_get(); + struct ipc_comp_dev *ipc_dev; + struct idc *idc = *idc_get(); + struct idc_payload *payload = idc_payload_get(idc, cpu_get_id()); + struct ipc_comp_dev *ppl_icd; + uint32_t cmd = *(uint32_t *)payload; + bool delayed = false; + int ret; + + ppl_icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, ppl_id); + if (!ppl_icd) { + tr_err(&idc_tr, "idc: comp %d not found", ppl_id); + return IPC4_INVALID_RESOURCE_ID; + } + + ret = set_pipeline_state(ppl_icd, cmd, &delayed); + + return ret; +} + static void idc_prepare_d0ix(void) { /* set prepare_d0ix flag, which indicates that in the next @@ -339,6 +366,9 @@ void idc_cmd(struct idc_msg *msg) case iTS(IDC_MSG_RESET): ret = idc_reset(msg->extension); break; + case iTS(IDC_MSG_PPL_STATE): + ret = idc_ppl_state(msg->extension); + break; case iTS(IDC_MSG_PREPARE_D0ix): idc_prepare_d0ix(); break; diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index bc03ee6ab37b..6667ce232052 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -206,7 +206,7 @@ static bool is_any_ppl_active(void) * ERROR Stop EOS |______\ SAVE * / */ -static int set_pipeline_state(struct ipc_comp_dev *ppl_icd, uint32_t cmd, +int set_pipeline_state(struct ipc_comp_dev *ppl_icd, uint32_t cmd, bool *delayed) { struct ipc_comp_dev *host = NULL; @@ -395,6 +395,8 @@ static int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) struct ipc *ipc = ipc_get(); uint32_t cmd, ppl_count, id; const uint32_t *ppl_id; + bool use_idc = false; + uint32_t idx; int ret = 0; int i; @@ -416,6 +418,21 @@ static int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) ppl_id = &id; } + for (i = 0; i < ppl_count; i++) { + ppl_icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, ppl_id[i]); + if (!ppl_icd) { + tr_err(&ipc_tr, "ipc: comp %d not found", ppl_id[i]); + return IPC4_INVALID_RESOURCE_ID; + } + + if (i) { + if (ppl_icd->core != idx) + use_idc = true; + } else { + idx = ppl_icd->core; + } + } + for (i = 0; i < ppl_count; i++) { bool delayed = false; @@ -426,15 +443,23 @@ static int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) } /* Pass IPC to target core - * Note: current implementation supports only a case with - * all pipelines in cmd allocated on the same core + * or use idc if more than one core used */ - if (!cpu_is_me(ppl_icd->core)) - return ipc4_process_on_core(ppl_icd->core, false); - - ipc_compound_pre_start(state.primary.r.type); - ret = set_pipeline_state(ppl_icd, cmd, &delayed); - ipc_compound_post_start(state.primary.r.type, ret, delayed); + if (!cpu_is_me(ppl_icd->core)) { + if (use_idc) { + struct idc_msg msg = { IDC_MSG_PPL_STATE, + IDC_MSG_PPL_STATE_EXT(ppl_id[i]), ppl_icd->core, sizeof(cmd), + &cmd, }; + + ret = idc_send_msg(&msg, IDC_BLOCKING); + } else { + ret = ipc4_process_on_core(ppl_icd->core, false); + } + } else { + ipc_compound_pre_start(state.primary.r.type); + ret = set_pipeline_state(ppl_icd, cmd, &delayed); + ipc_compound_post_start(state.primary.r.type, ret, delayed); + } if (ret != 0) return ret; diff --git a/zephyr/include/rtos/idc.h b/zephyr/include/rtos/idc.h index e5e8f1f8a072..8734687aebea 100644 --- a/zephyr/include/rtos/idc.h +++ b/zephyr/include/rtos/idc.h @@ -102,6 +102,10 @@ #define IDC_HEADER_TO_AMS_SLOT_MASK(x) (x & 0xFFFF) +/** \brief IDC pipeline set state message. */ +#define IDC_MSG_PPL_STATE IDC_TYPE(0xC) +#define IDC_MSG_PPL_STATE_EXT(x) IDC_EXTENSION(x) + /** \brief IDC_MSG_SECONDARY_CORE_CRASHED header fields. */ #define IDC_SCC_CORE_SHIFT 0 #define IDC_SCC_CORE_MASK 0xff From e47e9f0d8c476ae75281fde285a37ac1778a16ac Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Thu, 18 May 2023 15:30:16 +0200 Subject: [PATCH 38/94] [WORKAROUND] Add frame_align_shift default init frame_align_shift must be initialised (by audio_stream_init_alignment_constants()) once stream format is set. Not all components do this. Calling audio_stream_init_alignment_constants() from audio_stream_init() is wrong as stream format is set after audio_stream_init(). This patch is a quick fix and to be redo with proper fix. Signed-off-by: Serhiy Katsyuba --- src/include/sof/audio/audio_stream.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/include/sof/audio/audio_stream.h b/src/include/sof/audio/audio_stream.h index 61f17fe5f113..37fe900b3563 100644 --- a/src/include/sof/audio/audio_stream.h +++ b/src/include/sof/audio/audio_stream.h @@ -176,6 +176,9 @@ struct audio_stream { #define audio_stream_get_frag(buffer, ptr, idx, sample_size) \ audio_stream_wrap(buffer, (char *)(ptr) + ((idx) * (sample_size))) +static inline void audio_stream_init_alignment_constants(const uint32_t byte_align, + const uint32_t frame_align_req, + struct audio_stream __sparse_cache *stream); /** * Applies parameters to the buffer. * @param buffer Buffer. @@ -192,6 +195,10 @@ static inline int audio_stream_set_params(struct audio_stream __sparse_cache *bu buffer->rate = params->rate; buffer->channels = params->channels; + /* FIXME: WORKAROUND!!! */ + if (buffer->frame_align_shift == 0) + audio_stream_init_alignment_constants(1, 1, buffer); + return 0; } From 7c46d9c6fea68be3c0ee1ff426d24e12c8b9be15 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Thu, 18 May 2023 16:03:53 +0200 Subject: [PATCH 39/94] module_adapter: Do not run on unconfigured bufs Skip .copy() in module_adapter if buffer params are not yet set. Buffer might be configured soon by another pipeline (possibly on another core). Signed-off-by: Serhiy Katsyuba --- src/audio/module_adapter/module_adapter.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index e53eda4212e8..8a809f4b8457 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -705,20 +705,36 @@ static int module_adapter_simple_copy(struct comp_dev *dev) uint32_t num_input_buffers = 0; uint32_t num_output_buffers = 0; int ret, i = 0; + bool all_bufs_configured = true; /* acquire all sink and source buffers */ list_for_item(blist, &dev->bsink_list) { struct comp_buffer *sink; sink = container_of(blist, struct comp_buffer, source_list); - sinks_c[i++] = buffer_acquire(sink); + sinks_c[i] = buffer_acquire(sink); + if (!sinks_c[i]->hw_params_configured) + all_bufs_configured = false; + i++; } i = 0; list_for_item(blist, &dev->bsource_list) { struct comp_buffer *source; source = container_of(blist, struct comp_buffer, sink_list); - source_c[i++] = buffer_acquire(source); + source_c[i] = buffer_acquire(source); + if (!source_c[i]->hw_params_configured) + all_bufs_configured = false; + i++; + } + + if (!all_bufs_configured) { + comp_warn(dev, "Skipping .copy() as not all buffers yet configured"); + /* Do not abort processing -- wait for buffer(s) to be configured by + * other pipeline (possibly on another core). + */ + ret = 0; + goto out; } /* setup active input/output buffers for processing */ From bb7249f5abe80e3cb971595754bea089a7739215 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 25 Apr 2023 09:54:22 -0700 Subject: [PATCH 40/94] topology2: Set the deepbuffer PCM D0i3 compatibility conditionally Set the deep buffer PCM as D0I3 compatible only for MTL. Signed-off-by: Ranjani Sridharan (cherry picked from commit 0140c43099b6f17c76834b92430a2da17360510c) --- .../topology2/development/tplg-targets.cmake | 6 ++++-- .../platform/intel/common_definitions.conf | 1 + .../topology2/platform/intel/deep-buffer.conf | 2 +- .../topology2/sof-ace-tplg/tplg-targets.cmake | 19 ++++++++++++------- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tools/topology/topology2/development/tplg-targets.cmake b/tools/topology/topology2/development/tplg-targets.cmake index faed8382d4a1..4d6d7e9c5b65 100644 --- a/tools/topology/topology2/development/tplg-targets.cmake +++ b/tools/topology/topology2/development/tplg-targets.cmake @@ -28,9 +28,11 @@ PLATFORM=adl" # SSP topology for MTL "cavs-nocodec\;sof-mtl-nocodec\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ -PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-nocodec.bin,DEEPBUFFER_FW_DMA_MS=100" +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-nocodec.bin,DEEPBUFFER_FW_DMA_MS=100,\ +DEEPBUFFER_D0I3_COMPATIBLE=true" "cavs-nocodec\;sof-mtl-nocodec-ssp0-ssp2\;PLATFORM=mtl,NUM_DMICS=2,SSP1_ENABLED=false,\ -PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-nocodec.bin,DEEPBUFFER_FW_DMA_MS=100" +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-nocodec.bin,DEEPBUFFER_FW_DMA_MS=100,\ +DEEPBUFFER_D0I3_COMPATIBLE=true" # CAVS HDA topology with mixer-based efx eq pipelines for HDA and passthrough pipelines for HDMI "sof-hda-generic\;sof-hda-efx-generic\;HDA_CONFIG=efx,USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100,\ diff --git a/tools/topology/topology2/platform/intel/common_definitions.conf b/tools/topology/topology2/platform/intel/common_definitions.conf index f4d49718f559..9c684c7968c0 100644 --- a/tools/topology/topology2/platform/intel/common_definitions.conf +++ b/tools/topology/topology2/platform/intel/common_definitions.conf @@ -58,6 +58,7 @@ Define { SPI_INPUT_CLASS 26 # SPI Input (DSP <-) DEEPBUFFER_FW_DMA_MS 100 # 100 ms copier dma size + DEEPBUFFER_D0I3_COMPATIBLE false # Deep buffer PCM is not D0I3 compatible SSP_BLOB_VERSION_1_0 0x100 SSP_BLOB_VERSION_1_5 0x105 diff --git a/tools/topology/topology2/platform/intel/deep-buffer.conf b/tools/topology/topology2/platform/intel/deep-buffer.conf index 7bf828638906..f66b5d62e39f 100644 --- a/tools/topology/topology2/platform/intel/deep-buffer.conf +++ b/tools/topology/topology2/platform/intel/deep-buffer.conf @@ -19,7 +19,7 @@ Object.PCM.pcm [ name $DEEP_BUFFER_PCM_NAME id $DEEP_BUFFER_PCM_ID direction playback - playback_compatible_d0i3 true + playback_compatible_d0i3 $DEEPBUFFER_D0I3_COMPATIBLE Object.Base.fe_dai.1 { name "DeepBuffer" diff --git a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake index f3267f84ee01..ce3f1901770f 100644 --- a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake +++ b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake @@ -3,31 +3,36 @@ # Array of "input-file-name;output-file-name;comma separated pre-processor variables" set(TPLGS # HDMI only topology with passthrough pipelines -"sof-hda-generic\;sof-hda-generic-idisp\;USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100" +"sof-hda-generic\;sof-hda-generic-idisp\;USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100,\ +DEEPBUFFER_D0I3_COMPATIBLE=true" # HDA topology with mixer-based pipelines for HDA and passthrough pipelines for HDMI -"sof-hda-generic\;sof-hda-generic\;HDA_CONFIG=mix,USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100" +"sof-hda-generic\;sof-hda-generic\;HDA_CONFIG=mix,USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100,\ +DEEPBUFFER_D0I3_COMPATIBLE=true" # If the alsatplg plugins for NHLT are not available, the NHLT blobs will not be added to the # topologies below. "sof-hda-generic\;sof-hda-generic-4ch\;PLATFORM=mtl,\ HDA_CONFIG=mix,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,PREPROCESS_PLUGINS=nhlt,\ -NHLT_BIN=nhlt-sof-hda-generic-4ch.bin,USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100" +NHLT_BIN=nhlt-sof-hda-generic-4ch.bin,USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100,\ +DEEPBUFFER_D0I3_COMPATIBLE=true" "sof-hda-generic\;sof-hda-generic-2ch\;PLATFORM=mtl,\ HDA_CONFIG=mix,NUM_DMICS=2,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-generic-2ch.bin,\ -USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100" +USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100,DEEPBUFFER_D0I3_COMPATIBLE=true" # SDW + DMIC topology with passthrough pipelines # We will change NUM_HDMIS to 3 once HDMI is enabled on MTL RVP "cavs-sdw\;sof-mtl-rt711-4ch\;PLATFORM=mtl,NUM_DMICS=4,DMIC0_ID=2,DMIC1_ID=3,NUM_HDMIS=0,\ -PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-rt711-4ch.bin,DEEPBUFFER_FW_DMA_MS=100" +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-rt711-4ch.bin,DEEPBUFFER_FW_DMA_MS=100,\ +DEEPBUFFER_D0I3_COMPATIBLE=true" "cavs-rt5682\;sof-mtl-max98357a-rt5682\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ PDM1_MIC_B_ENABLE=1,DMIC0_PCM_ID=99,PREPROCESS_PLUGINS=nhlt,\ NHLT_BIN=nhlt-sof-mtl-max98357a-rt5682.bin,DEEPBUFFER_FW_DMA_MS=10,INCLUDE_ECHO_REF=true,\ -BT_NAME=SSP2-BT,BT_ID=8,BT_PCM_NAME=Bluetooth,USE_CHAIN_DMA=true" +BT_NAME=SSP2-BT,BT_ID=8,BT_PCM_NAME=Bluetooth,USE_CHAIN_DMA=true,DEEPBUFFER_D0I3_COMPATIBLE=true" "cavs-rt5682\;sof-mtl-max98357a-rt5682-ssp2-ssp0\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ PDM1_MIC_B_ENABLE=1,DMIC0_PCM_ID=99,PREPROCESS_PLUGINS=nhlt,\ NHLT_BIN=nhlt-sof-mtl-max98357a-rt5682.bin,DEEPBUFFER_FW_DMA_MS=10,HEADSET_SSP_DAI_INDEX=2,\ SPEAKER_SSP_DAI_INDEX=0,HEADSET_CODEC_NAME=SSP2-Codec,SPEAKER_CODEC_NAME=SSP0-Codec,\ -BT_NAME=SSP1-BT,BT_INDEX=1,BT_ID=8,BT_PCM_NAME=Bluetooth,INCLUDE_ECHO_REF=true,USE_CHAIN_DMA=true" +BT_NAME=SSP1-BT,BT_INDEX=1,BT_ID=8,BT_PCM_NAME=Bluetooth,INCLUDE_ECHO_REF=true,USE_CHAIN_DMA=true,\ +DEEPBUFFER_D0I3_COMPATIBLE=true" ) From 55e0a4726faa489eb42831fc2ea90c892e653f1e Mon Sep 17 00:00:00 2001 From: Chao Song Date: Tue, 25 Apr 2023 14:11:05 +0800 Subject: [PATCH 41/94] Topology2: add comment to separate chromebook topology clearly Add a single comment to separate chromebook topologies from non-chromebook topologies. Signed-off-by: Chao Song (cherry picked from commit d3e3943badbd228717a745acec0fbfc83ca810a4) --- tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake index ce3f1901770f..9c41b5e2076f 100644 --- a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake +++ b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake @@ -24,6 +24,8 @@ USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100,DEEPBUFFER_D0I3_COMPATIBLE=true" PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-rt711-4ch.bin,DEEPBUFFER_FW_DMA_MS=100,\ DEEPBUFFER_D0I3_COMPATIBLE=true" +# Below topologies are used on Chromebooks + "cavs-rt5682\;sof-mtl-max98357a-rt5682\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ PDM1_MIC_B_ENABLE=1,DMIC0_PCM_ID=99,PREPROCESS_PLUGINS=nhlt,\ NHLT_BIN=nhlt-sof-mtl-max98357a-rt5682.bin,DEEPBUFFER_FW_DMA_MS=10,INCLUDE_ECHO_REF=true,\ From aca13d33b07b05e06ef01a1a0730a9aee73a9243 Mon Sep 17 00:00:00 2001 From: Chao Song Date: Tue, 25 Apr 2023 14:16:32 +0800 Subject: [PATCH 42/94] Topology2: Add mtl-rt711-l0-rt1316-l23-rt714-l1 support This topology could be used by MTL SDW RVP with 3-in-1 SDCA codec board, or other hardware configuration with the same codec layout: SDW0: RT711 Headphone SDW1: RT714 DMIC SDW2: RT1316 Speaker SDW3: RT1316 Speaker Signed-off-by: Chao Song (cherry picked from commit fabeb638423b2eeb76d9acfa7b3ec54819013a25) --- tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake index 9c41b5e2076f..142cf4ff7112 100644 --- a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake +++ b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake @@ -24,6 +24,9 @@ USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100,DEEPBUFFER_D0I3_COMPATIBLE=true" PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-rt711-4ch.bin,DEEPBUFFER_FW_DMA_MS=100,\ DEEPBUFFER_D0I3_COMPATIBLE=true" +"cavs-sdw\;sof-mtl-rt711-l0-rt1316-l23-rt714-l1\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,SDW_DMIC=1,\ +NUM_HDMIS=0,SDW_SPK_STREAM=SDW2-Playback,SDW_SPK_IN_STREAM=SDW2-Capture,SDW_DMIC_STREAM=SDW1-Capture" + # Below topologies are used on Chromebooks "cavs-rt5682\;sof-mtl-max98357a-rt5682\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ From c297b28b52c8f61b39d8e5102987a1a0f0f34626 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 27 Apr 2023 08:04:30 -0700 Subject: [PATCH 43/94] Tools: Topology2: SRC format fixes This patch avoids with development topology sof-hda-src-generic.tplg the playback start failure and error seen in trace "buffer: buffer_alloc(): new size = 0 is invalid". The kernel selects in case of multiple output formats defined the format that matches the input. It then caused the obs to become zero. When the SRC is used in the mixin-based playback pipeline, its output format is limited to 32-bits format only. So replace the multiple output formats with a single 48K, 2ch 32-bit format. Signed-off-by: Ranjani Sridharan Signed-off-by: Seppo Ingalsuo (cherry picked from commit dfe52aac14f71295e3398972ad3b49976c67e74e) --- .../include/components/src_format.conf | 601 +++++++----------- .../host-copier-gain-src-mixin-playback.conf | 3 +- .../cavs/src-gain-mixin-playback.conf | 2 + 3 files changed, 239 insertions(+), 367 deletions(-) diff --git a/tools/topology/topology2/include/components/src_format.conf b/tools/topology/topology2/include/components/src_format.conf index bb261d23d72b..6fc582f0cf0b 100644 --- a/tools/topology/topology2/include/components/src_format.conf +++ b/tools/topology/topology2/include/components/src_format.conf @@ -1,369 +1,238 @@ #src format array num_input_audio_formats 42 - num_output_audio_formats 42 - # 8khz input - Object.Base.audio_format.1 { - in_rate 8000 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.2 { - in_rate 8000 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.3{ - in_rate 8000 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } - - # 11.025 khz input - Object.Base.audio_format.4 { - in_rate 11025 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - # for 11.025k, 22.05k, 44.1k, 88.2k and 176.4k, extra 4 sample size is needed - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - Object.Base.audio_format.5 { - in_rate 11025 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - Object.Base.audio_format.6{ - in_rate 11025 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - # 12khz input - Object.Base.audio_format.7 { - in_rate 12000 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.8 { - in_rate 12000 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.9{ - in_rate 12000 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } - - # 16khz input - Object.Base.audio_format.10 { - in_rate 16000 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.11 { - in_rate 16000 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.12{ - in_rate 16000 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } - - # 22.05khz input - Object.Base.audio_format.13 { - in_rate 22050 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - Object.Base.audio_format.14 { - in_rate 22050 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - Object.Base.audio_format.15{ - in_rate 22050 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - - # 24khz input - Object.Base.audio_format.16 { - in_rate 24000 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.17 { - in_rate 24000 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.18{ - in_rate 24000 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } - - # 32khz input - Object.Base.audio_format.19 { - in_rate 32000 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.20 { - in_rate 32000 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.21 { - in_rate 32000 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } - - # 44.1khz input - Object.Base.audio_format.22 { - in_rate 44100 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - Object.Base.audio_format.23 { - in_rate 44100 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - Object.Base.audio_format.24{ - in_rate 44100 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - # 48khz input - Object.Base.audio_format.25 { - in_rate 48000 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.26 { - in_rate 48000 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.27 { - in_rate 48000 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } - - # 64khz input - Object.Base.audio_format.28 { - in_rate 64000 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.29 { - in_rate 64000 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.30 { - in_rate 64000 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } - # 88.2khz input - Object.Base.audio_format.31 { - in_rate 88200 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - Object.Base.audio_format.32 { - in_rate 88200 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - Object.Base.audio_format.33 { - in_rate 88200 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - # 96khz input - Object.Base.audio_format.34 { - in_rate 96000 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.35 { - in_rate 96000 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.36 { - in_rate 96000 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } - - # 176.4khz input - Object.Base.audio_format.37 { - in_rate 176400 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - Object.Base.audio_format.38 { - in_rate 176400 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - Object.Base.audio_format.39 { - in_rate 176400 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - obs "$[($out_channels * (($[($out_rate + 999)] / 1000) + 4)) * ($out_bit_depth / 8)]" - } - - # 192khz input - Object.Base.audio_format.40 { - in_rate 192000 - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.41 { - in_rate 192000 - in_bit_depth 32 - in_valid_bit_depth 24 - out_bit_depth 32 - out_valid_bit_depth 24 - } - - Object.Base.audio_format.42 { - in_rate 192000 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } + Object.Base.input_audio_format [ + # 8khz input + { + in_rate 8000 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 8000 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 11.025 khz input + { + in_rate 11025 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 11025 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 11025 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 12khz input + { + in_rate 12000 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 12000 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 12000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 16khz input + { + in_rate 16000 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 16000 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 16000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 22.05khz input + { + in_rate 22050 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 22050 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 22050 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 24khz input + { + in_rate 24000 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 24000 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 24000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 32khz input + { + in_rate 32000 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 32000 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 32000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 44.1khz input + { + in_rate 44100 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 44100 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 44100 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 48khz input + { + in_rate 48000 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 64khz input + { + in_rate 64000 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 64000 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 64000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 88.2khz input + { + in_rate 88200 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 88200 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 88200 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 96khz input + { + in_rate 96000 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 96000 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 96000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 176.4khz input + { + in_rate 176400 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 176400 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 176400 + in_bit_depth 32 + in_valid_bit_depth 32 + } + # 192khz input + { + in_rate 192000 + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate 192000 + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_rate 192000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + + num_output_audio_formats 1 + + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] diff --git a/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-src-mixin-playback.conf b/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-src-mixin-playback.conf index 6139b5574bee..292e5b1686c0 100644 --- a/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-src-mixin-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-src-mixin-playback.conf @@ -16,7 +16,8 @@ # Where N is the unique pipeline ID within the same alsaconf node. # - + + diff --git a/tools/topology/topology2/include/pipelines/cavs/src-gain-mixin-playback.conf b/tools/topology/topology2/include/pipelines/cavs/src-gain-mixin-playback.conf index 1e1e9cca2aa4..d2ae1e08fa0c 100644 --- a/tools/topology/topology2/include/pipelines/cavs/src-gain-mixin-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/src-gain-mixin-playback.conf @@ -15,6 +15,8 @@ # # Where N is the unique pipeline ID within the same alsaconf node. # + + From 40e4d5899f5b129d25b189b693f6a5d46a80c8e6 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 10 Mar 2023 11:43:12 -0800 Subject: [PATCH 44/94] topology2: cavs-sdw: Enable PDM 1 mics for 4ch It would be better to make these dependedent on NUM_DMICS. Something to improve in a follow up PR. Signed-off-by: Ranjani Sridharan (cherry picked from commit 3c39c2c996a3530193b03f552e066dd421b26f90) --- tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake index 142cf4ff7112..5b0fbeddcfa3 100644 --- a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake +++ b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake @@ -20,9 +20,9 @@ USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100,DEEPBUFFER_D0I3_COMPATIBLE=true" # SDW + DMIC topology with passthrough pipelines # We will change NUM_HDMIS to 3 once HDMI is enabled on MTL RVP -"cavs-sdw\;sof-mtl-rt711-4ch\;PLATFORM=mtl,NUM_DMICS=4,DMIC0_ID=2,DMIC1_ID=3,NUM_HDMIS=0,\ -PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-rt711-4ch.bin,DEEPBUFFER_FW_DMA_MS=100,\ -DEEPBUFFER_D0I3_COMPATIBLE=true" +"cavs-sdw\;sof-mtl-rt711-4ch\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +DMIC0_ID=2,DMIC1_ID=3,NUM_HDMIS=0,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-rt711-4ch.bin,\ +DEEPBUFFER_FW_DMA_MS=100,DEEPBUFFER_D0I3_COMPATIBLE=true" "cavs-sdw\;sof-mtl-rt711-l0-rt1316-l23-rt714-l1\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,SDW_DMIC=1,\ NUM_HDMIS=0,SDW_SPK_STREAM=SDW2-Playback,SDW_SPK_IN_STREAM=SDW2-Capture,SDW_DMIC_STREAM=SDW1-Capture" From e6479e5c24b9d408620ecb077209c9be4653105f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 28 Apr 2023 11:29:56 -0700 Subject: [PATCH 45/94] topology2: cavs-nocodec: add a module copier to SSP 0 capture pipeline Add a module copier between the DAI copier and gain in preparation for optimizing the single endpoint DAI copiers. This optimization will temporarily make multiple sinks unsupported with DAI copiers. This feature will be re-introduced in a follow up PR and the module copier will be removed then. Signed-off-by: Ranjani Sridharan (cherry picked from commit 74f324641a6c7f7420758d9b214b239b0f9deb78) --- tools/topology/topology2/cavs-nocodec.conf | 8 +++++--- .../dai-copier-gain-module-copier-capture.conf | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/tools/topology/topology2/cavs-nocodec.conf b/tools/topology/topology2/cavs-nocodec.conf index bf3d240019b6..0d5ab45ca022 100644 --- a/tools/topology/topology2/cavs-nocodec.conf +++ b/tools/topology/topology2/cavs-nocodec.conf @@ -213,7 +213,7 @@ Object.Pipeline.mixout-gain-smart-amp-dai-copier-playback [ } Object.Base.input_pin_binding.2 { - input_pin_binding_name "copier.SSP.8.1" + input_pin_binding_name "module-copier.8.1" } Object.Control.bytes."1" { @@ -345,7 +345,9 @@ Object.Pipeline.dai-copier-gain-module-copier-capture [ out_bit_depth 32 out_valid_bit_depth 32 } + } + Object.Widget.module-copier.1 { Object.Base.output_pin_binding.1 { output_pin_binding_name "gain.8.1" } @@ -634,7 +636,7 @@ Object.Base.route [ } { source "copier.SSP.8.1" - sink "gain.8.1" + sink "module-copier.8.1" } { source "copier.SSP.12.1" @@ -661,7 +663,7 @@ Object.Base.route [ sink gain.20.1 } { - source "copier.SSP.8.1" + source "module-copier.8.1" sink "smart_amp.2.1" } ] diff --git a/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-module-copier-capture.conf b/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-module-copier-capture.conf index dfa3c2752064..ad2259d47898 100644 --- a/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-module-copier-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-module-copier-capture.conf @@ -57,6 +57,16 @@ Class.Pipeline."dai-copier-gain-module-copier-capture" { out_valid_bit_depth 32 } } + module-copier."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.audio_format.1 { + in_bit_depth 32 + in_valid_bit_depth 32 + out_bit_depth 32 + out_valid_bit_depth 32 + } + } module-copier."2" { num_input_audio_formats 1 @@ -92,6 +102,10 @@ Class.Pipeline."dai-copier-gain-module-copier-capture" { source gain.$index.1 sink module-copier.$index.2 } + route.2 { + source module-copier.$index.1 + sink gain.$index.1 + } } direction "capture" From 729d54e18bb47b1e08c7915e460088a54a4c94d1 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 2 May 2023 09:45:50 +0800 Subject: [PATCH 46/94] topology2: cavs-sdw: make jack optional We assume sdw jack is always there in a sdw topology. This commit makes it be optional to deal with the sdw amp only case. Signed-off-by: Bard Liao (cherry picked from commit a3cb46d8c0c4b2f081ea9251c54652842f8db295) --- tools/topology/topology2/cavs-sdw.conf | 162 +----------------- .../platform/intel/sdw-jack-generic.conf | 159 +++++++++++++++++ 2 files changed, 162 insertions(+), 159 deletions(-) create mode 100644 tools/topology/topology2/platform/intel/sdw-jack-generic.conf diff --git a/tools/topology/topology2/cavs-sdw.conf b/tools/topology/topology2/cavs-sdw.conf index 198e37953167..61fe676fd004 100644 --- a/tools/topology/topology2/cavs-sdw.conf +++ b/tools/topology/topology2/cavs-sdw.conf @@ -69,6 +69,7 @@ Define { SDW_JACK_IN_BE_ID 1 NUM_SDW_AMP_LINKS 0 SDW_DMIC 0 + SDW_JACK true } # override defaults with platform-specific config @@ -90,11 +91,6 @@ IncludeByKey.NUM_HDMIS { "[3-4]" "platform/intel/hdmi-generic.conf" } -# include deep buffer config if buffer size is in 1 - 1000 ms. -IncludeByKey.DEEPBUFFER_FW_DMA_MS{ - "[1-1000]" "platform/intel/deep-buffer.conf" -} - IncludeByKey.NUM_SDW_AMP_LINKS { "[1-2]" "platform/intel/sdw-amp-generic.conf" } @@ -103,159 +99,7 @@ IncludeByKey.SDW_DMIC { "1" "platform/intel/sdw-dmic-generic.conf" } -# -# List of all DAIs -# -#ALH Index: 0, Direction: duplex -Object.Dai.ALH [ - { - dai_index 0 - id $SDW_JACK_OUT_BE_ID - direction "playback" - name $SDW_JACK_OUT_STREAM - default_hw_conf_id 0 - rate 48000 - channels 2 - - Object.Base.hw_config.1 { - id 0 - name "ALH2" - } - } - { - dai_index 10 - id $SDW_JACK_IN_BE_ID - direction "capture" - name $SDW_JACK_IN_STREAM - default_hw_conf_id 1 - rate 48000 - channels 2 - - Object.Base.hw_config.1 { - id 1 - name "ALH3" - } - } -] - -# -# Pipeline definitions -# - -# Pipeline ID:1 PCM ID: 0 -Object.Pipeline { - host-copier-gain-mixin-playback [ - { - index 0 - - Object.Widget.copier.1 { - stream_name "volume playback 0" - } - Object.Widget.gain.1 { - Object.Control.mixer.1 { - name '1 Playback Volume 0' - } - } - } - ] - - mixout-gain-dai-copier-playback [ - { - index 1 - - Object.Widget.copier.1 { - stream_name $SDW_JACK_OUT_STREAM - dai_type "ALH" - copier_type "ALH" - node_type $ALH_LINK_OUTPUT_CLASS - } - Object.Widget.gain.1 { - Object.Control.mixer.1 { - name '2 Main Playback Volume' - } - } - } - ] - - host-gateway-capture [ - { - index 10 - - Object.Widget.copier.1.stream_name "Passthrough Capture 0" - Object.Widget.copier.1.Object.Base.audio_format.1 { - # 32/32 -> 16/16 bits conversion is done here - in_bit_depth 32 - in_valid_bit_depth 32 - } - } - ] - - highpass-capture-be [ - { - direction "capture" - index 11 - copier_type "ALH" - - Object.Widget.copier.1 { - stream_name $SDW_JACK_IN_STREAM - dai_type "ALH" - copier_type "ALH" - type "dai_out" - node_type $ALH_LINK_INPUT_CLASS - } - Object.Widget.eqiir.1 { - Object.Control.bytes."1" { - name '4 Main capture Iir Eq' - } - } - } - ] +IncludeByKey.SDW_JACK { +"true" "platform/intel/sdw-jack-generic.conf" } -Object.PCM.pcm [ - { - name "Jack out" - id 0 - direction "playback" - Object.Base.fe_dai.1 { - name "Jack out" - } - - Object.PCM.pcm_caps.1 { - name "volume playback 0" - formats 'S16_LE,S32_LE' - } - } - { - name "Jack in" - id 1 - direction "capture" - Object.Base.fe_dai.1 { - name "Jack in" - } - - Object.PCM.pcm_caps.1 { - name "Passthrough Capture 0" - formats 'S16_LE,S32_LE' - } - } -] - -Object.Base.route [ - { - source "gain.1.1" - sink "copier.ALH.1.1" - } - { - source "mixin.0.1" - sink "mixout.1.1" - } - { - source "copier.ALH.11.1" - sink "eqiir.11.1" - } - { - source "eqiir.11.1" - sink "copier.host.10.1" - } -] diff --git a/tools/topology/topology2/platform/intel/sdw-jack-generic.conf b/tools/topology/topology2/platform/intel/sdw-jack-generic.conf new file mode 100644 index 000000000000..0c81629f9e3e --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-jack-generic.conf @@ -0,0 +1,159 @@ +# include deep buffer config if buffer size is in 1 - 1000 ms. +IncludeByKey.DEEPBUFFER_FW_DMA_MS{ + "[1-1000]" "platform/intel/deep-buffer.conf" +} + +# +# List of all DAIs +# +Object.Dai.ALH [ + { + dai_index 0 + id $SDW_JACK_OUT_BE_ID + direction "playback" + name $SDW_JACK_OUT_STREAM + default_hw_conf_id 0 + rate 48000 + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH2" + } + } + { + dai_index 10 + id $SDW_JACK_IN_BE_ID + direction "capture" + name $SDW_JACK_IN_STREAM + default_hw_conf_id 0 + rate 48000 + channels 2 + + Object.Base.hw_config.1 { + id 0 + name "ALH3" + } + } +] + +# +# Pipeline definitions +# + +Object.Pipeline { + host-copier-gain-mixin-playback [ + { + index 0 + + Object.Widget.copier.1 { + stream_name "volume playback 0" + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name '1 Playback Volume 0' + } + } + } + ] + + mixout-gain-dai-copier-playback [ + { + index 1 + + Object.Widget.copier.1 { + stream_name $SDW_JACK_OUT_STREAM + dai_type "ALH" + copier_type "ALH" + node_type $ALH_LINK_OUTPUT_CLASS + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name '2 Main Playback Volume' + } + } + } + ] + + host-gateway-capture [ + { + index 10 + + Object.Widget.copier.1.stream_name "Passthrough Capture 0" + Object.Widget.copier.1.Object.Base.audio_format.1 { + # 32/32 -> 16/16 bits conversion is done here + in_bit_depth 32 + in_valid_bit_depth 32 + } + } + ] + + highpass-capture-be [ + { + direction "capture" + index 11 + copier_type "ALH" + + Object.Widget.copier.1 { + stream_name $SDW_JACK_IN_STREAM + dai_type "ALH" + copier_type "ALH" + type "dai_out" + node_type $ALH_LINK_INPUT_CLASS + } + Object.Widget.eqiir.1 { + Object.Control.bytes."1" { + name '4 Main capture Iir Eq' + } + } + } + ] +} + +Object.PCM.pcm [ + { + name "Jack out" + id 0 + direction "playback" + Object.Base.fe_dai.1 { + name "Jack out" + } + + Object.PCM.pcm_caps.1 { + name "volume playback 0" + formats 'S16_LE,S32_LE' + } + } + { + name "Jack in" + id 1 + direction "capture" + Object.Base.fe_dai.1 { + name "Jack in" + } + + Object.PCM.pcm_caps.1 { + name "Passthrough Capture 0" + formats 'S16_LE,S32_LE' + } + } +] + +Object.Base.route [ + { + source "gain.1.1" + sink "copier.ALH.1.1" + } + { + source "mixin.0.1" + sink "mixout.1.1" + } + { + source "copier.ALH.11.1" + sink "eqiir.11.1" + } + { + source "eqiir.11.1" + sink "copier.host.10.1" + } +] From 660b4bec0ac8d8569176c736915ed78b4e758f1d Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Mon, 24 Apr 2023 09:22:51 -0500 Subject: [PATCH 47/94] topology2: dmic-generic: add macro for DMIC_CORE_ID Add macros to quickly enable multi-core with DMICs. Signed-off-by: Yong Zhi (cherry picked from commit 04749b9c417f38726baa123759ac04edcc699a06) --- .../topology2/platform/intel/dmic-default.conf | 2 +- .../topology2/platform/intel/dmic-generic.conf | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/topology/topology2/platform/intel/dmic-default.conf b/tools/topology/topology2/platform/intel/dmic-default.conf index d5bfb7d11f1e..f23f930b3cf1 100644 --- a/tools/topology/topology2/platform/intel/dmic-default.conf +++ b/tools/topology/topology2/platform/intel/dmic-default.conf @@ -33,5 +33,5 @@ Define { WOV_UUID '1f:d5:a8:eb:27:78:b5:47:82:ee:de:6e:77:43:af:67' WOV_CPC '360000' DMIC1_PCM_CAPS 'Passthrough Capture 18' - + DMIC_CORE_ID 0 } diff --git a/tools/topology/topology2/platform/intel/dmic-generic.conf b/tools/topology/topology2/platform/intel/dmic-generic.conf index 179ad75422ee..5d7747d360c1 100644 --- a/tools/topology/topology2/platform/intel/dmic-generic.conf +++ b/tools/topology/topology2/platform/intel/dmic-generic.conf @@ -73,6 +73,7 @@ Object.Pipeline.gain-capture [ Object.Widget.copier.1 { stream_name $DMIC0_PCM_CAPS + core_id $DMIC_CORE_ID num_input_audio_formats 2 num_output_audio_formats 2 Object.Base.audio_format.1 { @@ -95,6 +96,7 @@ Object.Pipeline.gain-capture [ } } Object.Widget.gain.1 { + core_id $DMIC_CORE_ID num_input_audio_formats 2 num_output_audio_formats 2 Object.Base.audio_format.1 { @@ -121,6 +123,7 @@ Object.Pipeline.gain-capture [ } Object.Widget.module-copier."2" { + core_id $DMIC_CORE_ID num_input_audio_formats 2 num_output_audio_formats 2 Object.Base.audio_format.1 { @@ -142,6 +145,9 @@ Object.Pipeline.gain-capture [ out_ch_map $CHANNEL_MAP_3_POINT_1 } } + Object.Widget.pipeline."1" { + core $DMIC_CORE_ID + } } ] @@ -150,6 +156,7 @@ Object.Pipeline.dai-copier-eqiir-module-copier-capture [ index $DMIC0_DAI_PIPELINE_ID Object.Widget.copier.1 { + core_id $DMIC_CORE_ID dai_index 0 dai_type "DMIC" copier_type "DMIC" @@ -179,6 +186,7 @@ Object.Pipeline.dai-copier-eqiir-module-copier-capture [ } Object.Widget.module-copier."2" { + core_id $DMIC_CORE_ID stream_name $DMIC0_NAME num_input_audio_formats 2 num_output_audio_formats 2 @@ -203,6 +211,7 @@ Object.Pipeline.dai-copier-eqiir-module-copier-capture [ } Object.Widget.eqiir.1 { + core_id $DMIC_CORE_ID num_input_audio_formats 2 num_output_audio_formats 2 Object.Base.audio_format.1 { @@ -223,6 +232,9 @@ Object.Pipeline.dai-copier-eqiir-module-copier-capture [ name 'DMIC0 capture Iir Eq' } } + Object.Widget.pipeline."1" { + core $DMIC_CORE_ID + } } ] From dc58c6a20919d8da2a13a9c09fe2549a9f2bf871 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 25 Apr 2023 21:57:52 +0800 Subject: [PATCH 48/94] topology2: add multicore support for CI test create another topology to test multicore since Currently we have done too much work in cavs-nocodec and CI test will be failed for main branch is not ready for multicore feature. Signed-off-by: Rander Wang (cherry picked from commit c60529663652019a815a22253844efbf026addea) --- .../topology2/cavs-nocodec-multicore.conf | 473 ++++++++++++++++++ .../topology2/development/tplg-targets.cmake | 3 + 2 files changed, 476 insertions(+) create mode 100644 tools/topology/topology2/cavs-nocodec-multicore.conf diff --git a/tools/topology/topology2/cavs-nocodec-multicore.conf b/tools/topology/topology2/cavs-nocodec-multicore.conf new file mode 100644 index 000000000000..b1dc28426617 --- /dev/null +++ b/tools/topology/topology2/cavs-nocodec-multicore.conf @@ -0,0 +1,473 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Define { + MCLK 24576000 + PLATFORM "none" + SSP0_CORE_ID 0 + SSP1_CORE_ID 1 + SSP2_CORE_ID 2 +} + +# override defaults with platform-specific config +IncludeByKey.PLATFORM { + "tgl" "platform/intel/tgl.conf" + "adl" "platform/intel/tgl.conf" + "mtl" "platform/intel/mtl.conf" +} + +# +# List of all DAIs +# +Object.Dai.SSP [ + { + id 0 + dai_index 0 + direction "duplex" + name NoCodec-0 + default_hw_conf_id 0 + sample_bits 32 + quirks "lbm_mode" + io_clk $MCLK + + Object.Base.hw_config.1 { + name "SSP0" + id 0 + bclk_freq 3072000 + tdm_slot_width 32 + # TODO: remove this. Needs alsaptlg change. + Object.Base.link_config.1 { + clock_source 1 + } + } + } + { + id 2 + dai_index 2 + direction "duplex" + name NoCodec-2 + default_hw_conf_id 0 + sample_bits 32 + quirks "lbm_mode" + io_clk $MCLK + + Object.Base.hw_config.1 { + name "SSP2" + id 0 + bclk_freq 3072000 + tdm_slot_width 32 + # TODO: remove this. Needs alsaptlg change. + Object.Base.link_config.1 { + clock_source 1 + } + } + } +] + +# +# Pipeline definitions +# +# PCM0 ---> gain ---> Mixin ---> Mixout ---> gain ---> SSP0 (core SSP0_CORE_ID) +# PCM1 ---> gain ---> Mixin ---> Mixout ---> gain ---> SSP1 (core SSP1_CORE_ID) +# PCM2 ---> gain ---> Mixin ---> Mixout ---> gain ---> SSP2 (core SSP2_CORE_ID) +# SSP0 ---> PCM0 +# SSP1 ---> PCM1 +# SSP2 ---> PCM2 + +# Pipeline ID:1 PCM ID: 0 +Object.Pipeline.host-copier-gain-mixin-playback [ + { + index 1 + + core $SSP0_CORE_ID + Object.Widget.copier.1 { + core_id $SSP0_CORE_ID + stream_name 'SSP0 Playback' + } + Object.Widget.gain.1 { + core_id $SSP0_CORE_ID + Object.Control.mixer.1 { + name 'Playback Volume 1' + } + } + } + { + index 5 + + core $SSP2_CORE_ID + Object.Widget.copier.1 { + core_id $SSP2_CORE_ID + stream_name 'SSP2 Playback' + } + Object.Widget.gain.1 { + core_id $SSP2_CORE_ID + Object.Control.mixer.1 { + name 'Playback Volume 5' + } + } + Object.Widget.mixin.1 { + core_id $SSP2_CORE_ID + } + } +] + +Object.Pipeline.mixout-gain-dai-copier-playback [ + { + index 14 + + core $SSP0_CORE_ID + Object.Widget.copier.1 { + core_id $SSP0_CORE_ID + dai_index 0 + dai_type "SSP" + copier_type "SSP" + stream_name "NoCodec-0" + node_type $I2S_LINK_OUTPUT_CLASS + } + + Object.Widget.gain.1 { + core_id $SSP0_CORE_ID + Object.Control.mixer.1 { + name 'Main Playback Volume 14' + } + } + } + { + index 6 + + core $SSP2_CORE_ID + Object.Widget.copier.1 { + core_id $SSP2_CORE_ID + dai_index 2 + dai_type "SSP" + copier_type "SSP" + stream_name "NoCodec-2" + node_type $I2S_LINK_OUTPUT_CLASS + } + + Object.Widget.gain.1 { + core_id $SSP2_CORE_ID + Object.Control.mixer.1 { + name 'Main Playback Volume 6' + } + } + Object.Widget.mixout.1 { + core_id $SSP2_CORE_ID + } + } +] + +Object.Pipeline.host-gateway-capture [ + { + index 7 + + Object.Widget.copier.1 { + stream_name 'SSP0 Capture' + } + } + { + index 11 + + Object.Widget.copier.1 { + stream_name 'SSP2 Capture' + } + } +] + +Object.Pipeline.io-gateway-capture [ + { + index 8 + direction capture + + Object.Widget.copier."1" { + dai_index 1 + dai_type "SSP" + type dai_out + copier_type "SSP" + stream_name "NoCodec-0" + node_type $I2S_LINK_INPUT_CLASS + Object.Base.audio_format.1 { + in_bit_depth 32 + in_valid_bit_depth 32 + out_bit_depth 32 + out_valid_bit_depth 32 + } + } + } + { + index 12 + direction capture + + Object.Widget.copier."1" { + dai_index 2 + dai_type "SSP" + type dai_out + copier_type "SSP" + stream_name "NoCodec-2" + node_type $I2S_LINK_INPUT_CLASS + Object.Base.audio_format.1 { + in_bit_depth 32 + in_valid_bit_depth 32 + out_bit_depth 32 + out_valid_bit_depth 32 + } + } + } +] + +Object.PCM.pcm [ + { + name "Port0" + id 0 + direction "duplex" + Object.Base.fe_dai.1 { + name "Port0" + } + + Object.PCM.pcm_caps.1 { + direction "playback" + name "SSP0 Playback" + formats 'S16_LE,S24_LE,S32_LE' + } + + Object.PCM.pcm_caps.2 { + direction "capture" + name "SSP0 Capture" + formats 'S16_LE,S24_LE,S32_LE' + } + } + { + name "Port2" + id 2 + direction "duplex" + Object.Base.fe_dai.1 { + name "Port2" + } + + Object.PCM.pcm_caps.1 { + direction "playback" + name "SSP2 Playback" + formats 'S16_LE,S24_LE,S32_LE' + } + + Object.PCM.pcm_caps.2 { + direction "capture" + name "SSP2 Capture" + formats 'S16_LE,S24_LE,S32_LE' + } + } +] + +Object.Base.route [ + { + source "gain.14.1" + sink "copier.SSP.14.1" + } + { + source "mixin.1.1" + sink "mixout.14.1" + } + { + source "gain.6.1" + sink "copier.SSP.6.1" + } + { + source "mixin.5.1" + sink "mixout.6.1" + } + { + source "copier.SSP.8.1" + sink "copier.host.7.1" + } + { + source "copier.SSP.12.1" + sink "copier.host.11.1" + } +] + +# There is pinmux conflict between SSP1 and DMIC on MTL RVP, +# so include SSP1 pipelines conditionally. +IncludeByKey.SSP1_ENABLED { + "true" { + Object.Dai.SSP [ + { + id 1 + dai_index 1 + direction "duplex" + name NoCodec-1 + default_hw_conf_id 0 + sample_bits 32 + quirks "lbm_mode" + io_clk $MCLK + + Object.Base.hw_config.1 { + name "SSP1" + id 0 + bclk_freq 3072000 + tdm_slot_width 32 + # TODO: remove this. Needs alsaptlg change. + Object.Base.link_config.1 { + clock_source 1 + } + } + } + ] + + Object.Pipeline.host-copier-gain-mixin-playback [ + { + index 3 + + core $SSP1_CORE_ID + Object.Widget.copier.1 { + core_id $SSP1_CORE_ID + stream_name 'SSP1 Playback' + } + Object.Widget.gain.1 { + core_id $SSP1_CORE_ID + Object.Control.mixer.1 { + name 'Playback Volume 3' + } + } + Object.Widget.mixin.1 { + core_id $SSP1_CORE_ID + } + } + ] + + Object.Pipeline.mixout-gain-dai-copier-playback [ + { + index 4 + + core $SSP1_CORE_ID + Object.Widget.copier.1 { + core_id $SSP1_CORE_ID + dai_index 1 + dai_type "SSP" + copier_type "SSP" + stream_name "NoCodec-1" + node_type $I2S_LINK_OUTPUT_CLASS + } + + Object.Widget.gain.1 { + core_id $SSP1_CORE_ID + Object.Control.mixer.1 { + name 'Main Playback Volume 4' + } + } + Object.Widget.mixout.1 { + core_id $SSP1_CORE_ID + } + } + ] + + Object.Pipeline.host-gateway-capture [ + { + index 9 + + Object.Widget.copier.1 { + stream_name 'SSP1 Capture' + } + } + ] + + Object.Pipeline.io-gateway-capture [ + { + index 10 + direction capture + + Object.Widget.copier."1" { + dai_index 1 + dai_type "SSP" + type dai_out + copier_type "SSP" + stream_name "NoCodec-1" + node_type $I2S_LINK_INPUT_CLASS + Object.Base.audio_format.1 { + in_bit_depth 32 + in_valid_bit_depth 32 + out_bit_depth 32 + out_valid_bit_depth 32 + } + } + } + ] + + Object.PCM.pcm [ + { + name "Port1" + id 1 + direction "duplex" + Object.Base.fe_dai.1 { + name "Port1" + } + + Object.PCM.pcm_caps.1 { + direction "playback" + name "SSP1 Playback" + formats 'S16_LE,S24_LE,S32_LE' + } + + Object.PCM.pcm_caps.2 { + direction "capture" + name "SSP1 Capture" + formats 'S16_LE,S24_LE,S32_LE' + } + } + ] + + Object.Base.route [ + { + source "mixin.3.1" + sink "mixout.4.1" + } + { + source "gain.4.1" + sink "copier.SSP.4.1" + } + { + source "copier.SSP.10.1" + sink "copier.host.9.1" + } + ] + } +} diff --git a/tools/topology/topology2/development/tplg-targets.cmake b/tools/topology/topology2/development/tplg-targets.cmake index 4d6d7e9c5b65..0592f8b4a5fd 100644 --- a/tools/topology/topology2/development/tplg-targets.cmake +++ b/tools/topology/topology2/development/tplg-targets.cmake @@ -34,6 +34,9 @@ DEEPBUFFER_D0I3_COMPATIBLE=true" PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-nocodec.bin,DEEPBUFFER_FW_DMA_MS=100,\ DEEPBUFFER_D0I3_COMPATIBLE=true" +"cavs-nocodec-multicore\;sof-mtl-nocodec-multicore\;PLATFORM=mtl,SSP1_ENABLED=true,SSP0_CORE_ID=0,\ +SSP1_CORE_ID=1,SSP2_CORE_ID=2,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-nocodec.bin" + # CAVS HDA topology with mixer-based efx eq pipelines for HDA and passthrough pipelines for HDMI "sof-hda-generic\;sof-hda-efx-generic\;HDA_CONFIG=efx,USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100,\ EFX_FIR_PARAMS=passthrough,EFX_IIR_PARAMS=passthrough" From ddc2ef666872f07be639625652b20c877fee9f71 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Fri, 19 May 2023 10:51:24 +0200 Subject: [PATCH 49/94] ipc4: fix multi pipeline set state if only one secondary core used Fixes commit f2fec7476d1f Signed-off-by: Adrian Bonislawski --- src/ipc/ipc4/handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index 6667ce232052..54b30f29b96e 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -453,7 +453,7 @@ static int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) ret = idc_send_msg(&msg, IDC_BLOCKING); } else { - ret = ipc4_process_on_core(ppl_icd->core, false); + return ipc4_process_on_core(ppl_icd->core, false); } } else { ipc_compound_pre_start(state.primary.r.type); From 9939a3a0135fcfa57aa281a5a0489577b565084e Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Mon, 22 May 2023 13:22:31 +0200 Subject: [PATCH 50/94] west: update zephyr to 79b598daf229 update zephyr to 79b598daf229 Signed-off-by: Adrian Bonislawski --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index a148948ff48b..d9f88197de63 100644 --- a/west.yml +++ b/west.yml @@ -43,7 +43,7 @@ manifest: - name: zephyr repo-path: zephyr - revision: d11ba34ddad459f8244ae6adc217533d90c2ca0f + revision: 79b598daf229fe971a303389d5301ab31212deb8 remote: thesofproject # Import some projects listed in zephyr/west.yml@revision From 24eca03573122e9018917a2d2fd2c0c7b8761461 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Tue, 23 May 2023 16:59:33 +0200 Subject: [PATCH 51/94] Revert "ipc4: Fix Host gtw conversion to/from 24_4LE audio" This reverts commit d2b0b4716be7f5371d48993833e198c27d8c5d7e. --- .../pcm_converter/pcm_converter_generic.c | 28 +++---------------- src/audio/pcm_converter/pcm_converter_hifi3.c | 28 +++---------------- 2 files changed, 8 insertions(+), 48 deletions(-) diff --git a/src/audio/pcm_converter/pcm_converter_generic.c b/src/audio/pcm_converter/pcm_converter_generic.c index 23a2e23d511b..9f32dc68ac1d 100644 --- a/src/audio/pcm_converter/pcm_converter_generic.c +++ b/src/audio/pcm_converter/pcm_converter_generic.c @@ -855,44 +855,24 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, - ipc4_gtw_all & ~ipc4_gtw_host, ipc4_bidirection, pcm_convert_s24_to_s32}, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, - ipc4_gtw_host, ipc4_playback, audio_stream_copy}, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, - ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s32}, + ipc4_gtw_all, ipc4_bidirection, pcm_convert_s24_to_s32}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host), ipc4_bidirection, + ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh), ipc4_bidirection, pcm_convert_s32_to_s24 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_playback, pcm_convert_s32_to_s24_be }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_capture, pcm_convert_s32_to_s24 }, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_host, ipc4_playback, pcm_convert_s32_to_s24 }, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_host, ipc4_capture, pcm_convert_s32_to_s24_be }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host), + SOF_IPC_FRAME_S24_4LE, ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh), ipc4_bidirection, pcm_convert_s16_to_s24 }, { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_playback, pcm_convert_s16_to_s32}, - { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, - ipc4_playback, pcm_convert_s16_to_s24 }, - { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, - ipc4_capture, pcm_convert_s16_to_s32 }, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S16_LE, ipc4_gtw_all & ~ipc4_gtw_host, - ipc4_bidirection, pcm_convert_s24_to_s16 }, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S16_LE, ipc4_gtw_host, ipc4_playback, pcm_convert_s32_to_s16 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S16_LE, ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s16 }, + SOF_IPC_FRAME_S16_LE, ipc4_gtw_all, ipc4_bidirection, pcm_convert_s24_to_s16 }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S32_LE, diff --git a/src/audio/pcm_converter/pcm_converter_hifi3.c b/src/audio/pcm_converter/pcm_converter_hifi3.c index 0523454d746b..e89b25649945 100644 --- a/src/audio/pcm_converter/pcm_converter_hifi3.c +++ b/src/audio/pcm_converter/pcm_converter_hifi3.c @@ -1249,44 +1249,24 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, - ipc4_gtw_all & ~ipc4_gtw_host, ipc4_bidirection, pcm_convert_s24_to_s32}, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, - ipc4_gtw_host, ipc4_playback, audio_stream_copy}, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, - ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s32}, + ipc4_gtw_all, ipc4_bidirection, pcm_convert_s24_to_s32}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host), ipc4_bidirection, + ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh), ipc4_bidirection, pcm_convert_s32_to_s24 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_playback, pcm_convert_s32_to_s24_be }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_capture, pcm_convert_s32_to_s24 }, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_host, ipc4_playback, pcm_convert_s32_to_s24 }, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_host, ipc4_capture, pcm_convert_s32_to_s24_be }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE, - ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh | ipc4_gtw_host), + SOF_IPC_FRAME_S24_4LE, ipc4_gtw_all & ~(ipc4_gtw_link | ipc4_gtw_alh), ipc4_bidirection, pcm_convert_s16_to_s24 }, { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, ipc4_gtw_link | ipc4_gtw_alh, ipc4_playback, pcm_convert_s16_to_s32}, - { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, - ipc4_playback, pcm_convert_s16_to_s24 }, - { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE, ipc4_gtw_host, - ipc4_capture, pcm_convert_s16_to_s32 }, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S16_LE, ipc4_gtw_all & ~ipc4_gtw_host, - ipc4_bidirection, pcm_convert_s24_to_s16 }, - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S16_LE, ipc4_gtw_host, ipc4_playback, pcm_convert_s32_to_s16 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, - SOF_IPC_FRAME_S16_LE, ipc4_gtw_host, ipc4_capture, pcm_convert_s24_to_s16 }, + SOF_IPC_FRAME_S16_LE, ipc4_gtw_all, ipc4_bidirection, pcm_convert_s24_to_s16 }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S32_LE, From cb0f0daec6b8975c4cb0947d241c6e530b29f3d5 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Tue, 23 May 2023 16:59:54 +0200 Subject: [PATCH 52/94] Revert "module_adapter: Do not run on unconfigured bufs" This reverts commit 7c46d9c6fea68be3c0ee1ff426d24e12c8b9be15. --- src/audio/module_adapter/module_adapter.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 8a809f4b8457..e53eda4212e8 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -705,36 +705,20 @@ static int module_adapter_simple_copy(struct comp_dev *dev) uint32_t num_input_buffers = 0; uint32_t num_output_buffers = 0; int ret, i = 0; - bool all_bufs_configured = true; /* acquire all sink and source buffers */ list_for_item(blist, &dev->bsink_list) { struct comp_buffer *sink; sink = container_of(blist, struct comp_buffer, source_list); - sinks_c[i] = buffer_acquire(sink); - if (!sinks_c[i]->hw_params_configured) - all_bufs_configured = false; - i++; + sinks_c[i++] = buffer_acquire(sink); } i = 0; list_for_item(blist, &dev->bsource_list) { struct comp_buffer *source; source = container_of(blist, struct comp_buffer, sink_list); - source_c[i] = buffer_acquire(source); - if (!source_c[i]->hw_params_configured) - all_bufs_configured = false; - i++; - } - - if (!all_bufs_configured) { - comp_warn(dev, "Skipping .copy() as not all buffers yet configured"); - /* Do not abort processing -- wait for buffer(s) to be configured by - * other pipeline (possibly on another core). - */ - ret = 0; - goto out; + source_c[i++] = buffer_acquire(source); } /* setup active input/output buffers for processing */ From bf618a1e8a702a7332f8717dd62fc3ea1956307f Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Tue, 30 May 2023 19:00:41 +0200 Subject: [PATCH 53/94] host: zephyr: Subtract partial_size from dma avail/free size. When the host component detects use of deep buffering it decreases frequency of dma reloading. The number of processed data is summed up in the partial_size variable and they are acknowledged in larger packets. However, the size of processed data was not subtracted from the number of available data, which could lead to a buffer underrun/overrun. Signed-off-by: Adrian Warecki --- src/audio/host-zephyr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index caf51591a8d3..c611badb969d 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -417,11 +417,11 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev /* calculate minimum size to copy */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { - avail_samples = dma_stat.pending_length / dma_sample_bytes; + avail_samples = (dma_stat.pending_length - hd->partial_size) / dma_sample_bytes; free_samples = audio_stream_get_free_samples(&buffer_c->stream); } else { avail_samples = audio_stream_get_avail_samples(&buffer_c->stream); - free_samples = dma_stat.free / dma_sample_bytes; + free_samples = (dma_stat.free - hd->partial_size) / dma_sample_bytes; } dma_copy_bytes = MIN(avail_samples, free_samples) * dma_sample_bytes; From 8ddd262530042b10a5e566062433b5f2c294dd98 Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Thu, 1 Jun 2023 09:50:40 +0200 Subject: [PATCH 54/94] [WORKAROUND] mtl: host: Disable host dma reload delay Observed that sometimes the host needs even 4 ms to handle the dma buffer. With dma reload delay enabled sometimes the host can't keep up with writting/reading data leading to underrun/overrun. Signed-off-by: Adrian Warecki --- app/boards/intel_adsp_ace15_mtpm.conf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/boards/intel_adsp_ace15_mtpm.conf b/app/boards/intel_adsp_ace15_mtpm.conf index 69629e543ffa..8f190af50a40 100644 --- a/app/boards/intel_adsp_ace15_mtpm.conf +++ b/app/boards/intel_adsp_ace15_mtpm.conf @@ -75,7 +75,9 @@ CONFIG_LL_WATCHDOG=y # Temporary disabled options CONFIG_TRACE=n +CONFIG_HOST_DMA_RELOAD_DELAY_ENABLE=n + CONFIG_COMP_KPB=y CONFIG_COMP_ARIA=y CONFIG_CLOCK_CONTROL_ADSP=y -CONFIG_CLOCK_CONTROL=y +CONFIG_CLOCK_CONTROL=y \ No newline at end of file From c0585c219fd6dda18488b0e04664f4e8cb58160d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 20 Apr 2023 14:53:29 +0200 Subject: [PATCH 55/94] notifier: add a type for callbacks To make sure the same prototype is used for all notifier callbacks add a typedef. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib/notifier.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/include/sof/lib/notifier.h b/src/include/sof/lib/notifier.h index 99d11648f056..abf893281f70 100644 --- a/src/include/sof/lib/notifier.h +++ b/src/include/sof/lib/notifier.h @@ -58,6 +58,9 @@ struct notify_data { struct notify **arch_notify_get(void); +typedef void (*notifier_callback_t)(void *receiver_data, enum notify_id event_type, + void *caller_data); + /** Register a callback to be run when event 'type' happens. * * The identifier for un-registration is the tuple (receiver_data, @@ -74,9 +77,7 @@ struct notify **arch_notify_get(void); * @param flags see NOTIFIER_FLAG_* above */ int notifier_register(void *receiver_data, void *caller_id_filter, enum notify_id event_type, - void (*callback)(void *receiver_data, enum notify_id event_type, - void *caller_data), - uint32_t flags); + notifier_callback_t callback, uint32_t flags); /** Unregister all callbacks matching that arguments tuple. NULL acts * as a wildcard. From 2cc9c71e5a9383d98b9ab4fa13f163465777cb09 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 22 Mar 2023 17:34:47 +0100 Subject: [PATCH 56/94] IPC4: host: remove notifier, call the copier callback directly Using the notifier between the copier and the host makes little sense with native Zephyr drivers: it ends up in a direct function call, but before that it has to look for the correct callback in a global notifier list. The callback can perfectly be called directly instead. With legacy SOF drivers we still need to use the notifier because that is how SOF DMA drivers trigger the host component. We have to provide a compatibility callback in the copier for the IPC4 case. Signed-off-by: Guennadi Liakhovetski --- src/audio/copier/copier.c | 31 ++++++++-------- src/audio/host-legacy.c | 38 ++++++++++--------- src/audio/host-zephyr.c | 57 +++++++++-------------------- src/include/sof/audio/host_copier.h | 10 +++-- 4 files changed, 59 insertions(+), 77 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 809613f8a42b..b621e97e90b3 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -932,12 +931,8 @@ static int copier_reset(struct comp_dev *dev) cd->input_total_data_processed = 0; cd->output_total_data_processed = 0; - if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) { - if (cd->hd->chan) - notifier_unregister(dev, - cd->hd->chan, NOTIFIER_ID_DMA_COPY); + if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) host_zephyr_reset(cd->hd, dev->state); - } for (i = 0; i < cd->endpoint_num; i++) { if (dev->ipc_config.type != SOF_COMP_HOST || cd->ipc_gtw) { @@ -1191,9 +1186,12 @@ static int mux_into_multi_endpoint_buffer(struct copier_data *cd) return 0; } +static void copier_dma_cb(struct comp_dev *dev, size_t bytes); + static int do_endpoint_copy(struct comp_dev *dev) { struct copier_data *cd = comp_get_drvdata(dev); + if (cd->multi_endpoint_buffer) { int i; int ret = 0; @@ -1218,7 +1216,7 @@ static int do_endpoint_copy(struct comp_dev *dev) return ret; } else { if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) - return host_zephyr_copy(cd->hd, dev); + return host_zephyr_copy(cd->hd, dev, copier_dma_cb); return cd->endpoint[0]->drv->ops.copy(cd->endpoint[0]); } @@ -1385,13 +1383,10 @@ static void update_buffer_format(struct comp_buffer __sparse_cache *buf_c, /* This is called by DMA driver every time when DMA completes its current * transfer between host and DSP. */ -static void copier_dma_cb(void *arg, enum notify_id type, void *data) +static void copier_dma_cb(struct comp_dev *dev, size_t bytes) { - struct dma_cb_data *next = data; - struct comp_dev *dev = arg; struct copier_data *cd = comp_get_drvdata(dev); struct comp_buffer __sparse_cache *sink; - uint32_t bytes = next->elem.size; int ret, frames; comp_dbg(dev, "copier_dma_cb() %p", dev); @@ -1422,6 +1417,14 @@ static void copier_dma_cb(void *arg, enum notify_id type, void *data) } } +static void copier_notifier_cb(void *arg, enum notify_id type, void *data) +{ + struct dma_cb_data *next = data; + uint32_t bytes = next->elem.size; + + copier_dma_cb(arg, bytes); +} + /* configure the DMA params */ static int copier_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) { @@ -1505,11 +1508,7 @@ static int copier_params(struct comp_dev *dev, struct sof_ipc_stream_params *par cd->out_fmt->valid_bit_depth / 8; } - ret = host_zephyr_params(cd->hd, dev, params); - if (ret >= 0) - /* set up callback */ - notifier_register(dev, cd->hd->chan, - NOTIFIER_ID_DMA_COPY, copier_dma_cb, 0); + ret = host_zephyr_params(cd->hd, dev, params, copier_notifier_cb); cd->hd->process = cd->converter[IPC4_COPIER_GATEWAY_PIN]; } else { diff --git a/src/audio/host-legacy.c b/src/audio/host-legacy.c index 490394b6a876..d127d9423c0b 100644 --- a/src/audio/host-legacy.c +++ b/src/audio/host-legacy.c @@ -128,7 +128,7 @@ static uint32_t host_get_copy_bytes_one_shot(struct host_data *hd, struct comp_d * @param dev Host component device. * @return 0 if succeeded, error code otherwise. */ -static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev) +static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb) { uint32_t copy_bytes = 0; uint32_t split_value = 0; @@ -200,7 +200,7 @@ static uint32_t host_get_copy_bytes_one_shot(struct host_data *hd, struct comp_d * @param dev Host component device. * @return 0 if succeeded, error code otherwise. */ -static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev) +static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb) { uint32_t copy_bytes = 0; int ret = 0; @@ -355,7 +355,7 @@ static void host_dma_cb(void *arg, enum notify_id type, void *data) struct host_data *hd = comp_get_drvdata(dev); uint32_t bytes = next->elem.size; - comp_cl_dbg(&comp_host, "host_dma_cb() %p", &comp_host); + comp_dbg(dev, "host_dma_cb() %p", &comp_host); /* update position */ host_update_position(hd, dev, bytes); @@ -421,7 +421,7 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev * @param dev Host component device. * @return 0 if succeeded, error code otherwise. */ -static int host_copy_normal(struct host_data *hd, struct comp_dev *dev) +static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb) { uint32_t copy_bytes = 0; uint32_t flags = 0; @@ -687,7 +687,7 @@ static int host_verify_params(struct comp_dev *dev, /* configure the DMA params and descriptors for host buffer IO */ int host_zephyr_params(struct host_data *hd, struct comp_dev *dev, - struct sof_ipc_stream_params *params) + struct sof_ipc_stream_params *params, notifier_callback_t cb) { struct dma_sg_config *config = &hd->config; struct comp_buffer __sparse_cache *host_buf_c; @@ -856,6 +856,14 @@ int host_zephyr_params(struct host_data *hd, struct comp_dev *dev, out: buffer_release(host_buf_c); + + hd->cb_dev = dev; + + if (err >= 0) + /* set up callback */ + notifier_register(dev, hd->chan, NOTIFIER_ID_DMA_COPY, + cb ? : host_dma_cb, 0); + return err; } @@ -873,12 +881,7 @@ static int host_params(struct comp_dev *dev, return err; } - err = host_zephyr_params(hd, dev, params); - if (err >= 0) - /* set up callback */ - notifier_register(dev, hd->chan, NOTIFIER_ID_DMA_COPY, host_dma_cb, 0); - - return err; + return host_zephyr_params(hd, dev, params, NULL); } int host_zephyr_prepare(struct host_data *hd) @@ -924,6 +927,9 @@ void host_zephyr_reset(struct host_data *hd, uint16_t state) if (hd->chan) { dma_stop_delayed_legacy(hd->chan); + /* remove callback */ + notifier_unregister(hd->cb_dev, hd->chan, NOTIFIER_ID_DMA_COPY); + dma_channel_put_legacy(hd->chan); hd->chan = NULL; } @@ -958,10 +964,6 @@ static int host_reset(struct comp_dev *dev) comp_dbg(dev, "host_reset()"); - /* remove callback */ - if (hd->chan) - notifier_unregister(dev, hd->chan, NOTIFIER_ID_DMA_COPY); - host_zephyr_reset(hd, dev->state); dev->state = COMP_STATE_READY; @@ -969,9 +971,9 @@ static int host_reset(struct comp_dev *dev) } /* copy and process stream data from source to sink buffers */ -int host_zephyr_copy(struct host_data *hd, struct comp_dev *dev) +int host_zephyr_copy(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb) { - return hd->copy(hd, dev); + return hd->copy(hd, dev, cb); } static int host_copy(struct comp_dev *dev) @@ -981,7 +983,7 @@ static int host_copy(struct comp_dev *dev) if (dev->state != COMP_STATE_ACTIVE) return 0; - return host_zephyr_copy(hd, dev); + return host_zephyr_copy(hd, dev, NULL); } static int host_get_attribute(struct comp_dev *dev, uint32_t type, diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index c611badb969d..c496e5b29edb 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -75,7 +75,8 @@ static uint32_t host_dma_get_split(struct host_data *hd, uint32_t bytes) #if CONFIG_FORCE_DMA_COPY_WHOLE_BLOCK -static int host_dma_set_config_and_copy(struct host_data *hd, struct comp_dev *dev, uint32_t bytes) +static int host_dma_set_config_and_copy(struct host_data *hd, struct comp_dev *dev, uint32_t bytes, + copy_callback_t cb) { struct dma_sg_elem *local_elem = hd->config.elem_array.elems; int ret; @@ -90,12 +91,8 @@ static int host_dma_set_config_and_copy(struct host_data *hd, struct comp_dev *d return ret; } - struct dma_cb_data next = { - .channel = hd->chan, - .elem = { .size = bytes }, - }; - notifier_event(hd->chan, NOTIFIER_ID_DMA_COPY, - NOTIFIER_TARGET_CORE_LOCAL, &next, sizeof(next)); + cb(dev, bytes); + ret = dma_reload(hd->chan->dma->z_dev, hd->chan->index, 0, 0, bytes); if (ret < 0) { comp_err(dev, "host_dma_set_config_and_copy(): dma_copy() failed, ret = %d", @@ -139,7 +136,7 @@ static uint32_t host_get_copy_bytes_one_shot(struct host_data *hd) * @param dev Host component device. * @return 0 if succeeded, error code otherwise. */ -static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev) +static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb) { uint32_t copy_bytes; uint32_t split_value; @@ -158,7 +155,7 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev) split_value = host_dma_get_split(hd, copy_bytes); copy_bytes -= split_value; - ret = host_dma_set_config_and_copy(hd, dev, copy_bytes); + ret = host_dma_set_config_and_copy(hd, dev, copy_bytes, cb); if (ret < 0) return ret; @@ -214,7 +211,7 @@ static uint32_t host_get_copy_bytes_one_shot(struct host_data *hd) * @param dev Host component device. * @return 0 if succeeded, error code otherwise. */ -static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev) +static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb) { uint32_t copy_bytes; int ret = 0; @@ -234,12 +231,8 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev) return ret; } - struct dma_cb_data next = { - .channel = hd->chan, - .elem = { .size = copy_bytes }, - }; - notifier_event(hd->chan, NOTIFIER_ID_DMA_COPY, - NOTIFIER_TARGET_CORE_LOCAL, &next, sizeof(next)); + cb(dev, copy_bytes); + ret = dma_reload(hd->chan->dma->z_dev, hd->chan->index, 0, 0, copy_bytes); if (ret < 0) comp_err(dev, "host_copy_one_shot(): dma_copy() failed, ret = %u", ret); @@ -366,12 +359,9 @@ void host_one_shot_cb(struct host_data *hd, uint32_t bytes) /* This is called by DMA driver every time when DMA completes its current * transfer between host and DSP. */ -static void host_dma_cb(void *arg, enum notify_id type, void *data) +static void host_dma_cb(struct comp_dev *dev, size_t bytes) { - struct dma_cb_data *next = data; - struct comp_dev *dev = arg; struct host_data *hd = comp_get_drvdata(dev); - uint32_t bytes = next->elem.size; comp_cl_dbg(&comp_host, "host_dma_cb() %p", &comp_host); @@ -451,7 +441,7 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev * @param dev Host component device. * @return 0 if succeeded, error code otherwise. */ -static int host_copy_normal(struct host_data *hd, struct comp_dev *dev) +static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb) { struct comp_buffer __sparse_cache *buffer_c; uint32_t copy_bytes; @@ -471,12 +461,7 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev) /* Register Host DMA usage */ pm_runtime_get(PM_RUNTIME_HOST_DMA_L1, 0); - struct dma_cb_data next = { - .channel = hd->chan, - .elem = { .size = copy_bytes }, - }; - notifier_event(hd->chan, NOTIFIER_ID_DMA_COPY, - NOTIFIER_TARGET_CORE_LOCAL, &next, sizeof(next)); + cb(dev, copy_bytes); hd->partial_size += copy_bytes; buffer_c = buffer_acquire(hd->dma_buffer); @@ -762,7 +747,7 @@ static int host_verify_params(struct comp_dev *dev, /* configure the DMA params and descriptors for host buffer IO */ int host_zephyr_params(struct host_data *hd, struct comp_dev *dev, - struct sof_ipc_stream_params *params) + struct sof_ipc_stream_params *params, notifier_callback_t cb) { struct dma_sg_config *config = &hd->config; struct dma_sg_elem *sg_elem; @@ -1001,12 +986,7 @@ static int host_params(struct comp_dev *dev, return err; } - err = host_zephyr_params(hd, dev, params); - if (err >= 0) - /* set up callback */ - notifier_register(dev, hd->chan, NOTIFIER_ID_DMA_COPY, host_dma_cb, 0); - - return err; + return host_zephyr_params(hd, dev, params, NULL); } int host_zephyr_prepare(struct host_data *hd) @@ -1085,9 +1065,6 @@ static int host_reset(struct comp_dev *dev) struct host_data *hd = comp_get_drvdata(dev); comp_dbg(dev, "host_reset()"); - /* remove callback first for host reset */ - if (hd->chan) - notifier_unregister(dev, hd->chan, NOTIFIER_ID_DMA_COPY); host_zephyr_reset(hd, dev->state); dev->state = COMP_STATE_READY; @@ -1096,9 +1073,9 @@ static int host_reset(struct comp_dev *dev) } /* copy and process stream data from source to sink buffers */ -int host_zephyr_copy(struct host_data *hd, struct comp_dev *dev) +int host_zephyr_copy(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb) { - return hd->copy(hd, dev); + return hd->copy(hd, dev, cb); } static int host_copy(struct comp_dev *dev) @@ -1108,7 +1085,7 @@ static int host_copy(struct comp_dev *dev) if (dev->state != COMP_STATE_ACTIVE) return 0; - return host_zephyr_copy(hd, dev); + return host_zephyr_copy(hd, dev, host_dma_cb); } static int host_get_attribute(struct comp_dev *dev, uint32_t type, diff --git a/src/include/sof/audio/host_copier.h b/src/include/sof/audio/host_copier.h index 9e886b89a9fc..b4857af80595 100644 --- a/src/include/sof/audio/host_copier.h +++ b/src/include/sof/audio/host_copier.h @@ -21,9 +21,11 @@ #include #include +typedef void (*copy_callback_t)(struct comp_dev *dev, size_t bytes); + struct host_data; /** \brief Host copy function interface. */ -typedef int (*host_copy_func)(struct host_data *hd, struct comp_dev *dev); +typedef int (*host_copy_func)(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb); /** * \brief Host buffer info. @@ -51,6 +53,8 @@ struct host_data { #ifdef __ZEPHYR__ struct dma_config z_config; #endif + struct comp_dev *cb_dev; + struct comp_buffer *dma_buffer; struct comp_buffer *local_buffer; @@ -100,8 +104,8 @@ int host_zephyr_prepare(struct host_data *hd); void host_zephyr_reset(struct host_data *hd, uint16_t state); int host_zephyr_trigger(struct host_data *hd, struct comp_dev *dev, int cmd); int host_zephyr_params(struct host_data *hd, struct comp_dev *dev, - struct sof_ipc_stream_params *params); -int host_zephyr_copy(struct host_data *hd, struct comp_dev *dev); + struct sof_ipc_stream_params *params, notifier_callback_t cb); +int host_zephyr_copy(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb); void host_update_position(struct host_data *hd, struct comp_dev *dev, uint32_t bytes); void host_one_shot_cb(struct host_data *hd, uint32_t bytes); From 1255173204afd9373b50dd75dd2a7d8bff23389b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 09:33:07 -0700 Subject: [PATCH 57/94] dai: Modify the signature of dai_release_llp_slot() In preparation for using this function for both a DAI device and a copier device, modify the signature to pass the dai_data as the input instead of the dev pointer. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 2 +- src/audio/dai-zephyr.c | 2 +- src/include/sof/lib/dai-legacy.h | 2 +- src/include/sof/lib/dai-zephyr.h | 2 +- src/ipc/ipc3/dai.c | 2 +- src/ipc/ipc4/dai.c | 3 +-- 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index dafefecda260..2489f6e37f4e 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -235,7 +235,7 @@ static void dai_free(struct comp_dev *dev) dma_put(dd->dma); - dai_release_llp_slot(dev); + dai_release_llp_slot(dd); dai_put(dd->dai); diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 034f10945b87..0b9bfdff7655 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -357,7 +357,7 @@ static void dai_free(struct comp_dev *dev) dma_put(dd->dma); - dai_release_llp_slot(dev); + dai_release_llp_slot(dd); dai_put(dd->dai); diff --git a/src/include/sof/lib/dai-legacy.h b/src/include/sof/lib/dai-legacy.h index dcce8238719d..c08b164ae6ed 100644 --- a/src/include/sof/lib/dai-legacy.h +++ b/src/include/sof/lib/dai-legacy.h @@ -574,7 +574,7 @@ void dai_dma_position_update(struct comp_dev *dev); /** * \brief release llp slot */ -void dai_release_llp_slot(struct comp_dev *dev); +void dai_release_llp_slot(struct dai_data *dd); /** @}*/ #endif /* __SOF_LIB_DAI_LEGACY_H__ */ diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index e383db19e782..05c6e14f3cf5 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -283,7 +283,7 @@ void dai_dma_position_update(struct comp_dev *dev); /** * \brief release llp slot */ -void dai_release_llp_slot(struct comp_dev *dev); +void dai_release_llp_slot(struct dai_data *dd); /** @}*/ #endif /* __SOF_LIB_DAI_ZEPHYR_H__ */ diff --git a/src/ipc/ipc3/dai.c b/src/ipc/ipc3/dai.c index bffe3192eb05..28d9184dd96b 100644 --- a/src/ipc/ipc3/dai.c +++ b/src/ipc/ipc3/dai.c @@ -398,4 +398,4 @@ int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) void dai_dma_position_update(struct comp_dev *dev) { } -void dai_release_llp_slot(struct comp_dev *dev) { } +void dai_release_llp_slot(struct dai_data *dd) { } diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index be2f10eb08b5..d3dcef862cdb 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -189,9 +189,8 @@ void dai_dma_release(struct comp_dev *dev) } } -void dai_release_llp_slot(struct comp_dev *dev) +void dai_release_llp_slot(struct dai_data *dd) { - struct dai_data *dd = comp_get_drvdata(dev); struct ipc4_llp_reading_slot slot; k_spinlock_key_t key; From 8b2a4af56af8ed2bac8957c1bbbd31d5853d036e Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 09:39:02 -0700 Subject: [PATCH 58/94] dai-zephyr/dai-legacy: Split the dai_new() function Split the dai_new() function to add a helper function, dai_zephyr_new() in preparation for this to be called from both a DAI device and copier device. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 58 +++++++++++++++++++++++--------------- src/audio/dai-zephyr.c | 64 +++++++++++++++++++++++++----------------- 2 files changed, 74 insertions(+), 48 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 2489f6e37f4e..f20bdb1061a5 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -160,34 +160,15 @@ static void dai_dma_cb(void *arg, enum notify_id type, void *data) buffer_release(dma_buf); } -static struct comp_dev *dai_new(const struct comp_driver *drv, - const struct comp_ipc_config *config, - const void *spec) +static int dai_zephyr_new(struct dai_data *dd, struct comp_dev *dev, + const struct ipc_config_dai *dai) { - struct comp_dev *dev; - const struct ipc_config_dai *dai = spec; - struct dai_data *dd; uint32_t dir, caps, dma_dev; - comp_cl_dbg(&comp_dai, "dai_new()"); - - dev = comp_alloc(drv, sizeof(*dev)); - if (!dev) - return NULL; - dev->ipc_config = *config; - - dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); - if (!dd) { - rfree(dev); - return NULL; - } - - comp_set_drvdata(dev, dd); - dd->dai = dai_get(dai->type, dai->dai_index, DAI_CREAT); if (!dd->dai) { comp_cl_err(&comp_dai, "dai_new(): dai_get() failed to create DAI."); - goto error; + return -ENODEV; } dd->dai->dd = dd; dd->ipc_config = *dai; @@ -202,13 +183,44 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, dd->dma = dma_get(dir, caps, dma_dev, DMA_ACCESS_SHARED); if (!dd->dma) { comp_cl_err(&comp_dai, "dai_new(): dma_get() failed to get shared access to DMA."); - goto error; + return -ENODEV; } dma_sg_init(&dd->config.elem_array); dd->xrun = 0; dd->chan = NULL; + return 0; +} + +static struct comp_dev *dai_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec) +{ + struct comp_dev *dev; + const struct ipc_config_dai *dai = spec; + struct dai_data *dd; + int ret; + + comp_cl_dbg(&comp_dai, "dai_new()"); + + dev = comp_alloc(drv, sizeof(*dev)); + if (!dev) + return NULL; + dev->ipc_config = *config; + + dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); + if (!dd) { + rfree(dev); + return NULL; + } + + comp_set_drvdata(dev, dd); + + ret = dai_zephyr_new(dd, dev, dai); + if (ret < 0) + goto error; + dev->state = COMP_STATE_READY; return dev; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 0b9bfdff7655..8b94ec1c5bb0 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -284,34 +284,15 @@ static enum dma_cb_status dai_dma_cb(struct comp_dev *dev, uint32_t bytes) return dma_status; } -static struct comp_dev *dai_new(const struct comp_driver *drv, - const struct comp_ipc_config *config, - const void *spec) +static int dai_zephyr_new(struct dai_data *dd, struct comp_dev *dev, + const struct ipc_config_dai *dai_cfg) { - struct comp_dev *dev; - const struct ipc_config_dai *dai_cfg = spec; - struct dai_data *dd; uint32_t dir; - comp_cl_dbg(&comp_dai, "dai_new()"); - - dev = comp_alloc(drv, sizeof(*dev)); - if (!dev) - return NULL; - dev->ipc_config = *config; - - dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); - if (!dd) { - rfree(dev); - return NULL; - } - - comp_set_drvdata(dev, dd); - dd->dai = dai_get(dai_cfg->type, dai_cfg->dai_index, DAI_CREAT); if (!dd->dai) { - comp_cl_err(&comp_dai, "dai_new(): dai_get() failed to create DAI."); - goto error; + comp_err(dev, "dai_new(): dai_get() failed to create DAI."); + return -ENODEV; } dd->ipc_config = *dai_cfg; @@ -322,8 +303,9 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, dd->dma = dma_get(dir, dd->dai->dma_caps, dd->dai->dma_dev, DMA_ACCESS_SHARED); if (!dd->dma) { - comp_cl_err(&comp_dai, "dai_new(): dma_get() failed to get shared access to DMA."); - goto error; + dai_put(dd->dai); + comp_err(dev, "dai_new(): dma_get() failed to get shared access to DMA."); + return -ENODEV; } k_spinlock_init(&dd->dai->lock); @@ -332,11 +314,43 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, dd->xrun = 0; dd->chan = NULL; + return 0; +} + +static struct comp_dev *dai_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec) +{ + struct comp_dev *dev; + const struct ipc_config_dai *dai_cfg = spec; + struct dai_data *dd; + int ret; + + comp_cl_dbg(&comp_dai, "dai_new()"); + + dev = comp_alloc(drv, sizeof(*dev)); + if (!dev) + return NULL; + + dev->ipc_config = *config; + + dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); + if (!dd) + goto e_data; + + comp_set_drvdata(dev, dd); + + ret = dai_zephyr_new(dd, dev, dai_cfg); + if (ret < 0) + goto error; + dev->state = COMP_STATE_READY; + return dev; error: rfree(dd); +e_data: rfree(dev); return NULL; } From f3ff9890f86a1561b6328a1ac6322c0823bb803e Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 09:42:27 -0700 Subject: [PATCH 59/94] dai-zephyr/dai-legacy: Split the dai_free() function Split the dai_free() function to add a helper function, dai_zephyr_free() in preparation for this to be called from both a DAI device and copier device. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 22 +++++++++++++++------- src/audio/dai-zephyr.c | 19 +++++++++++++------ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index f20bdb1061a5..b7d2b8f3aebb 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -230,17 +230,12 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, return NULL; } -static void dai_free(struct comp_dev *dev) +static void dai_zephyr_free(struct dai_data *dd) { - struct dai_data *dd = comp_get_drvdata(dev); - - if (dd->group) { - notifier_unregister(dev, dd->group, NOTIFIER_ID_DAI_TRIGGER); + if (dd->group) dai_group_put(dd->group); - } if (dd->chan) { - notifier_unregister(dev, dd->chan, NOTIFIER_ID_DMA_COPY); dd->chan->dev_data = NULL; dma_channel_put_legacy(dd->chan); } @@ -253,6 +248,19 @@ static void dai_free(struct comp_dev *dev) if (dd->dai_spec_config) rfree(dd->dai_spec_config); +} + +static void dai_free(struct comp_dev *dev) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + if (dd->group) + notifier_unregister(dev, dd->group, NOTIFIER_ID_DAI_TRIGGER); + + if (dd->chan) + notifier_unregister(dev, dd->chan, NOTIFIER_ID_DMA_COPY); + + dai_zephyr_free(dd); rfree(dd); rfree(dev); diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 8b94ec1c5bb0..3254020d0793 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -355,14 +355,10 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, return NULL; } -static void dai_free(struct comp_dev *dev) +static void dai_zephyr_free(struct dai_data *dd) { - struct dai_data *dd = comp_get_drvdata(dev); - - if (dd->group) { - notifier_unregister(dev, dd->group, NOTIFIER_ID_DAI_TRIGGER); + if (dd->group) dai_group_put(dd->group); - } if (dd->chan) { dma_release_channel(dd->dma->z_dev, dd->chan->index); @@ -376,6 +372,17 @@ static void dai_free(struct comp_dev *dev) dai_put(dd->dai); rfree(dd->dai_spec_config); +} + +static void dai_free(struct comp_dev *dev) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + if (dd->group) + notifier_unregister(dev, dd->group, NOTIFIER_ID_DAI_TRIGGER); + + dai_zephyr_free(dd); + rfree(dd); rfree(dev); } From 5fc891c73ebc9026ddf768b49abf8c1eae4f6566 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 3 May 2023 08:10:58 -0700 Subject: [PATCH 60/94] dai: Modify the signature of dai_config_dma_channel() In preparation for this function to be used by both a copier device and the DAI device, modify the signature to pass both the dai_data and the device pointer. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 2 +- src/audio/dai-zephyr.c | 2 +- src/include/sof/lib/dai-legacy.h | 2 +- src/include/sof/lib/dai-zephyr.h | 2 +- src/ipc/ipc3/dai.c | 5 ++--- src/ipc/ipc4/dai.c | 5 ++--- 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index b7d2b8f3aebb..39f64659170a 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -640,7 +640,7 @@ static int dai_config_prepare(struct comp_dev *dev) return 0; } - channel = dai_config_dma_channel(dev, dd->dai_spec_config); + channel = dai_config_dma_channel(dd, dev, dd->dai_spec_config); comp_info(dev, "dai_config_prepare(), channel = %d", channel); /* do nothing for asking for channel free, for compatibility. */ diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 3254020d0793..9f58581f706c 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -895,7 +895,7 @@ static int dai_config_prepare(struct comp_dev *dev) return 0; } - channel = dai_config_dma_channel(dev, dd->dai_spec_config); + channel = dai_config_dma_channel(dd, dev, dd->dai_spec_config); comp_dbg(dev, "dai_config_prepare(), channel = %d", channel); /* do nothing for asking for channel free, for compatibility. */ diff --git a/src/include/sof/lib/dai-legacy.h b/src/include/sof/lib/dai-legacy.h index c08b164ae6ed..873d0cb78d85 100644 --- a/src/include/sof/lib/dai-legacy.h +++ b/src/include/sof/lib/dai-legacy.h @@ -543,7 +543,7 @@ static inline const struct dai_info *dai_info_get(void) /** * \brief Configure DMA channel for DAI */ -int dai_config_dma_channel(struct comp_dev *dev, const void *config); +int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void *config); /** * \brief Reset DAI DMA config diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index 05c6e14f3cf5..b1651017a4c3 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -253,7 +253,7 @@ int dai_get_stream_id(struct dai *dai, int direction); /** * \brief Configure DMA channel for DAI */ -int dai_config_dma_channel(struct comp_dev *dev, const void *config); +int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void *config); /** * \brief Reset DAI DMA config diff --git a/src/ipc/ipc3/dai.c b/src/ipc/ipc3/dai.c index 28d9184dd96b..fff4dba7df97 100644 --- a/src/ipc/ipc3/dai.c +++ b/src/ipc/ipc3/dai.c @@ -29,9 +29,8 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); -int dai_config_dma_channel(struct comp_dev *dev, const void *spec_config) +int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void *spec_config) { - struct dai_data *dd = comp_get_drvdata(dev); const struct sof_ipc_dai_config *config = spec_config; struct ipc_config_dai *dai = &dd->ipc_config; int channel; @@ -360,7 +359,7 @@ int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config, } #endif /* do nothing for asking for channel free, for compatibility. */ - if (dai_config_dma_channel(dev, spec_config) == DMA_CHAN_INVALID) + if (dai_config_dma_channel(dd, dev, spec_config) == DMA_CHAN_INVALID) return 0; /* allocated dai_config if not yet */ diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index d3dcef862cdb..e324d8425b09 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -30,10 +30,9 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); -int dai_config_dma_channel(struct comp_dev *dev, const void *spec_config) +int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void *spec_config) { const struct ipc4_copier_module_cfg *copier_cfg = spec_config; - struct dai_data *dd = comp_get_drvdata(dev); struct ipc_config_dai *dai = &dd->ipc_config; int channel; @@ -319,7 +318,7 @@ int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config, } #endif /* do nothing for asking for channel free, for compatibility. */ - if (dai_config_dma_channel(dev, spec_config) == DMA_CHAN_INVALID) + if (dai_config_dma_channel(dd, dev, spec_config) == DMA_CHAN_INVALID) return 0; dd->dai_dev = dev; From 3fc4a2a24e616a68b66081a3571ab988c1deea7d Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Wed, 3 May 2023 08:14:14 -0700 Subject: [PATCH 61/94] copier: Expose dai_zephyr_new()/free() Expose the dai_zephyr_new()/free() functions and use them for creating/freeing the endpoint device when the dai_count is 1 when a copier device is created. This is preparation to replace the endpoint device with the copier device and eventually remove the endpoint device itself. Signed-off-by: Baofeng Tian Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 96 ++++++++++++++++++++++++------ src/audio/dai-legacy.c | 6 +- src/audio/dai-zephyr.c | 7 ++- src/include/ipc4/alh.h | 1 + src/include/ipc4/copier.h | 2 + src/include/sof/audio/dai_copier.h | 25 ++++++++ 6 files changed, 114 insertions(+), 23 deletions(-) create mode 100644 src/include/sof/audio/dai_copier.h diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index b621e97e90b3..1c6abc8fccfc 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -36,6 +36,7 @@ #include #include #include +#include static const struct comp_driver comp_copier; @@ -292,6 +293,41 @@ static enum sof_ipc_stream_direction } } +static struct comp_dev *init_dai_single(struct comp_dev *parent_dev, + const struct comp_driver *drv, + struct comp_ipc_config *config, + struct ipc_config_dai *dai) +{ + struct comp_dev *dev; + struct dai_data *dd; + int ret; + + dev = comp_alloc(drv, sizeof(*dev)); + if (!dev) + return NULL; + + dev->ipc_config = *config; + + dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); + if (!dd) + goto free_dev; + + comp_set_drvdata(dev, dd); + + ret = dai_zephyr_new(dd, parent_dev, dai); + if (ret < 0) + goto free_dd; + + dev->state = COMP_STATE_READY; + + return dev; +free_dd: + rfree(dd); +free_dev: + rfree(dev); + return NULL; +} + static int init_dai(struct comp_dev *parent_dev, const struct comp_driver *drv, struct comp_ipc_config *config, @@ -299,7 +335,7 @@ static int init_dai(struct comp_dev *parent_dev, struct pipeline *pipeline, struct ipc_config_dai *dai, enum ipc4_gateway_type type, - int index) + int index, int dai_count) { struct comp_dev *dev; struct copier_data *cd; @@ -310,9 +346,13 @@ static int init_dai(struct comp_dev *parent_dev, if (ret < 0) return ret; - dev = drv->ops.create(drv, config, dai); + if (dai_count == 1) + dev = init_dai_single(parent_dev, drv, config, dai); + else + dev = drv->ops.create(drv, config, dai); + if (!dev) { - ret = -EINVAL; + ret = -ENOMEM; goto e_buf; } @@ -328,7 +368,7 @@ static int init_dai(struct comp_dev *parent_dev, ret = comp_dai_config(dev, dai, copier); if (ret < 0) - goto e_buf; + goto free_dev; if (dai->direction == SOF_IPC_STREAM_PLAYBACK) { comp_buffer_connect(dev, config->core, cd->endpoint_buffer[cd->endpoint_num], @@ -346,13 +386,16 @@ static int init_dai(struct comp_dev *parent_dev, if (!cd->converter[IPC4_COPIER_GATEWAY_PIN]) { comp_err(parent_dev, "failed to get converter type %d, dir %d", type, dai->direction); - return -EINVAL; + ret = -EINVAL; + goto free_dev; } cd->endpoint[cd->endpoint_num++] = dev; + cd->dd[index] = comp_get_drvdata(dev); return 0; - +free_dev: + drv->ops.free(dev); e_buf: buffer_free(cd->endpoint_buffer[cd->endpoint_num]); return ret; @@ -466,7 +509,8 @@ static int create_dai(struct comp_dev *parent_dev, struct copier_data *cd, int ret; dai.dai_index = dai_index[i]; - ret = init_dai(parent_dev, drv, config, copier, pipeline, &dai, type, i); + ret = init_dai(parent_dev, drv, config, copier, pipeline, &dai, type, i, + dai_count); if (ret) { comp_err(parent_dev, "failed to create dai"); return ret; @@ -709,21 +753,39 @@ static void copier_free(struct comp_dev *dev) struct copier_data *cd = comp_get_drvdata(dev); int i; - if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) { - host_zephyr_free(cd->hd); - rfree(cd->hd); + switch (dev->ipc_config.type) { + case SOF_COMP_HOST: + if (!cd->ipc_gtw) { + host_zephyr_free(cd->hd); + rfree(cd->hd); + } else { + /* handle gtw case */ + for (i = 0; i < cd->endpoint_num; i++) { + cd->endpoint[i]->drv->ops.free(cd->endpoint[i]); + buffer_free(cd->endpoint_buffer[i]); + } + } + break; + case SOF_COMP_DAI: + if (cd->endpoint_num == 1) { + dai_zephyr_free(cd->dd[0]); + rfree(cd->dd[0]); + rfree(cd->endpoint[0]); + buffer_free(cd->endpoint_buffer[0]); + } else { + for (i = 0; i < cd->endpoint_num; i++) { + cd->endpoint[i]->drv->ops.free(cd->endpoint[i]); + buffer_free(cd->endpoint_buffer[i]); + } + } + break; + default: + break; } if (cd->multi_endpoint_buffer) buffer_free(cd->multi_endpoint_buffer); - for (i = 0; i < cd->endpoint_num; i++) { - if (dev->ipc_config.type != SOF_COMP_HOST || cd->ipc_gtw) { - cd->endpoint[i]->drv->ops.free(cd->endpoint[i]); - buffer_free(cd->endpoint_buffer[i]); - } - } - rfree(cd); rfree(dev); } diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 39f64659170a..64029516e62e 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -160,8 +161,7 @@ static void dai_dma_cb(void *arg, enum notify_id type, void *data) buffer_release(dma_buf); } -static int dai_zephyr_new(struct dai_data *dd, struct comp_dev *dev, - const struct ipc_config_dai *dai) +int dai_zephyr_new(struct dai_data *dd, struct comp_dev *dev, const struct ipc_config_dai *dai) { uint32_t dir, caps, dma_dev; @@ -230,7 +230,7 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, return NULL; } -static void dai_zephyr_free(struct dai_data *dd) +void dai_zephyr_free(struct dai_data *dd) { if (dd->group) dai_group_put(dd->group); diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 9f58581f706c..66bc82a8381f 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -284,8 +285,8 @@ static enum dma_cb_status dai_dma_cb(struct comp_dev *dev, uint32_t bytes) return dma_status; } -static int dai_zephyr_new(struct dai_data *dd, struct comp_dev *dev, - const struct ipc_config_dai *dai_cfg) +int dai_zephyr_new(struct dai_data *dd, struct comp_dev *dev, + const struct ipc_config_dai *dai_cfg) { uint32_t dir; @@ -355,7 +356,7 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, return NULL; } -static void dai_zephyr_free(struct dai_data *dd) +void dai_zephyr_free(struct dai_data *dd) { if (dd->group) dai_group_put(dd->group); diff --git a/src/include/ipc4/alh.h b/src/include/ipc4/alh.h index a5a15b19be48..8a296973cf32 100644 --- a/src/include/ipc4/alh.h +++ b/src/include/ipc4/alh.h @@ -25,6 +25,7 @@ #define __SOF_IPC4_ALH_H__ #include +#include #include #define IPC4_ALH_MAX_NUMBER_OF_GTW 16 diff --git a/src/include/ipc4/copier.h b/src/include/ipc4/copier.h index 02c467cd1cfd..10eeccc656d3 100644 --- a/src/include/ipc4/copier.h +++ b/src/include/ipc4/copier.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -263,6 +264,7 @@ struct copier_data { uint64_t output_total_data_processed; struct host_data *hd; bool ipc_gtw; + struct dai_data *dd[IPC4_ALH_MAX_NUMBER_OF_GTW]; }; int apply_attenuation(struct comp_dev *dev, struct copier_data *cd, diff --git a/src/include/sof/audio/dai_copier.h b/src/include/sof/audio/dai_copier.h new file mode 100644 index 000000000000..5c50263d2641 --- /dev/null +++ b/src/include/sof/audio/dai_copier.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Baofeng Tian + */ + +/** + * \file audio/dai_copier.h + * \brief dai copier shared header file + * \authors Baofeng Tian + */ + +#ifndef __SOF_LIB_DAI_COPIER_H__ +#define __SOF_LIB_DAI_COPIER_H__ + +struct ipc_config_dai; +struct comp_dev; +struct dai_data; +int dai_zephyr_new(struct dai_data *dd, struct comp_dev *dev, + const struct ipc_config_dai *dai_cfg); + +void dai_zephyr_free(struct dai_data *dd); + +#endif /* __SOF_LIB_DAI_COPIER_H__ */ From 2ade6c8c4c02012552b2e2f80283b729f3e87d1a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 10:53:05 -0700 Subject: [PATCH 62/94] dai-zephyr/dai-legacy: split the dai_prepare() function Split the dai_prepare() function and add a new helper, dai_zephyr_prepare() that can also be invoked from the copier device. Also modify the dai_config_prepare() function to pass the dai_data and device separately for use with the copier device. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 44 +++++++++++++++++++++++----------------- src/audio/dai-zephyr.c | 46 ++++++++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 64029516e62e..1d486080c495 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -618,9 +618,8 @@ static int dai_params(struct comp_dev *dev, dai_capture_params(dev, period_bytes, period_count); } -static int dai_config_prepare(struct comp_dev *dev) +static int dai_config_prepare(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); int channel = 0; /* cannot configure DAI while active */ @@ -669,24 +668,10 @@ static int dai_config_prepare(struct comp_dev *dev) return 0; } -static int dai_prepare(struct comp_dev *dev) +static int dai_zephyr_prepare(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct comp_buffer __sparse_cache *buffer_c; - int ret = 0; - - comp_info(dev, "dai_prepare()"); - - ret = dai_config_prepare(dev); - if (ret < 0) - return ret; - - ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); - if (ret < 0) - return ret; - - if (ret == COMP_STATUS_STATE_ALREADY_SET) - return PPL_STATUS_PATH_STOP; + int ret; dd->total_data_processed = 0; @@ -711,7 +696,7 @@ static int dai_prepare(struct comp_dev *dev) if (dd->xrun) { /* after prepare, we have recovered from xrun */ dd->xrun = 0; - return ret; + return 0; } ret = dma_set_config_legacy(dd->chan, &dd->config); @@ -721,6 +706,27 @@ static int dai_prepare(struct comp_dev *dev) return ret; } +static int dai_prepare(struct comp_dev *dev) +{ + struct dai_data *dd = comp_get_drvdata(dev); + int ret; + + comp_info(dev, "dai_prepare()"); + + ret = dai_config_prepare(dd, dev); + if (ret < 0) + return ret; + + ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); + if (ret < 0) + return ret; + + if (ret == COMP_STATUS_STATE_ALREADY_SET) + return PPL_STATUS_PATH_STOP; + + return dai_zephyr_prepare(dd, dev); +} + static int dai_reset(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 66bc82a8381f..40f4a9532523 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -874,9 +874,8 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params dai_capture_params(dev, period_bytes, period_count); } -static int dai_config_prepare(struct comp_dev *dev) +static int dai_config_prepare(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); int channel; /* cannot configure DAI while active */ @@ -922,35 +921,21 @@ static int dai_config_prepare(struct comp_dev *dev) return 0; } -static int dai_prepare(struct comp_dev *dev) +static int dai_zephyr_prepare(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct comp_buffer __sparse_cache *buffer_c; int ret; - comp_dbg(dev, "dai_prepare()"); - - ret = dai_config_prepare(dev); - if (ret < 0) - return ret; - - ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); - if (ret < 0) - return ret; - - if (ret == COMP_STATUS_STATE_ALREADY_SET) - return PPL_STATUS_PATH_STOP; - dd->total_data_processed = 0; if (!dd->chan) { - comp_err(dev, "dai_prepare(): Missing dd->chan."); + comp_err(dev, "dai_zephyr_prepare(): Missing dd->chan."); comp_set_state(dev, COMP_TRIGGER_RESET); return -EINVAL; } if (!dd->config.elem_array.elems) { - comp_err(dev, "dai_prepare(): Missing dd->config.elem_array.elems."); + comp_err(dev, "dai_zephyr_prepare(): Missing dd->config.elem_array.elems."); comp_set_state(dev, COMP_TRIGGER_RESET); return -EINVAL; } @@ -964,7 +949,7 @@ static int dai_prepare(struct comp_dev *dev) if (dd->xrun) { /* after prepare, we have recovered from xrun */ dd->xrun = 0; - return ret; + return 0; } ret = dma_config(dd->chan->dma->z_dev, dd->chan->index, dd->z_config); @@ -974,6 +959,27 @@ static int dai_prepare(struct comp_dev *dev) return ret; } +static int dai_prepare(struct comp_dev *dev) +{ + struct dai_data *dd = comp_get_drvdata(dev); + int ret; + + comp_dbg(dev, "dai_prepare()"); + + ret = dai_config_prepare(dd, dev); + if (ret < 0) + return ret; + + ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); + if (ret < 0) + return ret; + + if (ret == COMP_STATUS_STATE_ALREADY_SET) + return PPL_STATUS_PATH_STOP; + + return dai_zephyr_prepare(dd, dev); +} + static int dai_reset(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); From da11f12fa6e3526944e8a79d2fb172b56ff94ba6 Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Wed, 15 Mar 2023 15:55:06 +0800 Subject: [PATCH 63/94] dai-zephyr/dai-legacy: Expose dai_zephyr_prepare() and dai_zephyr_config_prepare() Rename dai_config_prepare() to add the zephyr prefix and expose both functions and use them in the copier device in the single endpoint DAI case. Signed-off-by: Baofeng Tian Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 45 ++++++++++++++++++++++++------ src/audio/dai-legacy.c | 16 +++++------ src/audio/dai-zephyr.c | 16 +++++------ src/include/sof/audio/dai_copier.h | 3 ++ 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 1c6abc8fccfc..ce705b5a5757 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -928,18 +928,47 @@ static int copier_prepare(struct comp_dev *dev) if (ret == COMP_STATUS_STATE_ALREADY_SET) return PPL_STATUS_PATH_STOP; - if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) { - ret = host_zephyr_prepare(cd->hd); - if (ret < 0) - return ret; - } + switch (dev->ipc_config.type) { + case SOF_COMP_HOST: + if (!cd->ipc_gtw) { + ret = host_zephyr_prepare(cd->hd); + if (ret < 0) + return ret; + } else { + /* handle gtw case */ + for (i = 0; i < cd->endpoint_num; i++) { + ret = cd->endpoint[i]->drv->ops.prepare(cd->endpoint[i]); + if (ret < 0) + return ret; + } + } + break; + case SOF_COMP_DAI: + if (cd->endpoint_num == 1) { + ret = dai_zephyr_config_prepare(cd->dd[0], cd->endpoint[0]); + if (ret < 0) + return ret; - for (i = 0; i < cd->endpoint_num; i++) { - if (dev->ipc_config.type != SOF_COMP_HOST || cd->ipc_gtw) { - ret = cd->endpoint[i]->drv->ops.prepare(cd->endpoint[i]); + ret = comp_set_state(cd->endpoint[0], COMP_TRIGGER_PREPARE); if (ret < 0) return ret; + + if (ret == COMP_STATUS_STATE_ALREADY_SET) + return PPL_STATUS_PATH_STOP; + + ret = dai_zephyr_prepare(cd->dd[0], cd->endpoint[0]); + if (ret < 0) + return ret; + } else { + for (i = 0; i < cd->endpoint_num; i++) { + ret = cd->endpoint[i]->drv->ops.prepare(cd->endpoint[i]); + if (ret < 0) + return ret; + } } + break; + default: + break; } if (!cd->endpoint_num) { diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 1d486080c495..98c9c5c85101 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -618,13 +618,13 @@ static int dai_params(struct comp_dev *dev, dai_capture_params(dev, period_bytes, period_count); } -static int dai_config_prepare(struct dai_data *dd, struct comp_dev *dev) +int dai_zephyr_config_prepare(struct dai_data *dd, struct comp_dev *dev) { int channel = 0; /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { - comp_info(dev, "dai_config_prepare(): Component is in active state."); + comp_info(dev, "dai_zephyr_config_prepare(): Component is in active state."); return 0; } @@ -634,13 +634,13 @@ static int dai_config_prepare(struct dai_data *dd, struct comp_dev *dev) } if (dd->chan) { - comp_info(dev, "dai_config_prepare(): dma channel index %d already configured", + comp_info(dev, "dai_zephyr_config_prepare(): dma channel index %d already configured", dd->chan->index); return 0; } channel = dai_config_dma_channel(dd, dev, dd->dai_spec_config); - comp_info(dev, "dai_config_prepare(), channel = %d", channel); + comp_info(dev, "dai_zephyr_config_prepare(), channel = %d", channel); /* do nothing for asking for channel free, for compatibility. */ if (channel == DMA_CHAN_INVALID) { @@ -651,14 +651,14 @@ static int dai_config_prepare(struct dai_data *dd, struct comp_dev *dev) /* allocate DMA channel */ dd->chan = dma_channel_get_legacy(dd->dma, channel); if (!dd->chan) { - comp_err(dev, "dai_config_prepare(): dma_channel_get() failed"); + comp_err(dev, "dai_zephyr_config_prepare(): dma_channel_get() failed"); dd->chan = NULL; return -EIO; } dd->chan->dev_data = dd; - comp_info(dev, "dai_config_prepare(): new configured dma channel index %d", + comp_info(dev, "dai_zephyr_config_prepare(): new configured dma channel index %d", dd->chan->index); /* setup callback */ @@ -668,7 +668,7 @@ static int dai_config_prepare(struct dai_data *dd, struct comp_dev *dev) return 0; } -static int dai_zephyr_prepare(struct dai_data *dd, struct comp_dev *dev) +int dai_zephyr_prepare(struct dai_data *dd, struct comp_dev *dev) { struct comp_buffer __sparse_cache *buffer_c; int ret; @@ -713,7 +713,7 @@ static int dai_prepare(struct comp_dev *dev) comp_info(dev, "dai_prepare()"); - ret = dai_config_prepare(dd, dev); + ret = dai_zephyr_config_prepare(dd, dev); if (ret < 0) return ret; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 40f4a9532523..06af16e970ab 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -874,13 +874,13 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params dai_capture_params(dev, period_bytes, period_count); } -static int dai_config_prepare(struct dai_data *dd, struct comp_dev *dev) +int dai_zephyr_config_prepare(struct dai_data *dd, struct comp_dev *dev) { int channel; /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { - comp_info(dev, "dai_config_prepare(): Component is in active state."); + comp_info(dev, "dai_zephyr_config_prepare(): Component is in active state."); return 0; } @@ -890,13 +890,13 @@ static int dai_config_prepare(struct dai_data *dd, struct comp_dev *dev) } if (dd->chan) { - comp_info(dev, "dai_config_prepare(): dma channel index %d already configured", + comp_info(dev, "dai_zephyr_config_prepare(): dma channel index %d already configured", dd->chan->index); return 0; } channel = dai_config_dma_channel(dd, dev, dd->dai_spec_config); - comp_dbg(dev, "dai_config_prepare(), channel = %d", channel); + comp_dbg(dev, "dai_zephyr_config_prepare(), channel = %d", channel); /* do nothing for asking for channel free, for compatibility. */ if (channel == DMA_CHAN_INVALID) { @@ -907,7 +907,7 @@ static int dai_config_prepare(struct dai_data *dd, struct comp_dev *dev) /* get DMA channel */ channel = dma_request_channel(dd->dma->z_dev, &channel); if (channel < 0) { - comp_err(dev, "dai_config_prepare(): dma_request_channel() failed"); + comp_err(dev, "dai_zephyr_config_prepare(): dma_request_channel() failed"); dd->chan = NULL; return -EIO; } @@ -915,13 +915,13 @@ static int dai_config_prepare(struct dai_data *dd, struct comp_dev *dev) dd->chan = &dd->dma->chan[channel]; dd->chan->dev_data = dd; - comp_dbg(dev, "dai_config_prepare(): new configured dma channel index %d", + comp_dbg(dev, "dai_zephyr_config_prepare(): new configured dma channel index %d", dd->chan->index); return 0; } -static int dai_zephyr_prepare(struct dai_data *dd, struct comp_dev *dev) +int dai_zephyr_prepare(struct dai_data *dd, struct comp_dev *dev) { struct comp_buffer __sparse_cache *buffer_c; int ret; @@ -966,7 +966,7 @@ static int dai_prepare(struct comp_dev *dev) comp_dbg(dev, "dai_prepare()"); - ret = dai_config_prepare(dd, dev); + ret = dai_zephyr_config_prepare(dd, dev); if (ret < 0) return ret; diff --git a/src/include/sof/audio/dai_copier.h b/src/include/sof/audio/dai_copier.h index 5c50263d2641..e431d5ce753a 100644 --- a/src/include/sof/audio/dai_copier.h +++ b/src/include/sof/audio/dai_copier.h @@ -22,4 +22,7 @@ int dai_zephyr_new(struct dai_data *dd, struct comp_dev *dev, void dai_zephyr_free(struct dai_data *dd); +int dai_zephyr_config_prepare(struct dai_data *dd, struct comp_dev *dev); + +int dai_zephyr_prepare(struct dai_data *dd, struct comp_dev *dev); #endif /* __SOF_LIB_DAI_COPIER_H__ */ From ca2c3044154b31ccab2fd26500479c5986782e9f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 11:00:48 -0700 Subject: [PATCH 64/94] dai: Modify the signature of dai_dma_release() In preparation for it to be used with both the DAI device and the copier device, pass both the dai_data and the device pointer separately. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 2 +- src/audio/dai-zephyr.c | 2 +- src/include/sof/lib/dai-legacy.h | 2 +- src/include/sof/lib/dai-zephyr.h | 2 +- src/ipc/ipc3/dai.c | 6 ++---- src/ipc/ipc4/dai.c | 4 +--- 6 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 98c9c5c85101..4486057c767c 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -739,7 +739,7 @@ static int dai_reset(struct comp_dev *dev) * It will be done when the host sends the DAI_CONFIG IPC during hw_free. */ if (!dd->delayed_dma_stop) - dai_dma_release(dev); + dai_dma_release(dd, dev); dma_sg_free(&config->elem_array); diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 06af16e970ab..3c0abcccdbf8 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -992,7 +992,7 @@ static int dai_reset(struct comp_dev *dev) * option. It will be done when the host sends the DAI_CONFIG IPC during hw_free. */ if (!dd->delayed_dma_stop) - dai_dma_release(dev); + dai_dma_release(dd, dev); dma_sg_free(&config->elem_array); if (dd->z_config) { diff --git a/src/include/sof/lib/dai-legacy.h b/src/include/sof/lib/dai-legacy.h index 873d0cb78d85..918eff0b0b51 100644 --- a/src/include/sof/lib/dai-legacy.h +++ b/src/include/sof/lib/dai-legacy.h @@ -548,7 +548,7 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void /** * \brief Reset DAI DMA config */ -void dai_dma_release(struct comp_dev *dev); +void dai_dma_release(struct dai_data *dd, struct comp_dev *dev); /** * \brief Configure DAI physical interface. diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index b1651017a4c3..47f50be25be1 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -258,7 +258,7 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void /** * \brief Reset DAI DMA config */ -void dai_dma_release(struct comp_dev *dev); +void dai_dma_release(struct dai_data *dd, struct comp_dev *dev); /** * \brief Configure DAI physical interface. diff --git a/src/ipc/ipc3/dai.c b/src/ipc/ipc3/dai.c index fff4dba7df97..d6ab9e283637 100644 --- a/src/ipc/ipc3/dai.c +++ b/src/ipc/ipc3/dai.c @@ -262,10 +262,8 @@ int ipc_comp_dai_config(struct ipc *ipc, struct ipc_config_dai *common_config, return ret; } -void dai_dma_release(struct comp_dev *dev) +void dai_dma_release(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); - /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { comp_info(dev, "dai_config(): Component is in active state. Ignore resetting"); @@ -335,7 +333,7 @@ int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config, if (ret < 0) return ret; - dai_dma_release(dev); + dai_dma_release(dd, dev); } return 0; diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index e324d8425b09..5a650659fdc3 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -137,10 +137,8 @@ int ipc_comp_dai_config(struct ipc *ipc, struct ipc_config_dai *common_config, return 0; } -void dai_dma_release(struct comp_dev *dev) +void dai_dma_release(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); - /* cannot configure DAI while active */ if (dev->state == COMP_STATE_ACTIVE) { comp_info(dev, "dai_config(): Component is in active state. Ignore resetting"); From c1c402d33bf9dbf7543614542b726d3242ce9d50 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 11:02:29 -0700 Subject: [PATCH 65/94] dai-zephyr/dai-legacy: Split up dai_reset() And add a helper function, dai_zephyr_reset() that can also be used by the copier device in the next patch. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 15 +++++++++++---- src/audio/dai-zephyr.c | 15 +++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 4486057c767c..5dc19e8b33e7 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -727,13 +727,10 @@ static int dai_prepare(struct comp_dev *dev) return dai_zephyr_prepare(dd, dev); } -static int dai_reset(struct comp_dev *dev) +static void dai_zephyr_reset(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct dma_sg_config *config = &dd->config; - comp_info(dev, "dai_reset()"); - /* * DMA channel release should be skipped now for DAI's that support the two-step stop option. * It will be done when the host sends the DAI_CONFIG IPC during hw_free. @@ -751,6 +748,16 @@ static int dai_reset(struct comp_dev *dev) dd->wallclock = 0; dd->total_data_processed = 0; dd->xrun = 0; +} + +static int dai_reset(struct comp_dev *dev) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + comp_info(dev, "dai_reset()"); + + dai_zephyr_reset(dd, dev); + comp_set_state(dev, COMP_TRIGGER_RESET); return 0; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 3c0abcccdbf8..2ee88ef25b87 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -980,13 +980,10 @@ static int dai_prepare(struct comp_dev *dev) return dai_zephyr_prepare(dd, dev); } -static int dai_reset(struct comp_dev *dev) +static void dai_zephyr_reset(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct dma_sg_config *config = &dd->config; - comp_dbg(dev, "dai_reset()"); - /* * DMA channel release should be skipped now for DAI's that support the two-step stop * option. It will be done when the host sends the DAI_CONFIG IPC during hw_free. @@ -1009,6 +1006,16 @@ static int dai_reset(struct comp_dev *dev) dd->wallclock = 0; dd->total_data_processed = 0; dd->xrun = 0; +} + +static int dai_reset(struct comp_dev *dev) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + comp_dbg(dev, "dai_reset()"); + + dai_zephyr_reset(dd, dev); + comp_set_state(dev, COMP_TRIGGER_RESET); return 0; From aa432c37f850bb830293a697304e04a0d90fcd87 Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Mon, 13 Mar 2023 14:59:38 +0800 Subject: [PATCH 66/94] dai-zephyr/dai-legacy: Expose dai_zephyr_reset() Expose dai_zephyr_reset() and use in the copier device for the single endpoint case in preparation for removing the creation of DAI component. Signed-off-by: Baofeng Tian Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 36 +++++++++++++++++++++--------- src/audio/dai-legacy.c | 2 +- src/audio/dai-zephyr.c | 2 +- src/include/sof/audio/dai_copier.h | 2 ++ 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index ce705b5a5757..c2c3eecbcccb 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -1014,23 +1014,39 @@ static int copier_reset(struct comp_dev *dev) { struct copier_data *cd = comp_get_drvdata(dev); struct ipc4_pipeline_registers pipe_reg; - int ret = 0; - int i; + int i, ret = 0; comp_dbg(dev, "copier_reset()"); cd->input_total_data_processed = 0; cd->output_total_data_processed = 0; - if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) - host_zephyr_reset(cd->hd, dev->state); - - for (i = 0; i < cd->endpoint_num; i++) { - if (dev->ipc_config.type != SOF_COMP_HOST || cd->ipc_gtw) { - ret = cd->endpoint[i]->drv->ops.reset(cd->endpoint[i]); - if (ret < 0) - break; + switch (dev->ipc_config.type) { + case SOF_COMP_HOST: + if (!cd->ipc_gtw) { + host_zephyr_reset(cd->hd, dev->state); + } else { + for (i = 0; i < cd->endpoint_num; i++) { + ret = cd->endpoint[i]->drv->ops.reset(cd->endpoint[i]); + if (ret < 0) + break; + } } + break; + case SOF_COMP_DAI: + if (cd->endpoint_num == 1) { + dai_zephyr_reset(cd->dd[0], cd->endpoint[0]); + comp_set_state(cd->endpoint[0], COMP_TRIGGER_RESET); + } else { + for (i = 0; i < cd->endpoint_num; i++) { + ret = cd->endpoint[i]->drv->ops.reset(cd->endpoint[i]); + if (ret < 0) + break; + } + } + break; + default: + break; } if (cd->pipeline_reg_offset) { diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 5dc19e8b33e7..d4998141a8a2 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -727,7 +727,7 @@ static int dai_prepare(struct comp_dev *dev) return dai_zephyr_prepare(dd, dev); } -static void dai_zephyr_reset(struct dai_data *dd, struct comp_dev *dev) +void dai_zephyr_reset(struct dai_data *dd, struct comp_dev *dev) { struct dma_sg_config *config = &dd->config; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 2ee88ef25b87..ae6ad16fb86f 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -980,7 +980,7 @@ static int dai_prepare(struct comp_dev *dev) return dai_zephyr_prepare(dd, dev); } -static void dai_zephyr_reset(struct dai_data *dd, struct comp_dev *dev) +void dai_zephyr_reset(struct dai_data *dd, struct comp_dev *dev) { struct dma_sg_config *config = &dd->config; diff --git a/src/include/sof/audio/dai_copier.h b/src/include/sof/audio/dai_copier.h index e431d5ce753a..efeb5f3af5e5 100644 --- a/src/include/sof/audio/dai_copier.h +++ b/src/include/sof/audio/dai_copier.h @@ -25,4 +25,6 @@ void dai_zephyr_free(struct dai_data *dd); int dai_zephyr_config_prepare(struct dai_data *dd, struct comp_dev *dev); int dai_zephyr_prepare(struct dai_data *dd, struct comp_dev *dev); + +void dai_zephyr_reset(struct dai_data *dd, struct comp_dev *dev); #endif /* __SOF_LIB_DAI_COPIER_H__ */ From ac4e37636094e0106000ab9ddab91c6e99e45165 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 11:11:19 -0700 Subject: [PATCH 67/94] dai-zephyr/dai-legacy: Split up dai_comp_trigger() Add a new helper function dai_zephyr_trigger() that can also be used by a copier device. Also, modify the signature of the dai_comp_trigger_internal() to pass the dai_data and device pointer. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 39 ++++++++++++++++++--------------------- src/audio/dai-zephyr.c | 39 ++++++++++++++++++--------------------- 2 files changed, 36 insertions(+), 42 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index d4998141a8a2..d720f07b74bb 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -47,7 +47,7 @@ DECLARE_TR_CTX(dai_comp_tr, SOF_UUID(dai_comp_uuid), LOG_LEVEL_INFO); #if CONFIG_COMP_DAI_GROUP -static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd); +static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, int cmd); static void dai_atomic_trigger(void *arg, enum notify_id type, void *data) { @@ -56,7 +56,7 @@ static void dai_atomic_trigger(void *arg, enum notify_id type, void *data) struct dai_group *group = dd->group; /* Atomic context set by the last DAI to receive trigger command */ - group->trigger_ret = dai_comp_trigger_internal(dev, group->trigger_cmd); + group->trigger_ret = dai_comp_trigger_internal(dd, dev, group->trigger_cmd); } /* Assign DAI to a group */ @@ -763,18 +763,9 @@ static int dai_reset(struct comp_dev *dev) return 0; } -static void dai_update_start_position(struct comp_dev *dev) -{ - struct dai_data *dd = comp_get_drvdata(dev); - - /* update starting wallclock */ - platform_dai_wallclock(dev, &dd->wallclock); -} - /* used to pass standard and bespoke command (with data) to component */ -static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd) +static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, int cmd) { - struct dai_data *dd = comp_get_drvdata(dev); int ret; comp_dbg(dev, "dai_comp_trigger_internal(), command = %u", cmd); @@ -801,7 +792,7 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd) dd->xrun = 0; } - dai_update_start_position(dev); + platform_dai_wallclock(dev, &dd->wallclock); break; case COMP_TRIGGER_RELEASE: /* before release, we clear the buffer data to 0s, @@ -832,7 +823,7 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd) dd->xrun = 0; } - dai_update_start_position(dev); + platform_dai_wallclock(dev, &dd->wallclock); break; case COMP_TRIGGER_XRUN: comp_info(dev, "dai_comp_trigger_internal(), XRUN"); @@ -875,17 +866,16 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd) return ret; } -static int dai_comp_trigger(struct comp_dev *dev, int cmd) +static int dai_zephyr_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd) { - struct dai_data *dd = comp_get_drvdata(dev); struct dai_group *group = dd->group; uint32_t irq_flags; int ret = 0; /* DAI not in a group, use normal trigger */ if (!group) { - comp_dbg(dev, "dai_comp_trigger(), non-atomic trigger"); - return dai_comp_trigger_internal(dev, cmd); + comp_dbg(dev, "dai_zephyr_trigger(), non-atomic trigger"); + return dai_comp_trigger_internal(dd, dev, cmd); } /* DAI is grouped, so only trigger when the entire group is ready */ @@ -894,13 +884,13 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd) /* First DAI to receive the trigger command, * prepare for atomic trigger */ - comp_dbg(dev, "dai_comp_trigger(), begin atomic trigger for group %d", + comp_dbg(dev, "dai_zephyr_trigger(), begin atomic trigger for group %d", group->group_id); group->trigger_cmd = cmd; group->trigger_counter = group->num_dais - 1; } else if (group->trigger_cmd != cmd) { /* Already processing a different trigger command */ - comp_err(dev, "dai_comp_trigger(), already processing atomic trigger"); + comp_err(dev, "dai_zephyr_trigger(), already processing atomic trigger"); ret = -EAGAIN; } else { /* Count down the number of remaining DAIs required @@ -908,7 +898,7 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd) * takes place */ group->trigger_counter--; - comp_dbg(dev, "dai_comp_trigger(), trigger counter %d, group %d", + comp_dbg(dev, "dai_zephyr_trigger(), trigger counter %d, group %d", group->trigger_counter, group->group_id); if (!group->trigger_counter) { @@ -931,6 +921,13 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd) return ret; } +static int dai_comp_trigger(struct comp_dev *dev, int cmd) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + return dai_zephyr_trigger(dd, dev, cmd); +} + /* report xrun occurrence */ static void dai_report_xrun(struct comp_dev *dev, uint32_t bytes) { diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index ae6ad16fb86f..5fc3ff832069 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -52,7 +52,7 @@ DECLARE_TR_CTX(dai_comp_tr, SOF_UUID(dai_comp_uuid), LOG_LEVEL_INFO); #if CONFIG_COMP_DAI_GROUP -static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd); +static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, int cmd); static void dai_atomic_trigger(void *arg, enum notify_id type, void *data) { @@ -61,7 +61,7 @@ static void dai_atomic_trigger(void *arg, enum notify_id type, void *data) struct dai_group *group = dd->group; /* Atomic context set by the last DAI to receive trigger command */ - group->trigger_ret = dai_comp_trigger_internal(dev, group->trigger_cmd); + group->trigger_ret = dai_comp_trigger_internal(dd, dev, group->trigger_cmd); } /* Assign DAI to a group */ @@ -1021,18 +1021,9 @@ static int dai_reset(struct comp_dev *dev) return 0; } -static void dai_update_start_position(struct comp_dev *dev) -{ - struct dai_data *dd = comp_get_drvdata(dev); - - /* update starting wallclock */ - platform_dai_wallclock(dev, &dd->wallclock); -} - /* used to pass standard and bespoke command (with data) to component */ -static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd) +static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, int cmd) { - struct dai_data *dd = comp_get_drvdata(dev); int prev_state = dev->state; int ret; @@ -1061,7 +1052,7 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd) dd->xrun = 0; } - dai_update_start_position(dev); + platform_dai_wallclock(dev, &dd->wallclock); break; case COMP_TRIGGER_RELEASE: /* before release, we clear the buffer data to 0s, @@ -1100,7 +1091,7 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd) dd->xrun = 0; } - dai_update_start_position(dev); + platform_dai_wallclock(dev, &dd->wallclock); break; case COMP_TRIGGER_XRUN: comp_info(dev, "dai_comp_trigger_internal(), XRUN"); @@ -1162,17 +1153,16 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd) return ret; } -static int dai_comp_trigger(struct comp_dev *dev, int cmd) +static int dai_zephyr_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd) { - struct dai_data *dd = comp_get_drvdata(dev); struct dai_group *group = dd->group; uint32_t irq_flags; int ret = 0; /* DAI not in a group, use normal trigger */ if (!group) { - comp_dbg(dev, "dai_comp_trigger(), non-atomic trigger"); - return dai_comp_trigger_internal(dev, cmd); + comp_dbg(dev, "dai_zephyr_trigger(), non-atomic trigger"); + return dai_comp_trigger_internal(dd, dev, cmd); } /* DAI is grouped, so only trigger when the entire group is ready */ @@ -1181,13 +1171,13 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd) /* First DAI to receive the trigger command, * prepare for atomic trigger */ - comp_dbg(dev, "dai_comp_trigger(), begin atomic trigger for group %d", + comp_dbg(dev, "dai_zephyr_trigger(), begin atomic trigger for group %d", group->group_id); group->trigger_cmd = cmd; group->trigger_counter = group->num_dais - 1; } else if (group->trigger_cmd != cmd) { /* Already processing a different trigger command */ - comp_err(dev, "dai_comp_trigger(), already processing atomic trigger"); + comp_err(dev, "dai_zephyr_trigger(), already processing atomic trigger"); ret = -EAGAIN; } else { /* Count down the number of remaining DAIs required @@ -1195,7 +1185,7 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd) * takes place */ group->trigger_counter--; - comp_dbg(dev, "dai_comp_trigger(), trigger counter %d, group %d", + comp_dbg(dev, "dai_zephyr_trigger(), trigger counter %d, group %d", group->trigger_counter, group->group_id); if (!group->trigger_counter) { @@ -1218,6 +1208,13 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd) return ret; } +static int dai_comp_trigger(struct comp_dev *dev, int cmd) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + return dai_zephyr_trigger(dd, dev, cmd); +} + /* report xrun occurrence */ static void dai_report_xrun(struct comp_dev *dev, uint32_t bytes) { From a02bcb603cebf1a1910a058c9caad4d88635e704 Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Mon, 13 Mar 2023 21:45:17 +0800 Subject: [PATCH 68/94] dai-zephyr/dai-legacy: Expose dai_zephyr_trigger() Expose and use the function in the single endpoint DAI case in the copier device in preparation to remove the creation of DAI component. Signed-off-by: Baofeng Tian Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 42 +++++++++++++++++++++--------- src/audio/dai-legacy.c | 2 +- src/audio/dai-zephyr.c | 2 +- src/include/sof/audio/dai_copier.h | 2 ++ 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index c2c3eecbcccb..20cce305a515 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -1080,23 +1080,41 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) if (ret == COMP_STATUS_STATE_ALREADY_SET) return PPL_STATUS_PATH_STOP; - if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) { - ret = host_zephyr_trigger(cd->hd, dev, cmd); - if (ret < 0) - return ret; - } - - for (i = 0; i < cd->endpoint_num; i++) { - if (dev->ipc_config.type != SOF_COMP_HOST || cd->ipc_gtw) { - ret = cd->endpoint[i]->drv->ops.trigger(cd->endpoint[i], cmd); + switch (dev->ipc_config.type) { + case SOF_COMP_HOST: + if (!cd->ipc_gtw) { + ret = host_zephyr_trigger(cd->hd, dev, cmd); + if (ret < 0) + return ret; + } else { + /* handle gtw case */ + for (i = 0; i < cd->endpoint_num; i++) { + ret = cd->endpoint[i]->drv->ops.trigger(cd->endpoint[i], cmd); + if (ret < 0) + return ret; + } + } + break; + case SOF_COMP_DAI: + if (cd->endpoint_num == 1) { + ret = dai_zephyr_trigger(cd->dd[0], cd->endpoint[0], cmd); if (ret < 0) - break; + return ret; + } else { + for (i = 0; i < cd->endpoint_num; i++) { + ret = cd->endpoint[i]->drv->ops.trigger(cd->endpoint[i], cmd); + if (ret < 0) + return ret; + } } + break; + default: + break; } /* For capture cd->pipeline_reg_offset == 0 */ - if (ret < 0 || !cd->endpoint_num || !cd->pipeline_reg_offset) - return ret; + if (!cd->endpoint_num || !cd->pipeline_reg_offset) + return 0; dai_copier = pipeline_get_dai_comp_latency(dev->pipeline->pipeline_id, &latency); if (!dai_copier) { diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index d720f07b74bb..f396507851f7 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -866,7 +866,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, return ret; } -static int dai_zephyr_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd) +int dai_zephyr_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd) { struct dai_group *group = dd->group; uint32_t irq_flags; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 5fc3ff832069..193f60445ff3 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -1153,7 +1153,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, return ret; } -static int dai_zephyr_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd) +int dai_zephyr_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd) { struct dai_group *group = dd->group; uint32_t irq_flags; diff --git a/src/include/sof/audio/dai_copier.h b/src/include/sof/audio/dai_copier.h index efeb5f3af5e5..6221640d090f 100644 --- a/src/include/sof/audio/dai_copier.h +++ b/src/include/sof/audio/dai_copier.h @@ -27,4 +27,6 @@ int dai_zephyr_config_prepare(struct dai_data *dd, struct comp_dev *dev); int dai_zephyr_prepare(struct dai_data *dd, struct comp_dev *dev); void dai_zephyr_reset(struct dai_data *dd, struct comp_dev *dev); + +int dai_zephyr_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd); #endif /* __SOF_LIB_DAI_COPIER_H__ */ From 07f96b4a30180af568db78aae68859b56e0f0053 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 11:24:55 -0700 Subject: [PATCH 69/94] copier: Modify get_processed_data() Modify the get_processed_data() function to use the total_processed_data from the dai_data directly for DAI components. Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 20cce305a515..49560eeee0f4 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -1852,6 +1852,7 @@ static uint64_t copier_get_processed_data(struct comp_dev *dev, uint32_t stream_ { struct copier_data *cd = comp_get_drvdata(dev); uint64_t ret = 0; + bool source; /* * total data processed is calculated as: accumulate all input data in bytes @@ -1864,14 +1865,28 @@ static uint64_t copier_get_processed_data(struct comp_dev *dev, uint32_t stream_ */ if (cd->endpoint_num) { if (stream_no < cd->endpoint_num) { - if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) { - bool source = dev->direction == SOF_IPC_STREAM_PLAYBACK; - - if (source == input) + switch (dev->ipc_config.type) { + case SOF_COMP_HOST: + source = dev->direction == SOF_IPC_STREAM_PLAYBACK; + if (cd->ipc_gtw) { + struct comp_dev *host_dev; + + host_dev = cd->endpoint[stream_no]; + ret = comp_get_total_data_processed(host_dev, + 0, input); + } else if (source == input) { ret = cd->hd->total_data_processed; - } else { + } + break; + case SOF_COMP_DAI: + source = dev->direction == SOF_IPC_STREAM_CAPTURE; + if (source == input) + ret = cd->dd[0]->total_data_processed; + break; + default: ret = comp_get_total_data_processed(cd->endpoint[stream_no], 0, input); + break; } } } else { From 6432249d37a9e439ddd0231418aac338200681e4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 11:36:53 -0700 Subject: [PATCH 70/94] ipc4: dai: Split up dai_position() And add a new helper, dai_zephyr_position() that can also be used by the copier device. Signed-off-by: Ranjani Sridharan --- src/ipc/ipc4/dai.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index 5a650659fdc3..1f8f6594420c 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -346,9 +346,9 @@ int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config, } #if CONFIG_ZEPHYR_NATIVE_DRIVERS -int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) +static int dai_zephyr_position(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_posn *posn) { - struct dai_data *dd = comp_get_drvdata(dev); struct dma_status status; int ret; @@ -367,6 +367,13 @@ int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) return 0; } +int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + return dai_zephyr_position(dd, dev, posn); +} + void dai_dma_position_update(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); @@ -392,9 +399,9 @@ void dai_dma_position_update(struct comp_dev *dev) mailbox_sw_regs_write(dd->slot_info.reg_offset, &slot, sizeof(slot)); } #else -int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) +static int dai_zephyr_position(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_posn *posn) { - struct dai_data *dd = comp_get_drvdata(dev); struct dma_chan_status status; /* total processed bytes count */ @@ -409,6 +416,13 @@ int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) return 0; } +int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + return dai_zephyr_position(dd, dev, posn); +} + void dai_dma_position_update(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); From ac529fc1b306e67aed5138859d256d1ff9fc18d4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 11:41:53 -0700 Subject: [PATCH 71/94] ipc4: dai: Expose dai_zephyr_position() Expose and use the function in the copier. Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 22 ++++++++++++++++------ src/include/sof/audio/dai_copier.h | 3 +++ src/ipc/ipc4/dai.c | 9 +++++---- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 49560eeee0f4..a791ea4d2093 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -1919,17 +1919,27 @@ static int copier_get_attribute(struct comp_dev *dev, uint32_t type, void *value static int copier_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) { struct copier_data *cd = comp_get_drvdata(dev); - int ret; + int ret = 0; /* Exit if no endpoints */ if (!cd->endpoint_num) return -EINVAL; - if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) { - posn->host_posn = cd->hd->local_pos; - ret = posn->host_posn; - } else { - ret = comp_position(cd->endpoint[IPC4_COPIER_GATEWAY_PIN], posn); + switch (dev->ipc_config.type) { + case SOF_COMP_HOST: + if (!cd->ipc_gtw) { + posn->host_posn = cd->hd->local_pos; + ret = posn->host_posn; + } else { + /* handle gtw case */ + ret = comp_position(cd->endpoint[IPC4_COPIER_GATEWAY_PIN], posn); + } + break; + case SOF_COMP_DAI: + ret = dai_zephyr_position(cd->dd[0], cd->endpoint[IPC4_COPIER_GATEWAY_PIN], posn); + break; + default: + break; } /* Return position from the default gateway pin */ return ret; diff --git a/src/include/sof/audio/dai_copier.h b/src/include/sof/audio/dai_copier.h index 6221640d090f..1011569de013 100644 --- a/src/include/sof/audio/dai_copier.h +++ b/src/include/sof/audio/dai_copier.h @@ -29,4 +29,7 @@ int dai_zephyr_prepare(struct dai_data *dd, struct comp_dev *dev); void dai_zephyr_reset(struct dai_data *dd, struct comp_dev *dev); int dai_zephyr_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd); + +int dai_zephyr_position(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_posn *posn); #endif /* __SOF_LIB_DAI_COPIER_H__ */ diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index 1f8f6594420c..126e6fa350f4 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -346,8 +347,8 @@ int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config, } #if CONFIG_ZEPHYR_NATIVE_DRIVERS -static int dai_zephyr_position(struct dai_data *dd, struct comp_dev *dev, - struct sof_ipc_stream_posn *posn) +int dai_zephyr_position(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_posn *posn) { struct dma_status status; int ret; @@ -399,8 +400,8 @@ void dai_dma_position_update(struct comp_dev *dev) mailbox_sw_regs_write(dd->slot_info.reg_offset, &slot, sizeof(slot)); } #else -static int dai_zephyr_position(struct dai_data *dd, struct comp_dev *dev, - struct sof_ipc_stream_posn *posn) +int dai_zephyr_position(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_posn *posn) { struct dma_chan_status status; From 70de2508cb30f459bd133453e3ceb6ea794adfed Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 11:52:19 -0700 Subject: [PATCH 72/94] dai: Modify the signature of ipc_dai_data_config() To pass both the dai_data and dev pointer and make it usable for both the DAI device and the copier device. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 2 +- src/audio/dai-zephyr.c | 2 +- src/include/sof/ipc/common.h | 3 ++- src/ipc/ipc3/dai.c | 3 +-- src/ipc/ipc4/dai.c | 3 +-- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index f396507851f7..a954e8763ba1 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -497,7 +497,7 @@ static int dai_params(struct comp_dev *dev, comp_dbg(dev, "dai_params()"); /* configure dai_data first */ - err = ipc_dai_data_config(dev); + err = ipc_dai_data_config(dd, dev); if (err < 0) return err; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 193f60445ff3..1d745d0380fa 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -762,7 +762,7 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params comp_dbg(dev, "dai_params()"); /* configure dai_data first */ - err = ipc_dai_data_config(dev); + err = ipc_dai_data_config(dd, dev); if (err < 0) return err; diff --git a/src/include/sof/ipc/common.h b/src/include/sof/ipc/common.h index 360e8417f4a6..8e659c5b4ae6 100644 --- a/src/include/sof/ipc/common.h +++ b/src/include/sof/ipc/common.h @@ -141,11 +141,12 @@ int ipc_dma_trace_send_position(void); */ void ipc_send_buffer_status_notify(void); +struct dai_data; /** * \brief Configure DAI. * @return 0 on success. */ -int ipc_dai_data_config(struct comp_dev *dev); +int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev); /** * \brief create a IPC boot complete message. diff --git a/src/ipc/ipc3/dai.c b/src/ipc/ipc3/dai.c index d6ab9e283637..07a598b51c0d 100644 --- a/src/ipc/ipc3/dai.c +++ b/src/ipc/ipc3/dai.c @@ -94,9 +94,8 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void return channel; } -int ipc_dai_data_config(struct comp_dev *dev) +int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct ipc_config_dai *dai = &dd->ipc_config; struct sof_ipc_dai_config *config = ipc_from_dai_config(dd->dai_spec_config); struct comp_buffer __sparse_cache *buffer_c; diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index 126e6fa350f4..9672df0d4358 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -62,9 +62,8 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void return channel; } -int ipc_dai_data_config(struct comp_dev *dev) +int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct ipc_config_dai *dai = &dd->ipc_config; struct ipc4_copier_module_cfg *copier_cfg = dd->dai_spec_config; struct dai *dai_p = dd->dai; From e543a7c1d8b5c0d27fbb4f6e417b0a8c96e6478c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 11:57:38 -0700 Subject: [PATCH 73/94] dai-zephyr/dai-legacy: Split up dai_params() Add a new helper, dai_zephyr_params() to make it usable from the copier device. Also modify the signatures of dai_playback_params() and dai_capture_params() to use the passed dai_data and dev pointer. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 14 ++++++++++--- src/audio/dai-zephyr.c | 45 +++++++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index a954e8763ba1..93b9b319f5b1 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -480,11 +480,10 @@ static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, return err; } -static int dai_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) +static int dai_zephyr_params(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_params *params) { struct sof_ipc_stream_params hw_params = *params; - struct dai_data *dd = comp_get_drvdata(dev); struct comp_buffer __sparse_cache *buffer_c; uint32_t frame_size; uint32_t period_count; @@ -618,6 +617,15 @@ static int dai_params(struct comp_dev *dev, dai_capture_params(dev, period_bytes, period_count); } +static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + comp_dbg(dev, "dai_params()"); + + return dai_zephyr_params(dd, dev, params); +} + int dai_zephyr_config_prepare(struct dai_data *dd, struct comp_dev *dev) { int channel = 0; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 1d745d0380fa..3270207a0ce9 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -453,10 +453,9 @@ static int dai_verify_params(struct comp_dev *dev, struct sof_ipc_stream_params } /* set component audio SSP and DMA configuration */ -static int dai_playback_params(struct comp_dev *dev, uint32_t period_bytes, - uint32_t period_count) +static int dai_playback_params(struct dai_data *dd, struct comp_dev *dev, uint32_t period_bytes, + int32_t period_count) { - struct dai_data *dd = comp_get_drvdata(dev); struct dma_sg_config *config = &dd->config; struct dma_config *dma_cfg; struct dma_block_config *dma_block_cfg; @@ -591,10 +590,9 @@ static int dai_playback_params(struct comp_dev *dev, uint32_t period_bytes, return err; } -static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, +static int dai_capture_params(struct dai_data *dd, struct comp_dev *dev, uint32_t period_bytes, uint32_t period_count) { - struct dai_data *dd = comp_get_drvdata(dev); struct dma_sg_config *config = &dd->config; struct dma_config *dma_cfg; struct dma_block_config *dma_block_cfg; @@ -746,10 +744,10 @@ static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, return err; } -static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) +static int dai_zephyr_params(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_params *params) { struct sof_ipc_stream_params hw_params = *params; - struct dai_data *dd = comp_get_drvdata(dev); struct comp_buffer __sparse_cache *buffer_c; uint32_t frame_size; uint32_t period_count; @@ -759,8 +757,6 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params uint32_t align; int err; - comp_dbg(dev, "dai_params()"); - /* configure dai_data first */ err = ipc_dai_data_config(dd, dev); if (err < 0) @@ -768,7 +764,7 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params err = dai_verify_params(dev, params); if (err < 0) { - comp_err(dev, "dai_params(): pcm params verification failed."); + comp_err(dev, "dai_zephyr_params(): pcm params verification failed."); return -EINVAL; } @@ -783,13 +779,13 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params /* check if already configured */ if (dev->state == COMP_STATE_PREPARE) { - comp_info(dev, "dai_params() component has been already configured."); + comp_info(dev, "dai_zephyr_params() component has been already configured."); return 0; } /* can set params on only init state */ if (dev->state != COMP_STATE_READY) { - comp_err(dev, "dai_params(): Component is in state %d, expected COMP_STATE_READY.", + comp_err(dev, "dai_zephyr_params(): Component is in state %d, expected COMP_STATE_READY.", dev->state); return -EINVAL; } @@ -797,21 +793,21 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params err = dma_get_attribute(dd->dma->z_dev, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, &addr_align); if (err < 0) { - comp_err(dev, "dai_params(): could not get dma buffer address alignment, err = %d", + comp_err(dev, "dai_zephyr_params(): could not get dma buffer address alignment, err = %d", err); return err; } err = dma_get_attribute(dd->dma->z_dev, DMA_ATTR_BUFFER_SIZE_ALIGNMENT, &align); if (err < 0 || !align) { - comp_err(dev, "dai_params(): no valid dma buffer alignment, err = %d, align = %u", + comp_err(dev, "dai_zephyr_params(): no valid dma buffer alignment, err = %d, align = %u", err, align); return -EINVAL; } period_count = dd->dma->plat_data.period_count; if (!period_count) { - comp_err(dev, "dai_params(): no valid dma buffer period count"); + comp_err(dev, "dai_zephyr_params(): no valid dma buffer period count"); return -EINVAL; } @@ -826,7 +822,7 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params /* calculate period size */ period_bytes = dev->frames * frame_size; if (!period_bytes) { - comp_err(dev, "dai_params(): invalid period_bytes."); + comp_err(dev, "dai_zephyr_params(): invalid period_bytes."); return -EINVAL; } @@ -844,7 +840,7 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params buffer_release(buffer_c); if (err < 0) { - comp_err(dev, "dai_params(): buffer_set_size() failed, buffer_size = %u", + comp_err(dev, "dai_zephyr_params(): buffer_set_size() failed, buffer_size = %u", buffer_size); return err; } @@ -852,7 +848,7 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params dd->dma_buffer = buffer_alloc(buffer_size, SOF_MEM_CAPS_DMA, addr_align); if (!dd->dma_buffer) { - comp_err(dev, "dai_params(): failed to alloc dma buffer"); + comp_err(dev, "dai_zephyr_params(): failed to alloc dma buffer"); return -ENOMEM; } @@ -870,8 +866,17 @@ static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params } return dev->direction == SOF_IPC_STREAM_PLAYBACK ? - dai_playback_params(dev, period_bytes, period_count) : - dai_capture_params(dev, period_bytes, period_count); + dai_playback_params(dd, dev, period_bytes, period_count) : + dai_capture_params(dd, dev, period_bytes, period_count); +} + +static int dai_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + comp_dbg(dev, "dai_params()"); + + return dai_zephyr_params(dd, dev, params); } int dai_zephyr_config_prepare(struct dai_data *dd, struct comp_dev *dev) From 6271953ff36a5011f55dce143fb4fcf9b92445f7 Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Wed, 22 Mar 2023 13:47:44 +0800 Subject: [PATCH 74/94] dai-zephyr: Expose dai_zephyr_params() Expose and use it in the single endpoint DAI case in the copier device in preparation to remove the creation of dai component. Signed-off-by: Baofeng Tian Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 51 ++++++++++++++++++++---------- src/audio/dai-legacy.c | 4 +-- src/audio/dai-zephyr.c | 4 +-- src/include/sof/audio/dai_copier.h | 3 ++ 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index a791ea4d2093..b0311b144dbb 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -1557,8 +1557,7 @@ static int copier_params(struct comp_dev *dev, struct sof_ipc_stream_params *par struct comp_buffer *sink, *source; struct comp_buffer __sparse_cache *sink_c, *source_c; struct list_item *sink_list; - int ret = 0; - int i; + int i, ret = 0; comp_dbg(dev, "copier_params()"); @@ -1624,21 +1623,41 @@ static int copier_params(struct comp_dev *dev, struct sof_ipc_stream_params *par ret = cd->endpoint[i]->drv->ops.params(cd->endpoint[i], &demuxed_params); } else { - if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) { - component_set_nearest_period_frames(dev, params->rate); - if (params->direction == SOF_IPC_STREAM_CAPTURE) { - params->buffer.size = cd->config.base.obs; - params->sample_container_bytes = cd->out_fmt->depth / 8; - params->sample_valid_bytes = - cd->out_fmt->valid_bit_depth / 8; + switch (dev->ipc_config.type) { + case SOF_COMP_HOST: + if (!cd->ipc_gtw) { + component_set_nearest_period_frames(dev, params->rate); + if (params->direction == SOF_IPC_STREAM_CAPTURE) { + params->buffer.size = cd->config.base.obs; + params->sample_container_bytes = + cd->out_fmt->depth / 8; + params->sample_valid_bytes = + cd->out_fmt->valid_bit_depth / 8; + } + + ret = host_zephyr_params(cd->hd, dev, params, + copier_notifier_cb); + + cd->hd->process = cd->converter[IPC4_COPIER_GATEWAY_PIN]; + } else { + /* handle gtw case */ + ret = cd->endpoint[i]->drv->ops.params(cd->endpoint[i], + params); } - - ret = host_zephyr_params(cd->hd, dev, params, copier_notifier_cb); - - cd->hd->process = cd->converter[IPC4_COPIER_GATEWAY_PIN]; - } else { - ret = cd->endpoint[i]->drv->ops.params(cd->endpoint[i], - params); + break; + case SOF_COMP_DAI: + if (cd->endpoint_num == 1) { + ret = dai_zephyr_params(cd->dd[0], cd->endpoint[0], + params); + if (ret < 0) + return ret; + } else { + ret = cd->endpoint[i]->drv->ops.params(cd->endpoint[i], + params); + } + break; + default: + break; } } if (ret < 0) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 93b9b319f5b1..85773766a553 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -480,8 +480,8 @@ static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, return err; } -static int dai_zephyr_params(struct dai_data *dd, struct comp_dev *dev, - struct sof_ipc_stream_params *params) +int dai_zephyr_params(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_params *params) { struct sof_ipc_stream_params hw_params = *params; struct comp_buffer __sparse_cache *buffer_c; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 3270207a0ce9..8923972db3ac 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -744,8 +744,8 @@ static int dai_capture_params(struct dai_data *dd, struct comp_dev *dev, uint32_ return err; } -static int dai_zephyr_params(struct dai_data *dd, struct comp_dev *dev, - struct sof_ipc_stream_params *params) +int dai_zephyr_params(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_params *params) { struct sof_ipc_stream_params hw_params = *params; struct comp_buffer __sparse_cache *buffer_c; diff --git a/src/include/sof/audio/dai_copier.h b/src/include/sof/audio/dai_copier.h index 1011569de013..c78063496a6d 100644 --- a/src/include/sof/audio/dai_copier.h +++ b/src/include/sof/audio/dai_copier.h @@ -32,4 +32,7 @@ int dai_zephyr_trigger(struct dai_data *dd, struct comp_dev *dev, int cmd); int dai_zephyr_position(struct dai_data *dd, struct comp_dev *dev, struct sof_ipc_stream_posn *posn); + +int dai_zephyr_params(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_params *params); #endif /* __SOF_LIB_DAI_COPIER_H__ */ From 76fe3274711f149ec38e25debb337dc3726820c9 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 12:17:33 -0700 Subject: [PATCH 75/94] dai: Modify the signature of dai_dma_position_update() Pass both the dai_data and the dev pointers so that it can also be used from the copier device. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 2 +- src/audio/dai-zephyr.c | 2 +- src/include/sof/lib/dai-legacy.h | 2 +- src/include/sof/lib/dai-zephyr.h | 2 +- src/ipc/ipc3/dai.c | 2 +- src/ipc/ipc4/dai.c | 6 ++---- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 85773766a553..0a5ef44b3f04 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -1035,7 +1035,7 @@ static int dai_copy(struct comp_dev *dev) return ret; } - dai_dma_position_update(dev); + dai_dma_position_update(dd, dev); return ret; } diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 8923972db3ac..b93013bc434c 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -1342,7 +1342,7 @@ static int dai_copy(struct comp_dev *dev) return ret; } - dai_dma_position_update(dev); + dai_dma_position_update(dd, dev); return ret; } diff --git a/src/include/sof/lib/dai-legacy.h b/src/include/sof/lib/dai-legacy.h index 918eff0b0b51..c1d54c7b388f 100644 --- a/src/include/sof/lib/dai-legacy.h +++ b/src/include/sof/lib/dai-legacy.h @@ -569,7 +569,7 @@ int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn); /** * \brief update dai dma position for host driver. */ -void dai_dma_position_update(struct comp_dev *dev); +void dai_dma_position_update(struct dai_data *dd, struct comp_dev *dev); /** * \brief release llp slot diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index 47f50be25be1..2a4d097b9b87 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -278,7 +278,7 @@ int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn); /** * \brief update dai dma position for host driver. */ -void dai_dma_position_update(struct comp_dev *dev); +void dai_dma_position_update(struct dai_data *dd, struct comp_dev *dev); /** * \brief release llp slot diff --git a/src/ipc/ipc3/dai.c b/src/ipc/ipc3/dai.c index 07a598b51c0d..546acdd8d060 100644 --- a/src/ipc/ipc3/dai.c +++ b/src/ipc/ipc3/dai.c @@ -392,6 +392,6 @@ int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) return 0; } -void dai_dma_position_update(struct comp_dev *dev) { } +void dai_dma_position_update(struct dai_data *dd, struct comp_dev *dev) { } void dai_release_llp_slot(struct dai_data *dd) { } diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index 9672df0d4358..1d5b69c3732d 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -374,9 +374,8 @@ int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) return dai_zephyr_position(dd, dev, posn); } -void dai_dma_position_update(struct comp_dev *dev) +void dai_dma_position_update(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct ipc4_llp_reading_slot slot; struct dma_status status; int ret; @@ -423,9 +422,8 @@ int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) return dai_zephyr_position(dd, dev, posn); } -void dai_dma_position_update(struct comp_dev *dev) +void dai_dma_position_update(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct ipc4_llp_reading_slot slot; struct dma_chan_status status; uint32_t llp_data[2]; From 9a37e8b2c951f7b761c6640774901bc6db657b03 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 12:18:29 -0700 Subject: [PATCH 76/94] dai-zephyr/dai-legacy: Split up dai_copy() Add a helper function, dai_zephyr_copy() that can also be called from a copier device. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 22 ++++++++++++++-------- src/audio/dai-zephyr.c | 40 +++++++++++++++++++++------------------- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 0a5ef44b3f04..7c91b1bcf96d 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -954,9 +954,8 @@ static void dai_report_xrun(struct comp_dev *dev, uint32_t bytes) } /* copy and process stream data from source to sink buffers */ -static int dai_copy(struct comp_dev *dev) +static int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); uint32_t dma_fmt; uint32_t sampling; struct comp_buffer __sparse_cache *buf_c; @@ -968,8 +967,6 @@ static int dai_copy(struct comp_dev *dev) uint32_t samples; int ret; - comp_dbg(dev, "dai_copy()"); - /* get data sizes from DMA */ ret = dma_get_data_size_legacy(dd->chan, &avail_bytes, &free_bytes); if (ret < 0) { @@ -1004,7 +1001,7 @@ static int dai_copy(struct comp_dev *dev) copy_bytes = samples * sampling; - comp_dbg(dev, "dai_copy(), dir: %d copy_bytes= 0x%x, frames= %d", + comp_dbg(dev, "dai_zephyr_copy(), dir: %d copy_bytes= 0x%x, frames= %d", dev->direction, copy_bytes, samples / buf_c->stream.channels); @@ -1013,16 +1010,16 @@ static int dai_copy(struct comp_dev *dev) /* Check possibility of glitch occurrence */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK && copy_bytes + avail_bytes < dd->period_bytes) - comp_warn(dev, "dai_copy(): Copy_bytes %d + avail bytes %d < period bytes %d, possible glitch", + comp_warn(dev, "dai_zephyr_copy(): Copy_bytes %d + avail bytes %d < period bytes %d, possible glitch", copy_bytes, avail_bytes, dd->period_bytes); else if (dev->direction == SOF_IPC_STREAM_CAPTURE && copy_bytes + free_bytes < dd->period_bytes) - comp_warn(dev, "dai_copy(): Copy_bytes %d + free bytes %d < period bytes %d, possible glitch", + comp_warn(dev, "dai_zephyr_copy(): Copy_bytes %d + free bytes %d < period bytes %d, possible glitch", copy_bytes, free_bytes, dd->period_bytes); /* return if nothing to copy */ if (!copy_bytes) { - comp_warn(dev, "dai_copy(): nothing to copy"); + comp_warn(dev, "dai_zephyr_copy(): nothing to copy"); return 0; } @@ -1040,6 +1037,15 @@ static int dai_copy(struct comp_dev *dev) return ret; } +static int dai_copy(struct comp_dev *dev) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + comp_dbg(dev, "dai_copy()"); + + return dai_zephyr_copy(dd, dev); +} + /** * \brief Get DAI parameters and configure timestamping * \param[in, out] dev DAI device. diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index b93013bc434c..53aafa1af63e 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -220,9 +220,8 @@ static int dai_get_fifo(struct dai *dai, int direction, int stream_id) } /* this is called by DMA driver every time descriptor has completed */ -static enum dma_cb_status dai_dma_cb(struct comp_dev *dev, uint32_t bytes) +static enum dma_cb_status dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes) { - struct dai_data *dd = comp_get_drvdata(dev); struct comp_buffer __sparse_cache *local_buf, *dma_buf; enum dma_cb_status dma_status = DMA_CB_STATUS_RELOAD; int ret; @@ -1221,9 +1220,8 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd) } /* report xrun occurrence */ -static void dai_report_xrun(struct comp_dev *dev, uint32_t bytes) +static void dai_report_xrun(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes) { - struct dai_data *dd = comp_get_drvdata(dev); struct comp_buffer __sparse_cache *buf_c = buffer_acquire(dd->local_buffer); if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { @@ -1238,9 +1236,8 @@ static void dai_report_xrun(struct comp_dev *dev, uint32_t bytes) } /* copy and process stream data from source to sink buffers */ -static int dai_copy(struct comp_dev *dev) +static int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); uint32_t dma_fmt; uint32_t sampling; struct comp_buffer __sparse_cache *buf_c; @@ -1253,8 +1250,6 @@ static int dai_copy(struct comp_dev *dev) uint32_t samples; int ret; - comp_dbg(dev, "dai_copy()"); - /* get data sizes from DMA */ ret = dma_get_status(dd->chan->dma->z_dev, dd->chan->index, &stat); switch (ret) { @@ -1263,11 +1258,11 @@ static int dai_copy(struct comp_dev *dev) case -EPIPE: /* DMA status can return -EPIPE and current status content if xrun occurs */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) - comp_dbg(dev, "dai_copy(): dma_get_status() underrun occurred, ret = %u", - ret); + comp_dbg(dev, "dai_zephyr_copy(): dma_get_status() underrun occurred, ret = %u", + ret); else - comp_dbg(dev, "dai_copy(): dma_get_status() overrun occurred, ret = %u", - ret); + comp_dbg(dev, "dai_zephyr_copy(): dma_get_status() overrun occurred, ret = %u", + ret); break; default: return ret; @@ -1305,7 +1300,7 @@ static int dai_copy(struct comp_dev *dev) copy_bytes = samples * sampling; - comp_dbg(dev, "dai_copy(), dir: %d copy_bytes= 0x%x, frames= %d", + comp_dbg(dev, "dai_zephyr_copy(), dir: %d copy_bytes= 0x%x, frames= %d", dev->direction, copy_bytes, samples / buf_c->stream.channels); @@ -1314,16 +1309,16 @@ static int dai_copy(struct comp_dev *dev) /* Check possibility of glitch occurrence */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK && copy_bytes + avail_bytes < dd->period_bytes) - comp_warn(dev, "dai_copy(): Copy_bytes %d + avail bytes %d < period bytes %d, possible glitch", + comp_warn(dev, "dai_zephyr_copy(): Copy_bytes %d + avail bytes %d < period bytes %d, possible glitch", copy_bytes, avail_bytes, dd->period_bytes); else if (dev->direction == SOF_IPC_STREAM_CAPTURE && copy_bytes + free_bytes < dd->period_bytes) - comp_warn(dev, "dai_copy(): Copy_bytes %d + free bytes %d < period bytes %d, possible glitch", + comp_warn(dev, "dai_zephyr_copy(): Copy_bytes %d + free bytes %d < period bytes %d, possible glitch", copy_bytes, free_bytes, dd->period_bytes); /* return if nothing to copy */ if (!copy_bytes) { - comp_warn(dev, "dai_copy(): nothing to copy"); + comp_warn(dev, "dai_zephyr_copy(): nothing to copy"); dma_reload(dd->chan->dma->z_dev, dd->chan->index, 0, 0, 0); return 0; } @@ -1331,14 +1326,14 @@ static int dai_copy(struct comp_dev *dev) /* trigger optional DAI_TRIGGER_COPY which prepares dai to copy */ ret = dai_trigger(dd->dai->dev, dev->direction, DAI_TRIGGER_COPY); if (ret < 0) - comp_warn(dev, "dai_copy(): dai trigger copy failed"); + comp_warn(dev, "dai_zephyr_copy(): dai trigger copy failed"); - if (dai_dma_cb(dev, copy_bytes) == DMA_CB_STATUS_END) + if (dai_dma_cb(dd, dev, copy_bytes) == DMA_CB_STATUS_END) dma_stop(dd->chan->dma->z_dev, dd->chan->index); ret = dma_reload(dd->chan->dma->z_dev, dd->chan->index, 0, 0, copy_bytes); if (ret < 0) { - dai_report_xrun(dev, copy_bytes); + dai_report_xrun(dd, dev, copy_bytes); return ret; } @@ -1347,6 +1342,13 @@ static int dai_copy(struct comp_dev *dev) return ret; } +static int dai_copy(struct comp_dev *dev) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + return dai_zephyr_copy(dd, dev); +} + /** * \brief Get DAI parameters and configure timestamping * \param[in, out] dev DAI device. From ba5f8fe2c3d6949ea65ff3042ef2c7eeeef14a2d Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Sun, 30 Apr 2023 13:24:28 -0700 Subject: [PATCH 77/94] dai-zephyr: Expose dai_zephyr_copy() Expose and use the function for the single endpoint DAI coper case in preparation to remove the creation of the DAI device. Signed-off-by: Baofeng Tian Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 15 ++++++++++++--- src/audio/dai-legacy.c | 2 +- src/audio/dai-zephyr.c | 2 +- src/include/sof/audio/dai_copier.h | 2 ++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index b0311b144dbb..863637da3513 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -1340,9 +1340,18 @@ static int do_endpoint_copy(struct comp_dev *dev) return ret; } else { - if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) - return host_zephyr_copy(cd->hd, dev, copier_dma_cb); - + switch (dev->ipc_config.type) { + case SOF_COMP_HOST: + if (!cd->ipc_gtw) + return host_zephyr_copy(cd->hd, dev, copier_dma_cb); + break; + case SOF_COMP_DAI: + if (cd->endpoint_num == 1) + return dai_zephyr_copy(cd->dd[0], cd->endpoint[0]); + break; + default: + break; + } return cd->endpoint[0]->drv->ops.copy(cd->endpoint[0]); } } diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 7c91b1bcf96d..fe87b983003d 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -954,7 +954,7 @@ static void dai_report_xrun(struct comp_dev *dev, uint32_t bytes) } /* copy and process stream data from source to sink buffers */ -static int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) +int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) { uint32_t dma_fmt; uint32_t sampling; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 53aafa1af63e..7582ff47831e 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -1236,7 +1236,7 @@ static void dai_report_xrun(struct dai_data *dd, struct comp_dev *dev, uint32_t } /* copy and process stream data from source to sink buffers */ -static int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) +int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) { uint32_t dma_fmt; uint32_t sampling; diff --git a/src/include/sof/audio/dai_copier.h b/src/include/sof/audio/dai_copier.h index c78063496a6d..23ec22f727e7 100644 --- a/src/include/sof/audio/dai_copier.h +++ b/src/include/sof/audio/dai_copier.h @@ -35,4 +35,6 @@ int dai_zephyr_position(struct dai_data *dd, struct comp_dev *dev, int dai_zephyr_params(struct dai_data *dd, struct comp_dev *dev, struct sof_ipc_stream_params *params); + +int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev); #endif /* __SOF_LIB_DAI_COPIER_H__ */ From d4140c9662f53f59769746bfcf548eef18c9961b Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Wed, 29 Mar 2023 21:12:01 +0800 Subject: [PATCH 78/94] dai-zephyr: Modify the signature of comp_dai_config() op In order to also use this function from the copier device without an endpoint DAI device, modify the signature to ass both the dai_data and the dev pointers. Also, modify the signatures of dai_assign_group() and dai_init_llp_info() to use the passed pointers. Signed-off-by: Baofeng Tian Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 4 ++-- src/audio/dai-legacy.c | 4 +--- src/audio/dai-zephyr.c | 4 +--- src/include/sof/audio/component.h | 4 ++-- src/include/sof/audio/component_ext.h | 15 +++++++++++++-- src/include/sof/lib/dai-legacy.h | 4 ++-- src/include/sof/lib/dai-zephyr.h | 5 +++-- src/ipc/ipc3/dai.c | 5 ++--- src/ipc/ipc4/dai.c | 10 ++++------ 9 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 863637da3513..9e458a770bce 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -366,7 +366,8 @@ static int init_dai(struct comp_dev *parent_dev, list_init(&dev->bsource_list); list_init(&dev->bsink_list); - ret = comp_dai_config(dev, dai, copier); + cd->dd[index] = comp_get_drvdata(dev); + ret = comp_dai_config(cd->dd[index], dev, dai, copier); if (ret < 0) goto free_dev; @@ -391,7 +392,6 @@ static int init_dai(struct comp_dev *parent_dev, } cd->endpoint[cd->endpoint_num++] = dev; - cd->dd[index] = comp_get_drvdata(dev); return 0; free_dev: diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index fe87b983003d..52ee11d112b4 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -60,10 +60,8 @@ static void dai_atomic_trigger(void *arg, enum notify_id type, void *data) } /* Assign DAI to a group */ -int dai_assign_group(struct comp_dev *dev, uint32_t group_id) +int dai_assign_group(struct dai_data *dd, struct comp_dev *dev, uint32_t group_id) { - struct dai_data *dd = comp_get_drvdata(dev); - if (dd->group) { if (dd->group->group_id != group_id) { comp_err(dev, "dai_assign_group(), DAI already in group %d, requested %d", diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 7582ff47831e..38fce878046f 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -65,10 +65,8 @@ static void dai_atomic_trigger(void *arg, enum notify_id type, void *data) } /* Assign DAI to a group */ -int dai_assign_group(struct comp_dev *dev, uint32_t group_id) +int dai_assign_group(struct dai_data *dd, struct comp_dev *dev, uint32_t group_id) { - struct dai_data *dd = comp_get_drvdata(dev); - if (dd->group) { if (dd->group->group_id != group_id) { comp_err(dev, "dai_assign_group(), DAI already in group %d, requested %d", diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 5a06857b188e..96ec168f28e9 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -347,8 +347,8 @@ struct comp_ops { * * Mandatory for components that allocate DAI. */ - int (*dai_config)(struct comp_dev *dev, struct ipc_config_dai *dai_config, - const void *dai_spec_config); + int (*dai_config)(struct dai_data *dd, struct comp_dev *dev, + struct ipc_config_dai *dai_config, const void *dai_spec_config); /** * Used to pass standard and bespoke commands (with optional data). diff --git a/src/include/sof/audio/component_ext.h b/src/include/sof/audio/component_ext.h index 339b479b3ff2..40ac3d129074 100644 --- a/src/include/sof/audio/component_ext.h +++ b/src/include/sof/audio/component_ext.h @@ -252,16 +252,27 @@ static inline int comp_reset(struct comp_dev *dev) return 0; } +#if CONFIG_IPC_MAJOR_3 /** See comp_ops::dai_config */ static inline int comp_dai_config(struct comp_dev *dev, struct ipc_config_dai *config, const void *spec_config) { + struct dai_data *dd = comp_get_drvdata(dev); + if (dev->drv->ops.dai_config) - return dev->drv->ops.dai_config(dev, config, spec_config); + return dev->drv->ops.dai_config(dd, dev, config, spec_config); return 0; } - +#elif CONFIG_IPC_MAJOR_4 +static inline int comp_dai_config(struct dai_data *dd, struct comp_dev *dev, + struct ipc_config_dai *config, const void *spec_config) +{ + return dai_config(dd, dev, config, spec_config); +} +#else +#error Unknown IPC major version +#endif /** See comp_ops::position */ static inline int comp_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) diff --git a/src/include/sof/lib/dai-legacy.h b/src/include/sof/lib/dai-legacy.h index c1d54c7b388f..b72e176d10ac 100644 --- a/src/include/sof/lib/dai-legacy.h +++ b/src/include/sof/lib/dai-legacy.h @@ -553,13 +553,13 @@ void dai_dma_release(struct dai_data *dd, struct comp_dev *dev); /** * \brief Configure DAI physical interface. */ -int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config, +int dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai *common_config, const void *spec_config); /** * \brief Assign DAI to a group for simultaneous triggering. */ -int dai_assign_group(struct comp_dev *dev, uint32_t group_id); +int dai_assign_group(struct dai_data *dd, struct comp_dev *dev, uint32_t group_id); /** * \brief dai position for host driver. diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index 2a4d097b9b87..639fdce5849f 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -263,12 +263,13 @@ void dai_dma_release(struct dai_data *dd, struct comp_dev *dev); /** * \brief Configure DAI physical interface. */ -int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_cfg, const void *spec_cfg); +int dai_config(struct dai_data *dd, struct comp_dev *dev, + struct ipc_config_dai *common_cfg, const void *spec_cfg); /** * \brief Assign DAI to a group for simultaneous triggering. */ -int dai_assign_group(struct comp_dev *dev, uint32_t group_id); +int dai_assign_group(struct dai_data *dd, struct comp_dev *dev, uint32_t group_id); /** * \brief dai position for host driver. diff --git a/src/ipc/ipc3/dai.c b/src/ipc/ipc3/dai.c index 546acdd8d060..a33e9ad680f0 100644 --- a/src/ipc/ipc3/dai.c +++ b/src/ipc/ipc3/dai.c @@ -283,11 +283,10 @@ void dai_dma_release(struct dai_data *dd, struct comp_dev *dev) } } -int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config, +int dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai *common_config, const void *spec_config) { const struct sof_ipc_dai_config *config = spec_config; - struct dai_data *dd = comp_get_drvdata(dev); int ret; /* ignore if message not for this DAI id/type */ @@ -349,7 +348,7 @@ int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config, } #if CONFIG_COMP_DAI_GROUP if (config->group_id) { - ret = dai_assign_group(dev, config->group_id); + ret = dai_assign_group(dd, dev, config->group_id); if (ret) return ret; diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index 1d5b69c3732d..20ac83b81c5c 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -249,9 +249,8 @@ static int dai_get_unused_llp_slot(struct comp_dev *dev, return offset; } -static int dai_init_llp_info(struct comp_dev *dev) +static int dai_init_llp_info(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct ipc4_copier_module_cfg *copier_cfg; union ipc4_connector_node_id node; int ret; @@ -279,11 +278,10 @@ static int dai_init_llp_info(struct comp_dev *dev) return 0; } -int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config, +int dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai *common_config, const void *spec_config) { const struct ipc4_copier_module_cfg *copier_cfg = spec_config; - struct dai_data *dd = comp_get_drvdata(dev); int size; int ret; @@ -309,7 +307,7 @@ int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config, #if CONFIG_COMP_DAI_GROUP if (common_config->group_id) { - ret = dai_assign_group(dev, common_config->group_id); + ret = dai_assign_group(dd, dev, common_config->group_id); if (ret) return ret; @@ -338,7 +336,7 @@ int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config, } } - ret = dai_init_llp_info(dev); + ret = dai_init_llp_info(dd, dev); if (ret < 0) return ret; From b5cdac0ecb090d43a93a9ff701fff9b6762e6a77 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 May 2023 19:50:59 -0700 Subject: [PATCH 79/94] dai-legacy/dai-zephyr: Split the timestamping ops In preparation to remove the DAI device creation, add the timestamping ops for the DAI copier and expose the timestaming functions in dai-zephyr and dai-legacy. Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 46 ++++++++++++++++++++++++++++++ src/audio/dai-legacy.c | 40 ++++++++++++++++++++------ src/audio/dai-zephyr.c | 46 ++++++++++++++++++++---------- src/include/sof/audio/dai_copier.h | 8 ++++++ 4 files changed, 117 insertions(+), 23 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 9e458a770bce..7a42af187387 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -38,6 +38,10 @@ #include #include +#if CONFIG_ZEPHYR_NATIVE_DRIVERS +#include +#endif + static const struct comp_driver comp_copier; LOG_MODULE_REGISTER(copier, CONFIG_SOF_LOG_LEVEL); @@ -1973,6 +1977,44 @@ static int copier_position(struct comp_dev *dev, struct sof_ipc_stream_posn *pos return ret; } +static int copier_dai_ts_config_op(struct comp_dev *dev) +{ + struct copier_data *cd = comp_get_drvdata(dev); + struct dai_data *dd = cd->dd[0]; + + return dai_zephyr_ts_config_op(dd, dev); +} + +static int copier_dai_ts_start_op(struct comp_dev *dev) +{ + struct copier_data *cd = comp_get_drvdata(dev); + struct dai_data *dd = cd->dd[0]; + + comp_dbg(dev, "dai_ts_start()"); + + return dai_zephyr_ts_start(dd, dev); +} + +static int copier_dai_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd) +{ + struct copier_data *cd = comp_get_drvdata(dev); + struct dai_data *dd = cd->dd[0]; + + comp_dbg(dev, "dai_ts_get()"); + + return dai_zephyr_ts_get(dd, dev, tsd); +} + +static int copier_dai_ts_stop_op(struct comp_dev *dev) +{ + struct copier_data *cd = comp_get_drvdata(dev); + struct dai_data *dd = cd->dd[0]; + + comp_dbg(dev, "dai_ts_stop()"); + + return dai_zephyr_ts_stop(dd, dev); +} + static const struct comp_driver comp_copier = { .uid = SOF_RT_UUID(copier_comp_uuid), .tctx = &copier_comp_tr, @@ -1989,6 +2031,10 @@ static const struct comp_driver comp_copier = { .get_total_data_processed = copier_get_processed_data, .get_attribute = copier_get_attribute, .position = copier_position, + .dai_ts_config = copier_dai_ts_config_op, + .dai_ts_start = copier_dai_ts_start_op, + .dai_ts_stop = copier_dai_ts_stop_op, + .dai_ts_get = copier_dai_ts_get_op, }, }; diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 52ee11d112b4..3d111b6d2f46 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -1054,9 +1054,8 @@ static int dai_copy(struct comp_dev *dev) * DAI must be prepared before this function is used (for DMA information). If not, an error * is returned. */ -static int dai_ts_config(struct comp_dev *dev) +int dai_zephyr_ts_config_op(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct timestamp_cfg *cfg = &dd->ts_config; struct ipc_config_dai *dai = &dd->ipc_config; @@ -1078,39 +1077,64 @@ static int dai_ts_config(struct comp_dev *dev) return dd->dai->drv->ts_ops.ts_config(dd->dai, cfg); } -static int dai_ts_start(struct comp_dev *dev) +static int dai_ts_config(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); - comp_dbg(dev, "dai_ts_start()"); + return dai_zephyr_ts_config_op(dd, dev); +} + +int dai_zephyr_ts_start(struct dai_data *dd, struct comp_dev *dev) +{ if (!dd->dai->drv->ts_ops.ts_start) return -ENXIO; return dd->dai->drv->ts_ops.ts_start(dd->dai, &dd->ts_config); } -static int dai_ts_stop(struct comp_dev *dev) +static int dai_ts_start(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); - comp_dbg(dev, "dai_ts_stop()"); + comp_dbg(dev, "dai_ts_start()"); + + return dai_zephyr_ts_start(dd, dev); +} + +int dai_zephyr_ts_stop(struct dai_data *dd, struct comp_dev *dev) +{ if (!dd->dai->drv->ts_ops.ts_stop) return -ENXIO; return dd->dai->drv->ts_ops.ts_stop(dd->dai, &dd->ts_config); } -static int dai_ts_get(struct comp_dev *dev, struct timestamp_data *tsd) +static int dai_ts_stop(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); - comp_dbg(dev, "dai_ts_get()"); + comp_dbg(dev, "dai_ts_stop()"); + + return dai_zephyr_ts_stop(dd, dev); +} + +int dai_zephyr_ts_get(struct dai_data *dd, struct comp_dev *dev, struct timestamp_data *tsd) +{ if (!dd->dai->drv->ts_ops.ts_get) return -ENXIO; return dd->dai->drv->ts_ops.ts_get(dd->dai, &dd->ts_config, tsd); } +static int dai_ts_get(struct comp_dev *dev, struct timestamp_data *tsd) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + comp_dbg(dev, "dai_ts_get()"); + + return dai_zephyr_ts_get(dd, dev, tsd); +} + static uint64_t dai_get_processed_data(struct comp_dev *dev, uint32_t stream_no, bool input) { struct dai_data *dd = comp_get_drvdata(dev); diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 38fce878046f..19f7fb19e10f 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -1357,9 +1357,8 @@ static int dai_copy(struct comp_dev *dev) * DAI must be prepared before this function is used (for DMA information). If not, an error * is returned. */ -static int dai_ts_config_op(struct comp_dev *dev) +int dai_zephyr_ts_config_op(struct dai_data *dd, struct comp_dev *dev) { - struct dai_data *dd = comp_get_drvdata(dev); struct ipc_config_dai *dai = &dd->ipc_config; struct dai_ts_cfg cfg; @@ -1393,43 +1392,60 @@ static int dai_ts_config_op(struct comp_dev *dev) return dai_ts_config(dd->dai->dev, &cfg); } -static int dai_ts_start_op(struct comp_dev *dev) +static int dai_ts_config_op(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); - struct dai_ts_cfg cfg; - comp_dbg(dev, "dai_ts_start()"); + return dai_zephyr_ts_config_op(dd, dev); +} + +int dai_zephyr_ts_start(struct dai_data *dd, struct comp_dev *dev) +{ + struct dai_ts_cfg cfg; return dai_ts_start(dd->dai->dev, &cfg); } -static int dai_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd) +static int dai_ts_start_op(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); + + comp_dbg(dev, "dai_ts_start()"); + return dai_zephyr_ts_start(dd, dev); +} + +int dai_zephyr_ts_get(struct dai_data *dd, struct comp_dev *dev, struct timestamp_data *tsd) +{ struct dai_ts_data tsdata; struct dai_ts_cfg cfg; - int ret; - comp_dbg(dev, "dai_ts_get()"); + /* TODO: convert to timestamp_data */ + return dai_ts_get(dd->dai->dev, &cfg, &tsdata); +} - ret = dai_ts_get(dd->dai->dev, &cfg, &tsdata); +static int dai_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd) +{ + struct dai_data *dd = comp_get_drvdata(dev); - if (ret < 0) - return ret; + comp_dbg(dev, "dai_ts_get()"); - /* todo convert to timestamp_data */ + return dai_zephyr_ts_get(dd, dev, tsd); +} - return ret; +int dai_zephyr_ts_stop(struct dai_data *dd, struct comp_dev *dev) +{ + struct dai_ts_cfg cfg; + + return dai_ts_stop(dd->dai->dev, &cfg); } static int dai_ts_stop_op(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); - struct dai_ts_cfg cfg; comp_dbg(dev, "dai_ts_stop()"); - return dai_ts_stop(dd->dai->dev, &cfg); + return dai_zephyr_ts_stop(dd, dev); } uint32_t dai_get_init_delay_ms(struct dai *dai) diff --git a/src/include/sof/audio/dai_copier.h b/src/include/sof/audio/dai_copier.h index 23ec22f727e7..00f1b3b824c6 100644 --- a/src/include/sof/audio/dai_copier.h +++ b/src/include/sof/audio/dai_copier.h @@ -37,4 +37,12 @@ int dai_zephyr_params(struct dai_data *dd, struct comp_dev *dev, struct sof_ipc_stream_params *params); int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev); + +int dai_zephyr_ts_config_op(struct dai_data *dd, struct comp_dev *dev); + +int dai_zephyr_ts_start(struct dai_data *dd, struct comp_dev *dev); + +int dai_zephyr_ts_stop(struct dai_data *dd, struct comp_dev *dev); + +int dai_zephyr_ts_get(struct dai_data *dd, struct comp_dev *dev, struct timestamp_data *tsd); #endif /* __SOF_LIB_DAI_COPIER_H__ */ From 171ab5c98e54dec15b7e3fb724149bd8802cd46b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 May 2023 19:59:01 -0700 Subject: [PATCH 80/94] copier: Add dai_get_hw_params op In preparation to remove the DAI device creation for DAI copiers, add the dai_get_hw_params op and expose dai_zephyr_get_hw_params() for both dai-zephyr and dai-legacy. Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 13 +++++++++++++ src/audio/dai-legacy.c | 16 +++++++++++----- src/audio/dai-zephyr.c | 17 ++++++++++++----- src/include/sof/audio/dai_copier.h | 3 +++ 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 7a42af187387..07fd8279c76e 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -2015,6 +2015,18 @@ static int copier_dai_ts_stop_op(struct comp_dev *dev) return dai_zephyr_ts_stop(dd, dev); } +static int copier_get_hw_params(struct comp_dev *dev, struct sof_ipc_stream_params *params, + int dir) +{ + struct copier_data *cd = comp_get_drvdata(dev); + struct dai_data *dd = cd->dd[0]; + + if (dev->ipc_config.type != SOF_COMP_DAI) + return -EINVAL; + + return dai_zephyr_get_hw_params(dd, dev, params, dir); +} + static const struct comp_driver comp_copier = { .uid = SOF_RT_UUID(copier_comp_uuid), .tctx = &copier_comp_tr, @@ -2035,6 +2047,7 @@ static const struct comp_driver comp_copier = { .dai_ts_start = copier_dai_ts_start_op, .dai_ts_stop = copier_dai_ts_stop_op, .dai_ts_get = copier_dai_ts_get_op, + .dai_get_hw_params = copier_get_hw_params, }, }; diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 3d111b6d2f46..e8ef4a00c0a7 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -264,12 +264,10 @@ static void dai_free(struct comp_dev *dev) rfree(dev); } -static int dai_comp_get_hw_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params, - int dir) +int dai_zephyr_get_hw_params(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_params *params, int dir) { - struct dai_data *dd = comp_get_drvdata(dev); - int ret = 0; + int ret; comp_dbg(dev, "dai_hw_params()"); @@ -292,6 +290,14 @@ static int dai_comp_get_hw_params(struct comp_dev *dev, return 0; } +static int dai_comp_get_hw_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params, int dir) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + return dai_zephyr_get_hw_params(dd, dev, params, dir); +} + static int dai_comp_hw_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) { diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 19f7fb19e10f..b984751cc4f9 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -385,15 +385,13 @@ static void dai_free(struct comp_dev *dev) rfree(dev); } -static int dai_comp_get_hw_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params, - int dir) +int dai_zephyr_get_hw_params(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_params *params, int dir) { - struct dai_data *dd = comp_get_drvdata(dev); struct dai_config cfg; int ret; - comp_dbg(dev, "dai_hw_params()"); + comp_dbg(dev, "dai_zephyr_get_hw_params()"); ret = dai_config_get(dd->dai->dev, &cfg, dir); if (ret) @@ -414,6 +412,15 @@ static int dai_comp_get_hw_params(struct comp_dev *dev, return ret; } +static int dai_comp_get_hw_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params, + int dir) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + return dai_zephyr_get_hw_params(dd, dev, params, dir); +} + static int dai_verify_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) { struct sof_ipc_stream_params hw_params; diff --git a/src/include/sof/audio/dai_copier.h b/src/include/sof/audio/dai_copier.h index 00f1b3b824c6..48107d36d035 100644 --- a/src/include/sof/audio/dai_copier.h +++ b/src/include/sof/audio/dai_copier.h @@ -45,4 +45,7 @@ int dai_zephyr_ts_start(struct dai_data *dd, struct comp_dev *dev); int dai_zephyr_ts_stop(struct dai_data *dd, struct comp_dev *dev); int dai_zephyr_ts_get(struct dai_data *dd, struct comp_dev *dev, struct timestamp_data *tsd); + +int dai_zephyr_get_hw_params(struct dai_data *dd, struct comp_dev *dev, + struct sof_ipc_stream_params *params, int dir); #endif /* __SOF_LIB_DAI_COPIER_H__ */ From f43f9390ad8e7a760836993270984516f3ef856c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 12:36:54 -0700 Subject: [PATCH 81/94] component-ext: Remove comp_get_dai() The dai_data can simply be accessed via the copier_data. There is no copier with chain DMA anymore, so no need to special handle that case in pipeline_comp_trigger() either. Signed-off-by: Ranjani Sridharan --- src/audio/pipeline/pipeline-stream.c | 22 ++++++++++++---------- src/include/sof/audio/component_ext.h | 20 -------------------- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index 0a29ab8601d7..3203d53df675 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -429,16 +430,17 @@ static int pipeline_comp_trigger(struct comp_dev *current, * Initialization delay is only used with SSP, where we * don't use more than one DAI per copier */ - struct comp_dev *dai = comp_get_dai(current, 0); - - if (dai) { - struct dai_data *dd = comp_get_drvdata(dai); - - ppl_data->delay_ms = dai_get_init_delay_ms(dd->dai); - } else { - /* Chain DMA case */ - ppl_data->delay_ms = 0; - } + struct dai_data *dd; +#if CONFIG_IPC_MAJOR_3 + dd = comp_get_drvdata(current); +#elif CONFIG_IPC_MAJOR_4 + struct copier_data *cd = comp_get_drvdata(current); + + dd = cd->dd[0]; +#else +#error Unknown IPC major version +#endif + ppl_data->delay_ms = dai_get_init_delay_ms(dd->dai); } break; default: diff --git a/src/include/sof/audio/component_ext.h b/src/include/sof/audio/component_ext.h index 40ac3d129074..efa8e1b7767b 100644 --- a/src/include/sof/audio/component_ext.h +++ b/src/include/sof/audio/component_ext.h @@ -362,26 +362,6 @@ static inline int comp_get_endpoint_type(struct comp_dev *dev) } } -#if CONFIG_IPC_MAJOR_4 -#include -static inline struct comp_dev *comp_get_dai(struct comp_dev *parent, int index) -{ - struct copier_data *cd = comp_get_drvdata(parent); - - if (index >= ARRAY_SIZE(cd->endpoint)) - return NULL; - - return cd->endpoint[index]; -} -#elif CONFIG_IPC_MAJOR_3 -static inline struct comp_dev *comp_get_dai(struct comp_dev *parent, int index) -{ - return parent; -} -#else -#error Unknown IPC major version -#endif - /** * Called to check whether component schedules its pipeline. * @param dev Component device. From ed9257c9f6c6c9fdf136fdeb0f77eae182e51996 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 12:39:59 -0700 Subject: [PATCH 82/94] dai-zephyr/dai-legacy: Use comp_dai_get_hw_params() So that the correct op will be invoked when this function is invoked with a copier device. Signed-off-by: Ranjani Sridharan --- src/audio/dai-legacy.c | 2 +- src/audio/dai-zephyr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index e8ef4a00c0a7..6cc3fc55bb55 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -322,7 +322,7 @@ static int dai_verify_params(struct comp_dev *dev, { struct sof_ipc_stream_params hw_params; - dai_comp_get_hw_params(dev, &hw_params, params->direction); + comp_dai_get_hw_params(dev, &hw_params, params->direction); /* checks whether pcm parameters match hardware DAI parameter set * during dai_set_config(). If hardware parameter is equal to 0, it diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index b984751cc4f9..73337eba4c23 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -426,7 +426,7 @@ static int dai_verify_params(struct comp_dev *dev, struct sof_ipc_stream_params struct sof_ipc_stream_params hw_params; int ret; - ret = dai_comp_get_hw_params(dev, &hw_params, params->direction); + ret = comp_dai_get_hw_params(dev, &hw_params, params->direction); if (ret < 0) { comp_err(dev, "dai_verify_params(): dai_verify_params failed ret %d", ret); return ret; From 5bb718d7896b3872b7d4262e855794c315ad89f9 Mon Sep 17 00:00:00 2001 From: Baofeng Tian Date: Fri, 31 Mar 2023 11:41:08 +0800 Subject: [PATCH 83/94] copier: remove endpoint DAI device creation for single endpoint DAIs Remove the creation or the endpoint DAI device when a copier have only a single endpoint. Replace the usage of the endpoint device with the copier device and remove the endpoint buffer. Amend the copier_params() to pass the appropriate params for the DMA buffer and set the correct processing function in the case where the valid bits and the container size do not match. Signed-off-by: Baofeng Tian Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 229 ++++++++++++++++++++++++++------------ 1 file changed, 156 insertions(+), 73 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 07fd8279c76e..01586b0706c9 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -297,39 +297,77 @@ static enum sof_ipc_stream_direction } } -static struct comp_dev *init_dai_single(struct comp_dev *parent_dev, - const struct comp_driver *drv, - struct comp_ipc_config *config, - struct ipc_config_dai *dai) +static int init_dai_single(struct comp_dev *parent_dev, + const struct comp_driver *drv, + struct comp_ipc_config *config, + const struct ipc4_copier_module_cfg *copier, + struct pipeline *pipeline, + struct ipc_config_dai *dai, + enum ipc4_gateway_type type) { - struct comp_dev *dev; + struct copier_data *cd; struct dai_data *dd; int ret; - dev = comp_alloc(drv, sizeof(*dev)); - if (!dev) - return NULL; + cd = comp_get_drvdata(parent_dev); - dev->ipc_config = *config; + if (cd->direction == SOF_IPC_STREAM_PLAYBACK) { + enum sof_ipc_frame out_frame_fmt, out_valid_fmt; + + audio_stream_fmt_conversion(copier->out_fmt.depth, + copier->out_fmt.valid_bit_depth, + &out_frame_fmt, + &out_valid_fmt, + copier->out_fmt.s_type); + config->frame_fmt = out_frame_fmt; + pipeline->sink_comp = parent_dev; + } else { + enum sof_ipc_frame in_frame_fmt, in_valid_fmt; + + audio_stream_fmt_conversion(copier->base.audio_fmt.depth, + copier->base.audio_fmt.valid_bit_depth, + &in_frame_fmt, &in_valid_fmt, + copier->base.audio_fmt.s_type); + config->frame_fmt = in_frame_fmt; + pipeline->source_comp = parent_dev; + } + + parent_dev->ipc_config.frame_fmt = config->frame_fmt; dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); if (!dd) - goto free_dev; - - comp_set_drvdata(dev, dd); + return -ENOMEM; ret = dai_zephyr_new(dd, parent_dev, dai); if (ret < 0) - goto free_dd; + goto e_dd; - dev->state = COMP_STATE_READY; + pipeline->sched_id = config->id; - return dev; -free_dd: + ret = comp_dai_config(dd, parent_dev, dai, copier); + if (ret < 0) + goto e_zephyr; + + cd->converter[IPC4_COPIER_GATEWAY_PIN] = + get_converter_func(&copier->base.audio_fmt, &copier->out_fmt, type, + IPC4_DIRECTION(dai->direction)); + if (!cd->converter[IPC4_COPIER_GATEWAY_PIN]) { + comp_err(parent_dev, "failed to get converter type %d, dir %d", + type, dai->direction); + ret = -EINVAL; + goto e_zephyr; + } + + cd->endpoint_num++; + cd->dd[0] = dd; + + return 0; + +e_zephyr: + dai_zephyr_free(dd); +e_dd: rfree(dd); -free_dev: - rfree(dev); - return NULL; + return ret; } static int init_dai(struct comp_dev *parent_dev, @@ -345,16 +383,15 @@ static int init_dai(struct comp_dev *parent_dev, struct copier_data *cd; int ret; + if (dai_count == 1) + return init_dai_single(parent_dev, drv, config, copier, pipeline, dai, type); + cd = comp_get_drvdata(parent_dev); ret = create_endpoint_buffer(parent_dev, cd, config, copier, type, false, index); if (ret < 0) return ret; - if (dai_count == 1) - dev = init_dai_single(parent_dev, drv, config, dai); - else - dev = drv->ops.create(drv, config, dai); - + dev = drv->ops.create(drv, config, dai); if (!dev) { ret = -ENOMEM; goto e_buf; @@ -774,8 +811,6 @@ static void copier_free(struct comp_dev *dev) if (cd->endpoint_num == 1) { dai_zephyr_free(cd->dd[0]); rfree(cd->dd[0]); - rfree(cd->endpoint[0]); - buffer_free(cd->endpoint_buffer[0]); } else { for (i = 0; i < cd->endpoint_num; i++) { cd->endpoint[i]->drv->ops.free(cd->endpoint[i]); @@ -925,6 +960,12 @@ static int copier_prepare(struct comp_dev *dev) return 0; } + if (dev->ipc_config.type == SOF_COMP_DAI && cd->endpoint_num == 1) { + ret = dai_zephyr_config_prepare(cd->dd[0], dev); + if (ret < 0) + return ret; + } + ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); if (ret < 0) return ret; @@ -949,18 +990,7 @@ static int copier_prepare(struct comp_dev *dev) break; case SOF_COMP_DAI: if (cd->endpoint_num == 1) { - ret = dai_zephyr_config_prepare(cd->dd[0], cd->endpoint[0]); - if (ret < 0) - return ret; - - ret = comp_set_state(cd->endpoint[0], COMP_TRIGGER_PREPARE); - if (ret < 0) - return ret; - - if (ret == COMP_STATUS_STATE_ALREADY_SET) - return PPL_STATUS_PATH_STOP; - - ret = dai_zephyr_prepare(cd->dd[0], cd->endpoint[0]); + ret = dai_zephyr_prepare(cd->dd[0], dev); if (ret < 0) return ret; } else { @@ -1039,8 +1069,7 @@ static int copier_reset(struct comp_dev *dev) break; case SOF_COMP_DAI: if (cd->endpoint_num == 1) { - dai_zephyr_reset(cd->dd[0], cd->endpoint[0]); - comp_set_state(cd->endpoint[0], COMP_TRIGGER_RESET); + dai_zephyr_reset(cd->dd[0], dev); } else { for (i = 0; i < cd->endpoint_num; i++) { ret = cd->endpoint[i]->drv->ops.reset(cd->endpoint[i]); @@ -1069,7 +1098,6 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) struct copier_data *cd = comp_get_drvdata(dev); struct sof_ipc_stream_posn posn; struct comp_dev *dai_copier; - struct copier_data *dai_cd; struct comp_buffer *buffer; struct comp_buffer __sparse_cache *buffer_c; uint32_t latency; @@ -1077,12 +1105,18 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) comp_dbg(dev, "copier_comp_trigger()"); - ret = comp_set_state(dev, cmd); - if (ret < 0) - return ret; + /* + * do not modify the comp state in case of single endpoint DAI, it will be done in + * dai_zephyr_trigger() + */ + if (!(dev->ipc_config.type == SOF_COMP_DAI && cd->endpoint_num == 1)) { + ret = comp_set_state(dev, cmd); + if (ret < 0) + return ret; - if (ret == COMP_STATUS_STATE_ALREADY_SET) - return PPL_STATUS_PATH_STOP; + if (ret == COMP_STATUS_STATE_ALREADY_SET) + return PPL_STATUS_PATH_STOP; + } switch (dev->ipc_config.type) { case SOF_COMP_HOST: @@ -1101,7 +1135,7 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) break; case SOF_COMP_DAI: if (cd->endpoint_num == 1) { - ret = dai_zephyr_trigger(cd->dd[0], cd->endpoint[0], cmd); + ret = dai_zephyr_trigger(cd->dd[0], dev, cmd); if (ret < 0) return ret; } else { @@ -1131,10 +1165,8 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) return 0; } - dai_cd = comp_get_drvdata(dai_copier); /* dai is in another pipeline and it is not prepared or active */ - if (dai_copier->state <= COMP_STATE_READY || - dai_cd->endpoint[IPC4_COPIER_GATEWAY_PIN]->state <= COMP_STATE_READY) { + if (dai_copier->state <= COMP_STATE_READY) { struct ipc4_pipeline_registers pipe_reg; comp_warn(dev, "dai is not ready"); @@ -1351,7 +1383,7 @@ static int do_endpoint_copy(struct comp_dev *dev) break; case SOF_COMP_DAI: if (cd->endpoint_num == 1) - return dai_zephyr_copy(cd->dd[0], cd->endpoint[0]); + return dai_zephyr_copy(cd->dd[0], dev); break; default: break; @@ -1417,8 +1449,18 @@ static int copier_copy(struct comp_dev *dev) comp_dbg(dev, "copier_copy()"); - if (dev->ipc_config.type == SOF_COMP_HOST && !cd->ipc_gtw) - return do_endpoint_copy(dev); + switch (dev->ipc_config.type) { + case SOF_COMP_HOST: + if (!cd->ipc_gtw) + return do_endpoint_copy(dev); + break; + case SOF_COMP_DAI: + if (cd->endpoint_num == 1) + return do_endpoint_copy(dev); + break; + default: + break; + } processed_data.source_bytes = 0; @@ -1567,9 +1609,12 @@ static void copier_notifier_cb(void *arg, enum notify_id type, void *data) static int copier_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) { struct copier_data *cd = comp_get_drvdata(dev); + const struct ipc4_audio_format *in_fmt = &cd->config.base.audio_fmt; + const struct ipc4_audio_format *out_fmt = &cd->config.out_fmt; struct comp_buffer *sink, *source; struct comp_buffer __sparse_cache *sink_c, *source_c; struct list_item *sink_list; + enum sof_ipc_frame in_bits, in_valid_bits, out_bits, out_valid_bits; int i, ret = 0; comp_dbg(dev, "copier_params()"); @@ -1618,8 +1663,27 @@ static int copier_params(struct comp_dev *dev, struct sof_ipc_stream_params *par buffer_release(source_c); } + /* update params for the DMA buffer */ + switch (dev->ipc_config.type) { + case SOF_COMP_HOST: + if (cd->ipc_gtw || params->direction == SOF_IPC_STREAM_PLAYBACK) + break; + COMPILER_FALLTHROUGH; + case SOF_COMP_DAI: + if (dev->ipc_config.type == SOF_COMP_DAI && + (cd->endpoint_num > 1 || params->direction == SOF_IPC_STREAM_CAPTURE)) + break; + params->buffer.size = cd->config.base.obs; + params->sample_container_bytes = cd->out_fmt->depth / 8; + params->sample_valid_bytes = cd->out_fmt->valid_bit_depth / 8; + break; + default: + break; + } + for (i = 0; i < cd->endpoint_num; i++) { - update_internal_comp(dev, cd->endpoint[i]); + if (cd->endpoint[i]) + update_internal_comp(dev, cd->endpoint[i]); /* For ALH multi-gateway case, params->channels is a total multiplexed * number of channels. Demultiplexed number of channels for each individual @@ -1640,14 +1704,6 @@ static int copier_params(struct comp_dev *dev, struct sof_ipc_stream_params *par case SOF_COMP_HOST: if (!cd->ipc_gtw) { component_set_nearest_period_frames(dev, params->rate); - if (params->direction == SOF_IPC_STREAM_CAPTURE) { - params->buffer.size = cd->config.base.obs; - params->sample_container_bytes = - cd->out_fmt->depth / 8; - params->sample_valid_bytes = - cd->out_fmt->valid_bit_depth / 8; - } - ret = host_zephyr_params(cd->hd, dev, params, copier_notifier_cb); @@ -1660,10 +1716,27 @@ static int copier_params(struct comp_dev *dev, struct sof_ipc_stream_params *par break; case SOF_COMP_DAI: if (cd->endpoint_num == 1) { - ret = dai_zephyr_params(cd->dd[0], cd->endpoint[0], - params); - if (ret < 0) - return ret; + ret = dai_zephyr_params(cd->dd[0], dev, params); + + /* + * dai_zephyr_params assigns the conversion function + * based on the input/output formats but does not take + * the valid bits into account. So change the conversion + * function if the valid bits are different from the + * container size. + */ + audio_stream_fmt_conversion(in_fmt->depth, + in_fmt->valid_bit_depth, + &in_bits, &in_valid_bits, + in_fmt->s_type); + audio_stream_fmt_conversion(out_fmt->depth, + out_fmt->valid_bit_depth, + &out_bits, &out_valid_bits, + out_fmt->s_type); + + if (in_bits != in_valid_bits || out_bits != out_valid_bits) + cd->dd[0]->process = + cd->converter[IPC4_COPIER_GATEWAY_PIN]; } else { ret = cd->endpoint[i]->drv->ops.params(cd->endpoint[i], params); @@ -1806,11 +1879,17 @@ static int copier_get_large_config(struct comp_dev *dev, uint32_t param_id, struct sof_ipc_stream_posn posn; struct ipc4_llp_reading_extended llp_ext; struct ipc4_llp_reading llp; + struct comp_dev *temp_dev; + + if (dev->ipc_config.type == SOF_COMP_DAI && cd->endpoint_num == 1) + temp_dev = dev; + else + temp_dev = cd->endpoint[IPC4_COPIER_GATEWAY_PIN]; switch (param_id) { case IPC4_COPIER_MODULE_CFG_PARAM_LLP_READING: if (!cd->endpoint_num || - comp_get_endpoint_type(cd->endpoint[IPC4_COPIER_GATEWAY_PIN]) != + comp_get_endpoint_type(temp_dev) != COMP_ENDPOINT_DAI) { comp_err(dev, "Invalid component type"); return -EINVAL; @@ -1824,13 +1903,13 @@ static int copier_get_large_config(struct comp_dev *dev, uint32_t param_id, *data_offset = sizeof(struct ipc4_llp_reading); memset(&llp, 0, sizeof(llp)); - if (cd->endpoint[IPC4_COPIER_GATEWAY_PIN]->state != COMP_STATE_ACTIVE) { + if (temp_dev->state != COMP_STATE_ACTIVE) { memcpy_s(data, sizeof(llp), &llp, sizeof(llp)); return 0; } /* get llp from dai */ - comp_position(cd->endpoint[IPC4_COPIER_GATEWAY_PIN], &posn); + comp_position(temp_dev, &posn); convert_u64_to_u32s(posn.comp_posn, &llp.llp_l, &llp.llp_u); convert_u64_to_u32s(posn.wallclock, &llp.wclk_l, &llp.wclk_u); @@ -1840,7 +1919,7 @@ static int copier_get_large_config(struct comp_dev *dev, uint32_t param_id, case IPC4_COPIER_MODULE_CFG_PARAM_LLP_READING_EXTENDED: if (!cd->endpoint_num || - comp_get_endpoint_type(cd->endpoint[IPC4_COPIER_GATEWAY_PIN]) != + comp_get_endpoint_type(temp_dev) != COMP_ENDPOINT_DAI) { comp_err(dev, "Invalid component type"); return -EINVAL; @@ -1854,13 +1933,13 @@ static int copier_get_large_config(struct comp_dev *dev, uint32_t param_id, *data_offset = sizeof(struct ipc4_llp_reading_extended); memset(&llp_ext, 0, sizeof(llp_ext)); - if (cd->endpoint[IPC4_COPIER_GATEWAY_PIN]->state != COMP_STATE_ACTIVE) { + if (temp_dev->state != COMP_STATE_ACTIVE) { memcpy_s(data, sizeof(llp_ext), &llp_ext, sizeof(llp_ext)); return 0; } /* get llp from dai */ - comp_position(cd->endpoint[IPC4_COPIER_GATEWAY_PIN], &posn); + comp_position(temp_dev, &posn); convert_u64_to_u32s(posn.comp_posn, &llp_ext.llp_reading.llp_l, &llp_ext.llp_reading.llp_u); @@ -1968,7 +2047,11 @@ static int copier_position(struct comp_dev *dev, struct sof_ipc_stream_posn *pos } break; case SOF_COMP_DAI: - ret = dai_zephyr_position(cd->dd[0], cd->endpoint[IPC4_COPIER_GATEWAY_PIN], posn); + if (cd->endpoint_num == 1) + ret = dai_zephyr_position(cd->dd[0], dev, posn); + else + ret = dai_zephyr_position(cd->dd[0], cd->endpoint[IPC4_COPIER_GATEWAY_PIN], + posn); break; default: break; From 3b27700e48a49b704c400026af6cdb5b6f521621 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 May 2023 21:08:57 -0700 Subject: [PATCH 84/94] ipc4: dai: No need to unregister DMA copy notifier It is not needed for IPC4. Signed-off-by: Ranjani Sridharan --- src/ipc/ipc4/dai.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index 20ac83b81c5c..63cce5774833 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -171,14 +171,9 @@ void dai_dma_release(struct dai_data *dd, struct comp_dev *dev) if (dev->state != COMP_STATE_PAUSED) dma_stop(dd->chan->dma->z_dev, dd->chan->index); - /* remove callback */ - notifier_unregister(dev, dd->chan, NOTIFIER_ID_DMA_COPY); dma_release_channel(dd->chan->dma->z_dev, dd->chan->index); #else dma_stop_legacy(dd->chan); - - /* remove callback */ - notifier_unregister(dev, dd->chan, NOTIFIER_ID_DMA_COPY); dma_channel_put_legacy(dd->chan); #endif dd->chan->dev_data = NULL; From 2d0595bea9e9eee7682bf9062cca0e304402dd3b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 5 May 2023 11:38:01 -0700 Subject: [PATCH 85/94] lib: dma: Add a new DMA buffer copy function Add a new DMA copy function, dma_buffer_copy_from_no_consume(), that can be used to copy from the DMA buffer to the sink without modifying the read pointer in the DMA buffer. This will be used when the DMA data needs to be copied to multiple sink buffers. The DMA buffer pointer should be updated at the end of all copies in this case. Signed-off-by: Ranjani Sridharan --- src/lib/dma.c | 21 +++++++++++++++++++++ xtos/include/sof/lib/dma.h | 9 +++++++++ 2 files changed, 30 insertions(+) diff --git a/src/lib/dma.c b/src/lib/dma.c index 58aa64dc841e..6115cfba1e85 100644 --- a/src/lib/dma.c +++ b/src/lib/dma.c @@ -378,3 +378,24 @@ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, return ret; } + +int dma_buffer_copy_from_no_consume(struct comp_buffer __sparse_cache *source, + struct comp_buffer __sparse_cache *sink, + dma_process_func process, uint32_t source_bytes) +{ + struct audio_stream __sparse_cache *istream = &source->stream; + uint32_t samples = source_bytes / + audio_stream_sample_bytes(istream); + uint32_t sink_bytes = audio_stream_sample_bytes(&sink->stream) * + samples; + int ret; + + /* process data */ + ret = process(istream, 0, &sink->stream, 0, samples); + + buffer_stream_writeback(sink, sink_bytes); + + comp_update_buffer_produce(sink, sink_bytes); + + return ret; +} diff --git a/xtos/include/sof/lib/dma.h b/xtos/include/sof/lib/dma.h index bd207ce42025..30fa889699bb 100644 --- a/xtos/include/sof/lib/dma.h +++ b/xtos/include/sof/lib/dma.h @@ -532,6 +532,15 @@ int dma_buffer_copy_from(struct comp_buffer __sparse_cache *source, struct comp_buffer __sparse_cache *sink, dma_process_func process, uint32_t source_bytes); +/* + * Used when copying DMA buffer bytes into multiple sink buffers, one at a time using the provided + * conversion function. DMA buffer consume should be performed after the data has been copied + * to all sinks. + */ +int dma_buffer_copy_from_no_consume(struct comp_buffer __sparse_cache *source, + struct comp_buffer __sparse_cache *sink, + dma_process_func process, uint32_t source_bytes); + /* copies data to DMA buffer using provided processing function */ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, struct comp_buffer __sparse_cache *sink, From c08898c8ef2859a50d20af6758e408cb242e0373 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 May 2023 23:13:38 -0700 Subject: [PATCH 86/94] dai-zephyr: Support multiple sink buffers with single endpoint copier DAIs Add support for single endpoint DAI copiers with multiple sinks by copying from the DMA to all the sink buffers in a loop while using the right PCM converter function. Modify the signature of dai_zephyr_copy() to pass the array of converter functions to be used while copying from the DMA. Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 2 +- src/audio/dai-legacy.c | 8 +- src/audio/dai-zephyr.c | 128 +++++++++++++++++++++++++---- src/include/sof/audio/dai_copier.h | 2 +- 4 files changed, 119 insertions(+), 21 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 01586b0706c9..12cc0a9dd96a 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -1383,7 +1383,7 @@ static int do_endpoint_copy(struct comp_dev *dev) break; case SOF_COMP_DAI: if (cd->endpoint_num == 1) - return dai_zephyr_copy(cd->dd[0], dev); + return dai_zephyr_copy(cd->dd[0], dev, cd->converter); break; default: break; diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 6cc3fc55bb55..98d1c1e99673 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -958,7 +958,7 @@ static void dai_report_xrun(struct comp_dev *dev, uint32_t bytes) } /* copy and process stream data from source to sink buffers */ -int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) +int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_func *converter) { uint32_t dma_fmt; uint32_t sampling; @@ -1047,7 +1047,11 @@ static int dai_copy(struct comp_dev *dev) comp_dbg(dev, "dai_copy()"); - return dai_zephyr_copy(dd, dev); + /* + * DAI devices will only ever have 1 sink, so no need to pass an array of PCM converter + * functions. The default one to use is set in dd->process. + */ + return dai_zephyr_copy(dd, dev, NULL); } /** diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 73337eba4c23..68b9baf4c26d 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -218,7 +218,9 @@ static int dai_get_fifo(struct dai *dai, int direction, int stream_id) } /* this is called by DMA driver every time descriptor has completed */ -static enum dma_cb_status dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes) +static enum dma_cb_status +dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, + pcm_converter_func *converter) { struct comp_buffer __sparse_cache *local_buf, *dma_buf; enum dma_cb_status dma_status = DMA_CB_STATUS_RELOAD; @@ -250,13 +252,69 @@ static enum dma_cb_status dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, local_buf = buffer_acquire(dd->local_buffer); - if (dev->direction == SOF_IPC_STREAM_PLAYBACK) + if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { ret = dma_buffer_copy_to(local_buf, dma_buf, dd->process, bytes); - else - ret = dma_buffer_copy_from(dma_buf, local_buf, - dd->process, bytes); + buffer_release(local_buf); + } else { + struct list_item *sink_list; + + audio_stream_invalidate(&dma_buf->stream, bytes); + /* + * The PCM converter functions used during DMA buffer copy can never fail, + * so no need to check the return value of dma_buffer_copy_from_no_consume(). + */ + ret = dma_buffer_copy_from_no_consume(dma_buf, local_buf, dd->process, bytes); + buffer_release(local_buf); +#if CONFIG_IPC_MAJOR_4 + /* Skip in case of endpoint DAI devices created by the copier */ + if (converter) { + /* + * copy from DMA buffer to all sink buffers using the right PCM converter + * function + */ + list_for_item(sink_list, &dev->bsink_list) { + struct comp_buffer __sparse_cache *sink_c; + struct comp_dev *sink_dev; + struct comp_buffer *sink; + int j; + + sink = container_of(sink_list, struct comp_buffer, source_list); + + /* this has been handled above already */ + if (sink == dd->local_buffer) + continue; + sink_c = buffer_acquire(sink); + sink_dev = sink_c->sink; + + j = IPC4_SINK_QUEUE_ID(sink_c->id); + + if (j >= IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT) { + comp_err(dev, "Sink queue ID: %d >= max output pin count: %d\n", + j, IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT); + ret = -EINVAL; + goto err; + } + + if (!converter[j]) { + comp_err(dev, "No PCM converter for sink queue %d\n", j); + ret = -EINVAL; + goto err; + } + + if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE) + ret = dma_buffer_copy_from_no_consume(dma_buf, sink_c, + converter[j], bytes); +err: + buffer_release(sink_c); + } + } +#endif + audio_stream_consume(&dma_buf->stream, bytes); + } + + local_buf = buffer_acquire(dd->local_buffer); /* assert dma_buffer_copy succeed */ if (ret < 0) { struct comp_buffer __sparse_cache *source_c, *sink_c; @@ -1241,7 +1299,7 @@ static void dai_report_xrun(struct dai_data *dd, struct comp_dev *dev, uint32_t } /* copy and process stream data from source to sink buffers */ -int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) +int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_func *converter) { uint32_t dma_fmt; uint32_t sampling; @@ -1252,7 +1310,7 @@ int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) uint32_t copy_bytes = 0; uint32_t src_samples; uint32_t sink_samples; - uint32_t samples; + uint32_t samples = UINT32_MAX; int ret; /* get data sizes from DMA */ @@ -1283,17 +1341,52 @@ int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) buffer_release(buf_c); - buf_c = buffer_acquire(dd->local_buffer); /* calculate minimum size to copy */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { + buf_c = buffer_acquire(dd->local_buffer); src_samples = audio_stream_get_avail_samples(&buf_c->stream); sink_samples = free_bytes / sampling; samples = MIN(src_samples, sink_samples); + buffer_release(buf_c); } else { + struct list_item *sink_list; + src_samples = avail_bytes / sampling; - sink_samples = audio_stream_get_free_samples(&buf_c->stream); - samples = MIN(src_samples, sink_samples); + + /* + * there's only one sink buffer in the case of endpoint DAI devices created by + * a DAI copier and it is chosen as the dd->local buffer + */ + if (!converter) { + buf_c = buffer_acquire(dd->local_buffer); + sink_samples = audio_stream_get_free_samples(&buf_c->stream); + samples = MIN(samples, sink_samples); + buffer_release(buf_c); + } else { + /* + * In the case of capture DAI's with multiple sink buffers, compute the + * minimum number of samples based on the DMA avail_bytes and the free + * samples in all active sink buffers. + */ + list_for_item(sink_list, &dev->bsink_list) { + struct comp_dev *sink_dev; + struct comp_buffer *sink; + + sink = container_of(sink_list, struct comp_buffer, source_list); + buf_c = buffer_acquire(sink); + sink_dev = buf_c->sink; + + if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE) { + sink_samples = + audio_stream_get_free_samples(&buf_c->stream); + samples = MIN(samples, sink_samples); + } + buffer_release(buf_c); + } + } + + samples = MIN(samples, src_samples); } /* limit bytes per copy to one period for the whole pipeline @@ -1305,11 +1398,8 @@ int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) copy_bytes = samples * sampling; - comp_dbg(dev, "dai_zephyr_copy(), dir: %d copy_bytes= 0x%x, frames= %d", - dev->direction, copy_bytes, - samples / buf_c->stream.channels); - - buffer_release(buf_c); + comp_dbg(dev, "dai_zephyr_copy(), dir: %d copy_bytes= 0x%x", + dev->direction, copy_bytes); /* Check possibility of glitch occurrence */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK && @@ -1333,7 +1423,7 @@ int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev) if (ret < 0) comp_warn(dev, "dai_zephyr_copy(): dai trigger copy failed"); - if (dai_dma_cb(dd, dev, copy_bytes) == DMA_CB_STATUS_END) + if (dai_dma_cb(dd, dev, copy_bytes, converter) == DMA_CB_STATUS_END) dma_stop(dd->chan->dma->z_dev, dd->chan->index); ret = dma_reload(dd->chan->dma->z_dev, dd->chan->index, 0, 0, copy_bytes); @@ -1351,7 +1441,11 @@ static int dai_copy(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); - return dai_zephyr_copy(dd, dev); + /* + * DAI devices will only ever have 1 sink, so no need to pass an array of PCM converter + * functions. The default one to use is set in dd->process. + */ + return dai_zephyr_copy(dd, dev, NULL); } /** diff --git a/src/include/sof/audio/dai_copier.h b/src/include/sof/audio/dai_copier.h index 48107d36d035..56dde5bda85e 100644 --- a/src/include/sof/audio/dai_copier.h +++ b/src/include/sof/audio/dai_copier.h @@ -36,7 +36,7 @@ int dai_zephyr_position(struct dai_data *dd, struct comp_dev *dev, int dai_zephyr_params(struct dai_data *dd, struct comp_dev *dev, struct sof_ipc_stream_params *params); -int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev); +int dai_zephyr_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_func *converter); int dai_zephyr_ts_config_op(struct dai_data *dd, struct comp_dev *dev); From 98bf5212f7c7192a8543b4028b57619f09bd953b Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 9 Jun 2023 20:50:26 +0800 Subject: [PATCH 87/94] Topology2: sdw-jack-generic: add 1 ch format support Some codecs like cs42l42 support 1 channel capture only. Signed-off-by: Bard Liao --- tools/topology/topology2/cavs-sdw.conf | 2 + .../platform/intel/sdw-jack-generic.conf | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/tools/topology/topology2/cavs-sdw.conf b/tools/topology/topology2/cavs-sdw.conf index 61fe676fd004..c491fe4f64ab 100644 --- a/tools/topology/topology2/cavs-sdw.conf +++ b/tools/topology/topology2/cavs-sdw.conf @@ -37,6 +37,8 @@ + + diff --git a/tools/topology/topology2/platform/intel/sdw-jack-generic.conf b/tools/topology/topology2/platform/intel/sdw-jack-generic.conf index 0c81629f9e3e..a53ac66a65a3 100644 --- a/tools/topology/topology2/platform/intel/sdw-jack-generic.conf +++ b/tools/topology/topology2/platform/intel/sdw-jack-generic.conf @@ -80,11 +80,56 @@ Object.Pipeline { index 10 Object.Widget.copier.1.stream_name "Passthrough Capture 0" + Object.Widget.copier.1.num_input_audio_formats 9 + Object.Widget.copier.1.num_output_audio_formats 9 Object.Widget.copier.1.Object.Base.audio_format.1 { # 32/32 -> 16/16 bits conversion is done here in_bit_depth 32 in_valid_bit_depth 32 } + # 32-bit 48KHz 1ch + Object.Widget.copier.1.Object.Base.input_audio_format.7 { + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + Object.Widget.copier.1.Object.Base.output_audio_format.7 { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + # 24-bit 48KHz 1ch + Object.Widget.copier.1.Object.Base.input_audio_format.8 { + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO +} + Object.Widget.copier.1.Object.Base.output_audio_format.8 { + out_bit_depth 32 + out_valid_bit_depth 24 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + # 16-bit 48KHz 1ch + Object.Widget.copier.1.Object.Base.input_audio_format.9 { + in_channels 1 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + Object.Widget.copier.1.Object.Base.output_audio_format.9 { + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } } ] From 8a020dac19e075d1bc009bc79c186ef88e77fb01 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 24 May 2023 18:07:30 +0800 Subject: [PATCH 88/94] topology2: sdw-jack-generic: add SDW_JACK_CAPTURE_CH macro Adding SDW_JACK_CAPTURE_CH macro to specify sdw jack channels. The default value is 2. Signed-off-by: Bard Liao --- tools/topology/topology2/cavs-sdw.conf | 1 + tools/topology/topology2/platform/intel/sdw-jack-generic.conf | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tools/topology/topology2/cavs-sdw.conf b/tools/topology/topology2/cavs-sdw.conf index c491fe4f64ab..7708cfb422e5 100644 --- a/tools/topology/topology2/cavs-sdw.conf +++ b/tools/topology/topology2/cavs-sdw.conf @@ -72,6 +72,7 @@ Define { NUM_SDW_AMP_LINKS 0 SDW_DMIC 0 SDW_JACK true + SDW_JACK_CAPTURE_CH 2 } # override defaults with platform-specific config diff --git a/tools/topology/topology2/platform/intel/sdw-jack-generic.conf b/tools/topology/topology2/platform/intel/sdw-jack-generic.conf index a53ac66a65a3..f0d3c6e6d3fb 100644 --- a/tools/topology/topology2/platform/intel/sdw-jack-generic.conf +++ b/tools/topology/topology2/platform/intel/sdw-jack-generic.conf @@ -180,6 +180,8 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name "Passthrough Capture 0" formats 'S16_LE,S32_LE' + channels_min $SDW_JACK_CAPTURE_CH + channels_max $SDW_JACK_CAPTURE_CH } } ] From 006f71e212e32b8c0024ec326dbaf66628758f88 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Tue, 23 May 2023 12:07:49 -0500 Subject: [PATCH 89/94] topology2: add sof-mtl-cs42l42-l0-max98363-l2-4ch support cs42l42 headset codec on link0 & 2xmax98363 on link 2. Co-developed-by: Uday M Bhat Co-developed-by: Jairaj Arava Signed-off-by: Yong Zhi --- tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake index 5b0fbeddcfa3..092a8fe839a7 100644 --- a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake +++ b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake @@ -40,4 +40,11 @@ NHLT_BIN=nhlt-sof-mtl-max98357a-rt5682.bin,DEEPBUFFER_FW_DMA_MS=10,HEADSET_SSP_D SPEAKER_SSP_DAI_INDEX=0,HEADSET_CODEC_NAME=SSP2-Codec,SPEAKER_CODEC_NAME=SSP0-Codec,\ BT_NAME=SSP1-BT,BT_INDEX=1,BT_ID=8,BT_PCM_NAME=Bluetooth,INCLUDE_ECHO_REF=true,USE_CHAIN_DMA=true,\ DEEPBUFFER_D0I3_COMPATIBLE=true" + +# SDW + DMIC + HDMI +"cavs-sdw\;sof-mtl-sdw-cs42l42-l0-max98363-l2\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ +PDM1_MIC_B_ENABLE=1,DMIC0_ID=3,DMIC1_ID=4,USE_CHAIN_DMA=true,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-sdw-cs42l42-l0-max98363-l2.bin,\ +NUM_SDW_AMP_LINKS=1,SDW_SPK_STREAM=SDW2-Playback,SDW_AMP_FEEDBACK=false,\ +SDW_JACK_CAPTURE_CH=1,DEEPBUFFER_FW_DMA_MS=100,DEEPBUFFER_D0I3_COMPATIBLE=true" ) From 30f454312ec7e9451c5f14995b0dd160409b240a Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 23 May 2023 18:14:08 +0800 Subject: [PATCH 90/94] Topology2: sdw-jack-generic: add 24 bit format support for sdw jack Somehow s24_le format is missed. Signed-off-by: Bard Liao (cherry picked from commit f0b44b48549179a76626832d2abf6f6e6d661ef1) Signed-off-by: Jairaj Arava --- tools/topology/topology2/platform/intel/sdw-jack-generic.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/topology/topology2/platform/intel/sdw-jack-generic.conf b/tools/topology/topology2/platform/intel/sdw-jack-generic.conf index f0d3c6e6d3fb..f58267dfb74e 100644 --- a/tools/topology/topology2/platform/intel/sdw-jack-generic.conf +++ b/tools/topology/topology2/platform/intel/sdw-jack-generic.conf @@ -166,7 +166,7 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name "volume playback 0" - formats 'S16_LE,S32_LE' + formats 'S16_LE,S24_LE,S32_LE' } } { @@ -179,7 +179,7 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name "Passthrough Capture 0" - formats 'S16_LE,S32_LE' + formats 'S16_LE,S24_LE,S32_LE' channels_min $SDW_JACK_CAPTURE_CH channels_max $SDW_JACK_CAPTURE_CH } From 9daaddcffb8978befb8f8c7b6e9fcde80d07b526 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Tue, 27 Jun 2023 16:50:42 +0200 Subject: [PATCH 91/94] host: do not set L1 exit if interrupt mode selected + update zephyr west Update zephyr to c31e68329 Signed-off-by: Adrian Bonislawski --- src/audio/host-zephyr.c | 8 ++++++-- west.yml | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index c496e5b29edb..119d2e353eba 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -457,10 +457,10 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal copy_bytes = host_get_copy_bytes_normal(hd, dev); if (!copy_bytes) return 0; - +#if !CONFIG_DMA_INTEL_ADSP_HDA_TIMING_L1_EXIT /* Register Host DMA usage */ pm_runtime_get(PM_RUNTIME_HOST_DMA_L1, 0); - +#endif cb(dev, copy_bytes); hd->partial_size += copy_bytes; @@ -564,10 +564,12 @@ int host_zephyr_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) if (ret < 0) comp_err(dev, "host_trigger(): dma_start() failed, ret = %u", ret); +#if !CONFIG_DMA_INTEL_ADSP_HDA_TIMING_L1_EXIT /* Register common L1 exit for all channels */ ret = notifier_register(NULL, scheduler_get_data(SOF_SCHEDULE_LL_TIMER), NOTIFIER_ID_LL_POST_RUN, hda_dma_l1_exit_notify, NOTIFIER_FLAG_AGGREGATE); +#endif break; case COMP_TRIGGER_STOP: case COMP_TRIGGER_XRUN: @@ -576,9 +578,11 @@ int host_zephyr_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) if (ret < 0) comp_err(dev, "host_trigger(): dma stop failed: %d", ret); +#if !CONFIG_DMA_INTEL_ADSP_HDA_TIMING_L1_EXIT /* Unregister L1 exit */ notifier_unregister(NULL, scheduler_get_data(SOF_SCHEDULE_LL_TIMER), NOTIFIER_ID_LL_POST_RUN); +#endif } break; diff --git a/west.yml b/west.yml index d9f88197de63..6194854c7b1f 100644 --- a/west.yml +++ b/west.yml @@ -43,7 +43,7 @@ manifest: - name: zephyr repo-path: zephyr - revision: 79b598daf229fe971a303389d5301ab31212deb8 + revision: c31e683295ebd77789f6b4e95c68b073b53b0112 remote: thesofproject # Import some projects listed in zephyr/west.yml@revision From fc025f7f9e4c8f57139041046b6e904ef5c374a3 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Wed, 19 Jul 2023 09:41:34 +0200 Subject: [PATCH 92/94] west: update rimage to a0b0187ce1e9 update rimage to a0b0187ce1e9 (added missing cpc values and fixed pv build) Signed-off-by: Adrian Bonislawski --- rimage | 2 +- west.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rimage b/rimage index 01af253b5965..a0b0187ce1e9 160000 --- a/rimage +++ b/rimage @@ -1 +1 @@ -Subproject commit 01af253b59655c7823d40cc1e393859c628055ea +Subproject commit a0b0187ce1e945869fd5343097282411b7118654 diff --git a/west.yml b/west.yml index 6194854c7b1f..4e2bc7a5bc34 100644 --- a/west.yml +++ b/west.yml @@ -34,7 +34,7 @@ manifest: - name: rimage repo-path: rimage path: sof/rimage - revision: 01af253b59655c7823d40cc1e393859c628055ea + revision: a0b0187ce1e945869fd5343097282411b7118654 - name: tomlc99 repo-path: tomlc99 From dc1ea4902edefb62c853b83a763fb24bf4303c45 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Thu, 2 Mar 2023 11:28:34 -0800 Subject: [PATCH 93/94] zephyr: Update GOOGLE_RTC_AUDIO_PROCESSING Unbreak the Zephyr build when this is enabled, and add the needed bits to produce a working executable. This is mostly just a recapitulation of the existing integration, which means that it's manually pulling in bits from the Cadence toolchain it needs. Really this is nothing more than a C++ library and it shouldn't have to do anything other than enable CONFIG_CPP=y in the build. But the upstream Zephyr C++ toolchain integration for xcc/xt-clang isn't present yet. Signed-off-by: Andy Ross --- zephyr/CMakeLists.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index d00372c8cc54..4114371e8d61 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -710,6 +710,29 @@ zephyr_library_sources_ifdef(CONFIG_DW_DMA ${SOF_DRIVERS_PATH}/dw/dma.c ) +if(CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING) + zephyr_library_sources(${SOF_AUDIO_PATH}/google/google_rtc_audio_processing.c) + zephyr_library_sources_ifdef(CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK + ${SOF_AUDIO_PATH}/google/google_rtc_audio_processing_mock.c) + zephyr_include_directories(../third_party/include) + target_link_directories(SOF INTERFACE ../third_party/lib) + target_link_libraries(SOF INTERFACE google_rtc_audio_processing) + + # This isn't quite right, Zephyr should be providing a C++ + # linkage environment for the toolchain, but the xcc/xt-clang + # integration isn't yet. Note we need to specify libc/libm + # because the Cadence C++ standard library is tightly coupled + # to their own libc (which is just a newlib). And I have NO + # idea why libgcc isn't on the link currently, that's a Zephyr + # mistake and I guess I'm surprised nothing else has broken. + # Needs to be cleaned up Zephyr-side. + target_link_libraries(SOF INTERFACE c++) + target_link_libraries(SOF INTERFACE c++abi) + target_link_libraries(SOF INTERFACE m) + target_link_libraries(SOF INTERFACE c) + target_link_libraries(SOF INTERFACE gcc) +endif() + zephyr_library_link_libraries(SOF) target_link_libraries(SOF INTERFACE zephyr_interface) From cae739d0b044648364d5e7fdc38b887b5b32c71c Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Thu, 2 Mar 2023 11:25:59 -0800 Subject: [PATCH 94/94] zephyr/alloc: Add newlib-style allocator stub for C++ builds This is a weak stub for the Cadence libc's allocator (which is just a newlib build). It's traditionally been provided like this in SOF for the benefit of C++ code where the standard library needs to link to a working malloc() even if it will never call it. Longer term this should be integrated as a working allocator, either unified with the one here or in the Zephyr libc layer. Zephyr already provides a newlib-compatible _sbrk_r(), we just have to tell it to use it when linking against Cadence libc. Signed-off-by: Andy Ross --- zephyr/lib/alloc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/zephyr/lib/alloc.c b/zephyr/lib/alloc.c index 8b0dad31da38..35bd322a4e22 100644 --- a/zephyr/lib/alloc.c +++ b/zephyr/lib/alloc.c @@ -369,4 +369,15 @@ static int heap_init(void) return 0; } +/* This is a weak stub for the Cadence libc's allocator (which is just + * a newlib build). It's traditionally been provided like this in SOF + * for the benefit of C++ code where the standard library needs to + * link to a working malloc() even if it will never call it. + */ +struct _reent; +__weak void *_sbrk_r(struct _reent *ptr, ptrdiff_t incr) +{ + k_panic(); +} + SYS_INIT(heap_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);