diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index 29e602871af7..a67efe0d5118 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -126,6 +126,9 @@ if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) if(CONFIG_COMP_TONE) add_subdirectory(tone) endif() + if(CONFIG_DAI_INTEL_UAOL) + add_local_sources(sof uaol.c dsrc.c) + endif() if(CONFIG_ZEPHYR_NATIVE_DRIVERS) list(APPEND base_files host-zephyr.c) sof_list_append_ifdef(CONFIG_COMP_DAI base_files dai-zephyr.c) diff --git a/src/audio/base_fw_intel.c b/src/audio/base_fw_intel.c index 67b87a0afed4..57799f285f59 100644 --- a/src/audio/base_fw_intel.c +++ b/src/audio/base_fw_intel.c @@ -24,10 +24,6 @@ #include #include -#if CONFIG_UAOL_INTEL_ADSP -#include -#endif - #include #include #include @@ -37,6 +33,10 @@ #include #endif +#if CONFIG_UAOL_INTEL_ADSP +#include +#endif + struct ipc4_modules_info { uint32_t modules_count; struct sof_man_module modules[0]; @@ -46,22 +46,6 @@ struct ipc4_modules_info { STATIC_ASSERT(sizeof(struct ipc4_modules_info) < SOF_IPC_MSG_MAX_SIZE, invalid_modules_info_struct_size); -#if CONFIG_UAOL_INTEL_ADSP -struct ipc4_uaol_link_capabilities { - uint32_t input_streams_supported : 4; - uint32_t output_streams_supported : 4; - uint32_t bidirectional_streams_supported : 5; - uint32_t rsvd : 19; - uint32_t max_tx_fifo_size; - uint32_t max_rx_fifo_size; -} __packed __aligned(4); - -struct ipc4_uaol_capabilities { - uint32_t link_count; - struct ipc4_uaol_link_capabilities link_caps[]; -} __packed __aligned(4); -#endif /* CONFIG_UAOL_INTEL_ADSP */ - /* * TODO: default to value of ACE1.x platforms. This is defined * in multiple places in Zephyr, mm_drv_intel_adsp.h and @@ -103,61 +87,6 @@ __cold int basefw_vendor_fw_config(uint32_t *data_offset, char *data) return 0; } -#if CONFIG_UAOL_INTEL_ADSP -#define DEV_AND_COMMA(node) DEVICE_DT_GET(node), -static const struct device *uaol_devs[] = { - DT_FOREACH_STATUS_OKAY(intel_adsp_uaol, DEV_AND_COMMA) -}; - -#if !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY -__cold static void tlv_value_set_uaol_caps(struct sof_tlv *tuple, uint32_t type) -{ - const size_t dev_count = ARRAY_SIZE(uaol_devs); - struct uaol_capabilities dev_cap; - struct ipc4_uaol_capabilities *caps = (struct ipc4_uaol_capabilities *)tuple->value; - size_t caps_size = offsetof(struct ipc4_uaol_capabilities, link_caps[dev_count]); - size_t i; - int ret; - - assert_can_be_cold(); - - memset(caps, 0, caps_size); - - caps->link_count = dev_count; - for (i = 0; i < dev_count; i++) { - ret = uaol_get_capabilities(uaol_devs[i], &dev_cap); - if (ret) - continue; - - caps->link_caps[i].input_streams_supported = dev_cap.input_streams; - caps->link_caps[i].output_streams_supported = dev_cap.output_streams; - caps->link_caps[i].bidirectional_streams_supported = dev_cap.bidirectional_streams; - caps->link_caps[i].max_tx_fifo_size = dev_cap.max_tx_fifo_size; - caps->link_caps[i].max_rx_fifo_size = dev_cap.max_rx_fifo_size; - } - - tlv_value_set(tuple, type, caps_size, caps); -} -#endif /* CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY */ - -__cold static int uaol_stream_id_to_hda_link_stream_id(int uaol_stream_id) -{ - size_t dev_count = ARRAY_SIZE(uaol_devs); - size_t i; - - assert_can_be_cold(); - - for (i = 0; i < dev_count; i++) { - int hda_link_stream_id = uaol_get_mapped_hda_link_stream_id(uaol_devs[i], - uaol_stream_id); - if (hda_link_stream_id >= 0) - return hda_link_stream_id; - } - - return -1; -} -#endif /* CONFIG_UAOL_INTEL_ADSP */ - __cold int basefw_vendor_hw_config(uint32_t *data_offset, char *data) { struct sof_tlv *tuple = (struct sof_tlv *)data; diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index dfd2590c7108..3fcc790bc385 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -327,7 +327,7 @@ __cold int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, dai.type = SOF_DAI_INTEL_UAOL; dai.is_config_blob = true; cd->gtw_type = ipc4_gtw_alh; - ret = ipc4_find_dma_config(&dai, gtw_cfg_data, gtw_cfg_size); + ret = ipc4_find_dma_config_tlv(&dai, gtw_cfg_data, gtw_cfg_size); if (ret != IPC4_SUCCESS) { comp_err(dev, "No uaol dma_config found in blob!"); return -EINVAL; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index e49d3e0f0122..5fe3afde41c8 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -46,6 +46,10 @@ #include #include +#ifdef CONFIG_DAI_INTEL_UAOL +#include +#include +#endif #include @@ -352,8 +356,14 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, } } #endif - ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer, - dd->process, bytes, dd->chmap); + +#ifdef CONFIG_DAI_INTEL_UAOL + if (dd->uaol.feedback_drift) + ret = uaol_dma_buffer_copy_to(dd, bytes); + else +#endif /* CONFIG_DAI_INTEL_UAOL */ + ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer, + dd->process, bytes, dd->chmap); } else { audio_stream_invalidate(&dd->dma_buffer->stream, bytes); /* @@ -435,6 +445,12 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, /* update host position (in bytes offset) for drivers */ dd->total_data_processed += bytes; } + +#ifdef CONFIG_DAI_INTEL_UAOL + if (dd->uaol.fb_chan_idx >= 0) + process_uaol_feedback(dev, dd); +#endif /* CONFIG_DAI_INTEL_UAOL */ + #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS /* Increment performance counters */ io_perf_monitor_update_data(dd->io_perf_dai_byte_count, bytes); @@ -593,6 +609,75 @@ __cold int dai_common_new(struct dai_data *dd, struct comp_dev *dev, return 0; } +static void dai_dma_release_channel(struct dai_data *dd) +{ + if (dd->chan_index >= 0) { + sof_dma_release_channel(dd->dma, dd->chan_index); + dd->chan_index = -EINVAL; + } + +#if CONFIG_UAOL_INTEL_ADSP + if (dd->uaol.fb_chan_idx >= 0) { + sof_dma_release_channel(dd->dma, dd->uaol.fb_chan_idx); + dd->uaol.fb_chan_idx = -EINVAL; + } +#endif +} + +static int dai_dma_config(struct dai_data *dd) +{ + int ret = sof_dma_config(dd->dma, dd->chan_index, dd->z_config); + if (ret < 0) + return ret; + +#if CONFIG_UAOL_INTEL_ADSP + if (dd->uaol.fb_chan_idx >= 0) + ret = sof_dma_config(dd->dma, dd->uaol.fb_chan_idx, dd->uaol.fb_z_config); +#endif + + return ret; +} + +static int dai_dma_start(struct dai_data *dd) +{ + int ret = sof_dma_start(dd->dma, dd->chan_index); + if (ret < 0) + return ret; + +#if CONFIG_UAOL_INTEL_ADSP + if (dd->uaol.fb_chan_idx >= 0) + ret = sof_dma_start(dd->dma, dd->uaol.fb_chan_idx); +#endif + + return ret; +} + +static int dai_dma_stop(struct dai_data *dd) +{ + int ret = sof_dma_stop(dd->dma, dd->chan_index); + +#if CONFIG_UAOL_INTEL_ADSP + /* seems it's better to stop feedback even when the above fails */ + if (dd->uaol.fb_chan_idx >= 0) + sof_dma_stop(dd->dma, dd->uaol.fb_chan_idx); +#endif + + return ret; +} + +static int dai_dma_suspend(struct dai_data *dd) +{ + int ret = sof_dma_suspend(dd->dma, dd->chan_index); + +#if CONFIG_UAOL_INTEL_ADSP + /* seems it's better to suspend feedback even when the above fails */ + if (dd->uaol.fb_chan_idx >= 0) + sof_dma_suspend(dd->dma, dd->uaol.fb_chan_idx); +#endif + + return ret; +} + __cold static struct comp_dev *dai_new(const struct comp_driver *drv, const struct comp_ipc_config *config, const void *spec) @@ -649,11 +734,7 @@ __cold void dai_common_free(struct dai_data *dd) if (dd->group) dai_group_put(dd->group); - if (dd->chan_index >= 0) { - sof_dma_release_channel(dd->dma, dd->chan_index); - dd->chan_index = -EINVAL; - } - + dai_dma_release_channel(dd); sof_dma_put(dd->dma); dai_release_llp_slot(dd); @@ -661,6 +742,10 @@ __cold void dai_common_free(struct dai_data *dd) dai_put(dd->dai); sof_heap_free(dd->alloc_ctx.heap, dd->dai_spec_config); + +#if CONFIG_UAOL_INTEL_ADSP + uaol_free(dd); +#endif } __cold static void dai_free(struct comp_dev *dev) @@ -1143,8 +1228,33 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, } err = dai_set_dma_config(dd, dev); - if (err < 0) + if (err < 0) { comp_err(dev, "set dma config failed."); + goto out; + } + + /* Ideally, this should be moved into setup_uaol_feedback_dma() in uaol.c, but + * there is no easy access to "params" there to set up the buffer format. + */ +#ifdef CONFIG_DAI_INTEL_UAOL + /* create DSRC output buffer (if needed) */ + if (dd->ipc_config.type == SOF_DAI_INTEL_UAOL && + dd->ipc_config.direction == SOF_IPC_STREAM_PLAYBACK) { + /* resampling might generate 1 extra frame; DSRC only works with 32-bit data */ + size_t dsrc_buf_size = (dev->frames + 1) * dd->ipc_config.gtw_fmt->channels_count * 4; + dd->uaol.dsrc_buf = buffer_alloc_range(NULL, dsrc_buf_size, dsrc_buf_size, + SOF_MEM_FLAG_USER, PLATFORM_DCACHE_ALIGN, + BUFFER_USAGE_NOT_SHARED); + if (!dd->uaol.dsrc_buf) { + comp_err(dev, "failed to alloc dsrc buffer"); + goto out; + } + + /* params should be same as local_buffer's */ + buffer_set_params(dd->uaol.dsrc_buf, ¶ms, BUFFER_UPDATE_FORCE); + } +#endif /* CONFIG_DAI_INTEL_UAOL */ + out: /* * Make sure to free all allocated items, all functions @@ -1210,6 +1320,11 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev) comp_dbg(dev, "new configured dma channel index %d", dd->chan_index); +#ifdef CONFIG_DAI_INTEL_UAOL + /* Does nothing if feedback DMA is not needed */ + setup_uaol_feedback_dma(dd, dev); +#endif /* CONFIG_DAI_INTEL_UAOL */ + return 0; } @@ -1233,6 +1348,10 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev) /* clear dma buffer to avoid pop noise */ buffer_zero(dd->dma_buffer); +#ifdef CONFIG_DAI_INTEL_UAOL + if (dd->uaol.fb_dma_buf) + memset(dd->uaol.fb_dma_buf, 0, dd->uaol.fb_dma_buf_size); +#endif /* CONFIG_DAI_INTEL_UAOL */ /* dma reconfig not required if XRUN handling */ if (dd->xrun) { @@ -1241,7 +1360,7 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev) return 0; } - ret = sof_dma_config(dd->dma, dd->chan_index, dd->z_config); + ret = dai_dma_config(dd); if (ret < 0) comp_set_state(dev, COMP_TRIGGER_RESET); @@ -1292,6 +1411,10 @@ void dai_common_reset(struct dai_data *dd, struct comp_dev *dev) dd->dma_buffer = NULL; } +#ifdef CONFIG_DAI_INTEL_UAOL + uaol_free(dd); +#endif /* CONFIG_DAI_INTEL_UAOL */ + dd->wallclock = 0; dd->total_data_processed = 0; dd->xrun = 0; @@ -1328,7 +1451,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, /* only start the DAI if we are not XRUN handling */ if (dd->xrun == 0) { - ret = sof_dma_start(dd->dma, dd->chan_index); + ret = dai_dma_start(dd); if (ret < 0) return ret; @@ -1349,6 +1472,14 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, buffer_zero(dd->dma_buffer); } +#ifdef CONFIG_DAI_INTEL_UAOL + /* It might be beneficial to clear any old obsolete feedback value to prevent + * it from being used to adjust the rate immediately after resume. A feedback + * value of 0 will be rejected by the sanity check. */ + if (dd->uaol.fb_dma_buf) + memset(dd->uaol.fb_dma_buf, 0, dd->uaol.fb_dma_buf_size); +#endif /* CONFIG_DAI_INTEL_UAOL */ + /* DMA driver and SOF's view of the DMA buffer's * read and write cursors must be the same to * avoid scenarios in which the DMA driver @@ -1366,16 +1497,16 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, /* only start the DAI if we are not XRUN handling */ if (dd->xrun == 0) { /* recover valid start position */ - ret = sof_dma_stop(dd->dma, dd->chan_index); + ret = dai_dma_stop(dd); if (ret < 0) return ret; /* dma_config needed after stop */ - ret = sof_dma_config(dd->dma, dd->chan_index, dd->z_config); + ret = dai_dma_config(dd); if (ret < 0) return ret; - ret = sof_dma_start(dd->dma, dd->chan_index); + ret = dai_dma_start(dd); if (ret < 0) return ret; @@ -1403,11 +1534,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, * as soon as possible. */ #if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE - ret = sof_dma_stop(dd->dma, dd->chan_index); + ret = dai_dma_stop(dd); dai_trigger_op(dd->dai, cmd, dev->direction); #else dai_trigger_op(dd->dai, cmd, dev->direction); - ret = sof_dma_stop(dd->dma, dd->chan_index); + ret = dai_dma_stop(dd); if (ret) { comp_warn(dev, "dma was stopped earlier"); ret = 0; @@ -1417,11 +1548,11 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, case COMP_TRIGGER_PAUSE: comp_dbg(dev, "PAUSE"); #if CONFIG_COMP_DAI_STOP_TRIGGER_ORDER_REVERSE - ret = sof_dma_suspend(dd->dma, dd->chan_index); + ret = dai_dma_suspend(dd); dai_trigger_op(dd->dai, cmd, dev->direction); #else dai_trigger_op(dd->dai, cmd, dev->direction); - ret = sof_dma_suspend(dd->dma, dd->chan_index); + ret = dai_dma_suspend(dd); #endif break; case COMP_TRIGGER_PRE_START: @@ -1852,7 +1983,7 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun comp_warn(dev, "dai trigger copy failed"); if (dai_dma_cb(dd, dev, copy_bytes, converter) == SOF_DMA_CB_STATUS_END) - sof_dma_stop(dd->dma, dd->chan_index); + dai_dma_stop(dd); ret = sof_dma_reload(dd->dma, dd->chan_index, copy_bytes); if (ret < 0) { diff --git a/src/audio/dsrc.c b/src/audio/dsrc.c new file mode 100644 index 000000000000..69aa86d8b11e --- /dev/null +++ b/src/audio/dsrc.c @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 Intel Corporation. All rights reserved. + */ + +#include +#include +#include + +void dsrc_init(struct dsrc *dsrc, size_t channels) +{ + memset(dsrc, 0, sizeof(*dsrc)); + dsrc->channels = channels; +} + +void dsrc_set_rate(struct dsrc *dsrc, uint32_t in_rate, uint32_t out_rate) +{ + if (out_rate > in_rate) { + dsrc->max_phase = ((uint64_t)in_rate << 32) / (out_rate - in_rate); + dsrc->phase_acc = 0; + memset(dsrc->previous_sample_norm, 0, sizeof(dsrc->previous_sample_norm)); + } else { + assert(out_rate == in_rate); + dsrc->max_phase = 0; + } +} + +/* phase_acc and max_phase use uint64_t with << 32 to achieve high fractional precision + * without using floating-point arithmetic. The phase increment is 1 (i.e., 1 << 32). + * Frequency precision is 1 Hz. Audio data is 32-bit. + */ +size_t dsrc_process(struct dsrc *dsrc, const struct cir_buf_ptr *in, + struct cir_buf_ptr *out, size_t frames) +{ + if (dsrc->max_phase == 0) { + /* No resampling needed, just copy the data. */ + cir_buf_copy(in->ptr, in->buf_start, in->buf_end, out->ptr, + out->buf_start, out->buf_end, + sizeof(int32_t) * dsrc->channels * frames); + + return 0; + } + + int32_t *in_ptr = in->ptr; + int32_t *out_ptr = out->ptr; + size_t added_frames = 0; + + /* Two different data types are needed: dsrc->max_phase must be 64 bits to maintain + * precision when calculating dsrc->phase_acc rollover, but max_phase_32 must be 32 bits + * to prevent overflow during multiplication. + */ + uint32_t max_phase_32 = dsrc->max_phase >> 32; + + while (frames--) { + /* Same precision considerations as max_phase_32 above apply here. */ + uint32_t phase_acc_32 = dsrc->phase_acc >> 32; + + for (size_t ch = 0; ch < dsrc->channels; ch++) { + in_ptr = cir_buf_wrap(in_ptr, in->buf_start, in->buf_end); + out_ptr = cir_buf_wrap(out_ptr, out->buf_start, out->buf_end); + + int64_t sample_norm = ((int64_t)*in_ptr << 32) / max_phase_32; + + int64_t previous_sample_norm = dsrc->previous_sample_norm[ch]; + dsrc->previous_sample_norm[ch] = sample_norm; + + *out_ptr = (sample_norm * (max_phase_32 - phase_acc_32) + + previous_sample_norm * phase_acc_32) >> 32; + + in_ptr++; + out_ptr++; + } + + dsrc->phase_acc += (uint64_t)1 << 32; + + if (dsrc->phase_acc >= dsrc->max_phase) { + dsrc->phase_acc -= dsrc->max_phase; + added_frames++; + + /* Insert new frame here */ + for (size_t ch = 0; ch < dsrc->channels; ch++) { + out_ptr = cir_buf_wrap(out_ptr, out->buf_start, out->buf_end); + + *out_ptr = (dsrc->previous_sample_norm[ch] * max_phase_32) >> 32; + + out_ptr++; + } + } + } + + return added_frames; +} diff --git a/src/audio/mixin_mixout/mixin_mixout.h b/src/audio/mixin_mixout/mixin_mixout.h index 97aa0e12cdab..5cfb30f26c43 100644 --- a/src/audio/mixin_mixout/mixin_mixout.h +++ b/src/audio/mixin_mixout/mixin_mixout.h @@ -99,13 +99,6 @@ struct ipc4_mixer_mode_config { struct ipc4_mixer_mode_sink_config mixer_mode_sink_configs[1]; } __packed __aligned(4); -/* Pointer to data in circular buffer together with buffer boundaries */ -struct cir_buf_ptr { - void *buf_start; - void *buf_end; - void *ptr; -}; - /** * \brief mixin processing function interface */ diff --git a/src/audio/uaol.c b/src/audio/uaol.c new file mode 100644 index 000000000000..67b945ac36c6 --- /dev/null +++ b/src/audio/uaol.c @@ -0,0 +1,366 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 Intel Corporation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(uaol, CONFIG_SOF_LOG_LEVEL); + +struct ipc4_uaol_link_capabilities { + uint32_t input_streams_supported : 4; + uint32_t output_streams_supported : 4; + uint32_t bidirectional_streams_supported : 5; + uint32_t rsvd : 19; + uint32_t max_tx_fifo_size; + uint32_t max_rx_fifo_size; +} __packed __aligned(4); + +struct ipc4_uaol_capabilities { + uint32_t link_count; + struct ipc4_uaol_link_capabilities link_caps[]; +} __packed __aligned(4); + +#define DEV_AND_COMMA(node) DEVICE_DT_GET(node), +static const struct device *uaol_devs[] = { + DT_FOREACH_STATUS_OKAY(intel_adsp_uaol, DEV_AND_COMMA) +}; + +#if !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY +__cold void tlv_value_set_uaol_caps(struct sof_tlv *tuple, uint32_t type) +{ + const size_t dev_count = ARRAY_SIZE(uaol_devs); + struct uaol_capabilities dev_cap; + struct ipc4_uaol_capabilities *caps = (struct ipc4_uaol_capabilities *)tuple->value; + size_t caps_size = offsetof(struct ipc4_uaol_capabilities, link_caps[dev_count]); + size_t i; + int ret; + + assert_can_be_cold(); + + memset(caps, 0, caps_size); + + caps->link_count = dev_count; + for (i = 0; i < dev_count; i++) { + ret = uaol_get_capabilities(uaol_devs[i], &dev_cap); + if (ret) + continue; + + caps->link_caps[i].input_streams_supported = dev_cap.input_streams; + caps->link_caps[i].output_streams_supported = dev_cap.output_streams; + caps->link_caps[i].bidirectional_streams_supported = dev_cap.bidirectional_streams; + caps->link_caps[i].max_tx_fifo_size = dev_cap.max_tx_fifo_size; + caps->link_caps[i].max_rx_fifo_size = dev_cap.max_rx_fifo_size; + } + + tlv_value_set(tuple, type, caps_size, caps); +} +#endif /* !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY */ + +__cold int uaol_stream_id_to_hda_link_stream_id(int uaol_stream_id) +{ + size_t dev_count = ARRAY_SIZE(uaol_devs); + size_t i; + + assert_can_be_cold(); + + for (i = 0; i < dev_count; i++) { + int hda_link_stream_id = uaol_get_mapped_hda_link_stream_id(uaol_devs[i], + uaol_stream_id); + if (hda_link_stream_id >= 0) + return hda_link_stream_id; + } + + return -1; +} + +const struct device *get_uaol_zdevice(int uaol_link_id) +{ + /* uaol_link_id is just an index for the device tree device */ + assert(uaol_link_id < ARRAY_SIZE(uaol_devs)); + return uaol_devs[uaol_link_id]; +} + +/* These are called from dai-zephyr */ + +/* The UAOL DAI device has a DMA stream with a corresponding mapped (hardwired in HW) + * UAOL device stream. These streams are separate entities. This function returns + * the UAOL device stream ID that is mapped to the UAOL DAI DMA stream. + */ +int dai_get_uaol_stream_id(struct dai *dai, int *uaol_link_id, int *uaol_stream_id) +{ + const struct dai_properties *props; + k_spinlock_key_t key; + + key = k_spin_lock(&dai->lock); + + props = dai_get_properties(dai->dev, 0, 0); + *uaol_link_id = props->uaol_link_id; + *uaol_stream_id = props->uaol_stream_id; + + k_spin_unlock(&dai->lock, key); + + return 0; +} + +/* Reads the feedback frequency (USB playback device "desired" frequency) from the feedback + * USB endpoint via the feedback DMA channel. Then updates the DSRC rate if necessary. Called + * from the dai-zephyr DMA callback. + */ +void process_uaol_feedback(struct comp_dev *dev, struct dai_data *dd) +{ + assert(dd && dd->uaol.fb_chan_idx >= 0 && dd->uaol.fb_dma_buf); + + struct dma_status stat = {0}; + int ret = sof_dma_get_status(dd->dma, dd->uaol.fb_chan_idx, &stat); + if (ret) { + comp_err(dev, "Failed to get UAOL feedback DMA status: %d", ret); + return; + } + + /* Expected feedback length is 4 bytes */ + if (stat.pending_length < 4) { + /* No feedback is normal, as it is sent rarely (e.g., every 128 ms or less often). */ + /* comp_dbg(dev, "No feedback data: %d bytes", stat.pending_length); */ + return; + } + + assert(is_uncached(dd->uaol.fb_dma_buf)); /* Use uncached pointer to read DMA buffer */ + assert(dd->uaol.fb_dma_buf_size >= 4); + + /* NOTE: Not all DMA drivers populate stat.write_position. Intel ACE HDA does. */ + assert((stat.write_position & 3) == 0); /* 4-byte alignment check. */ + /* Read the last received 4 bytes (ignore older ones if any). */ + int last_4_bytes_pos = stat.write_position >= 4 ? (stat.write_position - 4) : + (dd->uaol.fb_dma_buf_size - 4); + uint32_t feedback_value = dd->uaol.fb_dma_buf[last_4_bytes_pos / 4]; + + ret = sof_dma_reload(dd->dma, dd->uaol.fb_chan_idx, stat.pending_length); + if (ret < 0) { + comp_err(dev, "Failed to reload UAOL feedback DMA: %d, pending_length: %d", + ret, stat.pending_length); + return; + } + + comp_dbg(dev, "UAOL feedback: 0x%x", feedback_value); + + const struct device *uaol_zdev = get_uaol_zdevice(dd->uaol.link_id); + int freq = uaol_interpret_feedback_value(uaol_zdev, dd->uaol.stream_id, feedback_value); + + if (freq < 0) { + comp_err(dev, "Unexpected feedback value: 0x%x, err/freq: %d", feedback_value, freq); + return; + } + + /* Let's do a sanity check first to see if the received value looks valid. + * Then limit the maximum drift to a reasonable value to prevent significant + * audio distortion when, for some reason, the reported drift is quite large. + */ + #define REJECT_DRIFT_HZ 1000 + #define CLIP_DRIFT_HZ 6 + + int drift = freq - dd->ipc_config.sampling_frequency; + + if (drift < -REJECT_DRIFT_HZ || drift > REJECT_DRIFT_HZ) { + comp_err(dev, "Weird UAOL feedback freq value: %d, drift: %d. Rejected!", + freq, drift); + return; + } + if (drift < -CLIP_DRIFT_HZ || drift > CLIP_DRIFT_HZ) { + comp_warn(dev, "Unreasonable UAOL feedback freq value: %d, drift: %d. Clipped!", + freq, drift); + drift = MAX(-CLIP_DRIFT_HZ, MIN(drift, CLIP_DRIFT_HZ)); + } + + dd->uaol.feedback_drift = drift; + if (dd->uaol.feedback_drift > 0) + dsrc_set_rate(&dd->uaol.dsrc, dd->ipc_config.sampling_frequency, + drift + dd->ipc_config.sampling_frequency); +} + +/* Tells UAOL HW to skip one audio frame or copy one additional audio frame + * on the next service interval to adjust the data rate. + */ +void adjust_uaol_rate(const struct dai_data *dd, bool increase) +{ + const struct device *uaol_zdev = get_uaol_zdevice(dd->uaol.link_id); + int ret = uaol_adjust_rate(uaol_zdev, dd->uaol.stream_id, increase); + + if (ret != 0) + comp_err(dd->dai_dev, "Failed to adjust UAOL rate: %d", ret); +} + +/* For UAOL playback with non-zero feedback frequency drift, the UAOL rate should be adjusted + * periodically to compensate for the drift. Additionally, for positive drift, DSRC is used + * to resample audio and insert additional audio frame as needed. + * This function is called from the dai-zephyr dai_dma_cb(). + */ +int uaol_dma_buffer_copy_to(struct dai_data *dd, size_t bytes) +{ + int ret = 0; + + assert(dd->uaol.feedback_drift != 0); + + if (dd->uaol.feedback_drift > 0) { + buffer_stream_invalidate(dd->local_buffer, bytes); + + struct cir_buf_ptr in = { dd->local_buffer->stream.addr, + dd->local_buffer->stream.end_addr, dd->local_buffer->stream.r_ptr }; + assert(dd->uaol.dsrc_buf); + struct cir_buf_ptr out = { dd->uaol.dsrc_buf->stream.addr, + dd->uaol.dsrc_buf->stream.end_addr, dd->uaol.dsrc_buf->stream.w_ptr }; + size_t frames = bytes / audio_stream_frame_bytes(&dd->local_buffer->stream); + + size_t added_frames = dsrc_process(&dd->uaol.dsrc, &in, &out, frames); + size_t src_added_bytes = added_frames * + audio_stream_frame_bytes(&dd->local_buffer->stream); + + comp_update_buffer_consume(dd->local_buffer, bytes); + audio_stream_produce(&dd->uaol.dsrc_buf->stream, bytes + src_added_bytes); + + if (added_frames) + adjust_uaol_rate(dd, true); + + /* dma_buffer_copy_to() may do format conversion so + * dst_added_bytes may not be equal to src_added_bytes. + */ + size_t dst_added_bytes = added_frames * audio_stream_frame_bytes(&dd->dma_buffer->stream); + ret = dma_buffer_copy_to(dd->uaol.dsrc_buf, dd->dma_buffer, + dd->process, bytes + dst_added_bytes, dd->chmap); + } else if (dd->uaol.feedback_drift < 0) { + /* It is expected this func is called every 1 ms */ + dd->uaol.ms_since_last_adjustment++; + assert(dd->uaol.feedback_drift < 0 && dd->uaol.feedback_drift >= -1000); + if (-1000 / dd->uaol.feedback_drift >= dd->uaol.ms_since_last_adjustment) { + dd->uaol.ms_since_last_adjustment = 0; + adjust_uaol_rate(dd, false); + } + + ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer, + dd->process, bytes, dd->chmap); + } else + return -EINVAL; + + return ret; +} + +/* When the host setups two DMA links for UAOL playback gateway, that tells us the second + * DMA link is to read from the USB feedback endpoint. This function (re)setups the feedback + * DMA channel and buffer for such case. + */ +int setup_uaol_feedback_dma(struct dai_data *dd, struct comp_dev *dev) +{ + struct ipc_config_dai *dai = &dd->ipc_config; + struct dma_config *dma_cfg; + + dd->uaol.fb_chan_idx = -EINVAL; + dd->uaol.feedback_drift = 0; + dd->uaol.ms_since_last_adjustment = 0; + + if (dai->type != SOF_DAI_INTEL_UAOL || dai->direction != SOF_IPC_STREAM_PLAYBACK) + return 0; + + /* UAOL feedback is an optional 2nd DMA link (1st is audio DMA link) */ + assert(GTW_DMA_DEVICE_MAX_COUNT >= 2); + if (!dai->host_dma_config[1] || !dai->host_dma_config[1]->pre_allocated_by_host) { + comp_info(dev, "No UAOL feedback DMA link supplied by host."); + return 0; + } + + int channel = dai->host_dma_config[1]->dma_channel_id; + comp_dbg(dev, "UAOL feedback channel: %d", channel); + + /* USB feedback endpoint payload is 4 bytes. Hi-Speed USB microframe + * period is 125 us (8 per 1 ms). Double the buffer size just in case. + */ + dd->uaol.fb_dma_buf_size = 4 * 8 * 2; + + /* TODO: perhaps get alignment by reading DMA alignment attribute? */ + dd->uaol.fb_dma_buf = (uint32_t *)rballoc_align(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA, + dd->uaol.fb_dma_buf_size, 64); + if (!dd->uaol.fb_dma_buf) { + comp_err(dev, "UAOL feedback buffer allocation failed!"); + return -ENOMEM; + } + memset(dd->uaol.fb_dma_buf, 0, dd->uaol.fb_dma_buf_size); + + dma_cfg = rballoc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT | SOF_MEM_FLAG_DMA, + sizeof(struct dma_config)); + if (!dma_cfg) { + rfree(dd->uaol.fb_dma_buf); + dd->uaol.fb_dma_buf = NULL; + comp_err(dev, "dma_cfg allocation failed"); + return -ENOMEM; + } + + memset(dma_cfg, 0, sizeof(struct dma_config)); + dma_cfg->dma_slot = 0; + dma_cfg->channel_direction = PERIPHERAL_TO_MEMORY; + dma_cfg->source_data_size = 4; + dma_cfg->dest_data_size = 4; + dma_cfg->source_burst_length = 4; + dma_cfg->dest_burst_length = 4; + dma_cfg->cyclic = 1; + dma_cfg->block_count = 1; + + dma_cfg->head_block = rballoc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT | SOF_MEM_FLAG_DMA, + sizeof(struct dma_block_config)); + if (!dma_cfg->head_block) { + rfree(dma_cfg); + rfree(dd->uaol.fb_dma_buf); + dd->uaol.fb_dma_buf = NULL; + comp_err(dev, "dma_block_config allocation failed"); + return -ENOMEM; + } + + memset(dma_cfg->head_block, 0, sizeof(struct dma_block_config)); + dma_cfg->head_block->dest_scatter_en = 0; + dma_cfg->head_block->block_size = dd->uaol.fb_dma_buf_size; + dma_cfg->head_block->source_addr_adj = DMA_ADDR_ADJ_INCREMENT; + dma_cfg->head_block->dest_addr_adj = DMA_ADDR_ADJ_DECREMENT; /* WHY? IS THIS OK??? */ + dma_cfg->head_block->source_address = 0; + dma_cfg->head_block->dest_address = (uint32_t)dd->uaol.fb_dma_buf; + dma_cfg->head_block->next_block = dma_cfg->head_block; + dd->uaol.fb_z_config = dma_cfg; + + dd->uaol.fb_chan_idx = sof_dma_request_channel(dd->dma, channel); + if (dd->uaol.fb_chan_idx < 0) { + rfree(dma_cfg->head_block); + rfree(dma_cfg); + rfree(dd->uaol.fb_dma_buf); + dd->uaol.fb_dma_buf = NULL; + comp_err(dev, "dma_request_channel() failed"); + return -EIO; + } + + dsrc_init(&dd->uaol.dsrc, dai->gtw_fmt->channels_count); + + comp_dbg(dev, "New configured UAOL feedback DMA channel: %d", dd->uaol.fb_chan_idx); + + return 0; +} + +void uaol_free(struct dai_data *dd) +{ + if (dd->uaol.fb_z_config) { + rfree(dd->uaol.fb_z_config->head_block); + rfree(dd->uaol.fb_z_config); + dd->uaol.fb_z_config = NULL; + } + + if (dd->uaol.fb_dma_buf) { + rfree(dd->uaol.fb_dma_buf); + dd->uaol.fb_dma_buf = NULL; + dd->uaol.fb_dma_buf_size = 0; + } + + if (dd->uaol.dsrc_buf) { + buffer_free(dd->uaol.dsrc_buf); + dd->uaol.dsrc_buf = NULL; + } +} diff --git a/src/include/sof/audio/audio_stream.h b/src/include/sof/audio/audio_stream.h index dd81c157b8d8..5c6f15392800 100644 --- a/src/include/sof/audio/audio_stream.h +++ b/src/include/sof/audio/audio_stream.h @@ -66,6 +66,15 @@ struct audio_stream { struct sof_audio_stream_params runtime_stream_params; }; +/* A pointer to data in a ring buffer. Just for convenience to reduce the number of typical + * processing function parameters: e.g., just 3 parameters (in, out ptr, and size) instead of 7. + */ +struct cir_buf_ptr { + void *buf_start; + void *buf_end; + void *ptr; +}; + void audio_stream_recalc_align(struct audio_stream *stream); static inline void *audio_stream_get_rptr(const struct audio_stream *buf) diff --git a/src/include/sof/audio/dsrc.h b/src/include/sof/audio/dsrc.h new file mode 100644 index 000000000000..e68563b200fd --- /dev/null +++ b/src/include/sof/audio/dsrc.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 Intel Corporation. All rights reserved. + */ + +#ifndef __SOF_AUDIO_DSRC_H__ +#define __SOF_AUDIO_DSRC_H__ + +#include +#include +#include + +struct dsrc { + size_t channels; + int64_t previous_sample_norm[PLATFORM_MAX_CHANNELS]; + uint64_t phase_acc; + uint64_t max_phase; +}; + +void dsrc_init(struct dsrc *dsrc, size_t channels); +void dsrc_set_rate(struct dsrc *dsrc, uint32_t in_rate, uint32_t out_rate); +size_t dsrc_process(struct dsrc *dsrc, const struct cir_buf_ptr *in, + struct cir_buf_ptr *out, size_t frames); + +#endif /* __SOF_AUDIO_DSRC_H__ */ diff --git a/src/include/sof/audio/uaol.h b/src/include/sof/audio/uaol.h new file mode 100644 index 000000000000..f050b7aba254 --- /dev/null +++ b/src/include/sof/audio/uaol.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2026 Intel Corporation. All rights reserved. + */ + +#ifndef __SOF_AUDIO_UAOL_H__ +#define __SOF_AUDIO_UAOL_H__ + +#include +#include + +struct sof_tlv; +struct device; + +#if !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY +__cold void tlv_value_set_uaol_caps(struct sof_tlv *tuple, uint32_t type); +#endif /* !CONFIG_SOF_OS_LINUX_COMPAT_PRIORITY */ + +__cold int uaol_stream_id_to_hda_link_stream_id(int uaol_stream_id); + +const struct device *get_uaol_zdevice(int uaol_link_id); + +/* these are called from dai-zephyr.c */ + +struct dai; +struct comp_dev; +struct dai_data; + +int dai_get_uaol_stream_id(struct dai *dai, int *uaol_link_id, int *uaol_stream_id); + +void process_uaol_feedback(struct comp_dev *dev, struct dai_data *dd); + +void adjust_uaol_rate(const struct dai_data *dd, bool increase); + +int uaol_dma_buffer_copy_to(struct dai_data *dd, size_t bytes); + +int setup_uaol_feedback_dma(struct dai_data *dd, struct comp_dev *dev); + +void uaol_free(struct dai_data *dd); + +#endif /* __SOF_AUDIO_UAOL_H__ */ diff --git a/src/include/sof/ipc/topology.h b/src/include/sof/ipc/topology.h index 3503c7a407d8..ecea8b96eeab 100644 --- a/src/include/sof/ipc/topology.h +++ b/src/include/sof/ipc/topology.h @@ -56,6 +56,7 @@ int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma, bool *d int ipc4_process_on_core(uint32_t core, bool blocking); int ipc4_pipeline_complete(struct ipc *ipc, uint32_t comp_id, uint32_t cmd); int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint32_t size); +int ipc4_find_dma_config_tlv(struct ipc_config_dai *dai, uint8_t *data_buffer, size_t size); int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd); int ipc4_pipeline_trigger(struct ipc_comp_dev *ppl_icd, uint32_t cmd, bool *delayed); int ipc4_find_dma_config_multiple(struct ipc_config_dai *dai, uint8_t *data_buffer, diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index 595d11de9b47..0f1d12aba212 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -30,6 +30,9 @@ #include #include #include +#ifdef CONFIG_DAI_INTEL_UAOL +#include +#endif #include #include #include @@ -114,6 +117,24 @@ typedef int (*channel_copy_func)(const struct audio_stream *src, unsigned int sr struct audio_stream *dst, unsigned int dst_channel, unsigned int frames); +#ifdef CONFIG_DAI_INTEL_UAOL +struct uaol_dai_data { + int feedback_drift; + uint32_t ms_since_last_adjustment; + + int fb_chan_idx; + uint32_t *fb_dma_buf; + size_t fb_dma_buf_size; + struct dma_config *fb_z_config; + + struct dsrc dsrc; + struct comp_buffer *dsrc_buf; + + int link_id; + int stream_id; +}; +#endif + /** * \brief DAI runtime data */ @@ -148,6 +169,10 @@ struct dai_data { uint64_t wallclock; /* wall clock at stream start */ +#ifdef CONFIG_DAI_INTEL_UAOL + struct uaol_dai_data uaol; +#endif + /* * flag indicating two-step stop/pause for DAI comp and DAI DMA. * DAI stop occurs during STREAM_TRIG_STOP IPC and DMA stop during DAI_CONFIG IPC with diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index 58c08d9ec04b..4e7e43374a2a 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -28,6 +28,9 @@ #include #include #include +#ifdef CONFIG_DAI_INTEL_UAOL +#include +#endif #include "../audio/copier/copier.h" #include "../audio/copier/dai_copier.h" @@ -183,8 +186,11 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) dev->ipc_config.frame_fmt, dd->stream_id); break; +#ifdef CONFIG_DAI_INTEL_UAOL case SOF_DAI_INTEL_UAOL: + dai_get_uaol_stream_id(dd->dai, &dd->uaol.link_id, &dd->uaol.stream_id); break; +#endif default: /* other types of DAIs not handled for now */ comp_warn(dev, "Unknown dai type %d", dai->type); @@ -241,6 +247,14 @@ void dai_dma_release(struct dai_data *dd, struct comp_dev *dev) dma_release_channel(dd->dma->z_dev, dd->chan_index); dd->chan_index = -EINVAL; } + +#ifdef CONFIG_DAI_INTEL_UAOL + if (dd->uaol.fb_chan_idx >= 0) { + dma_stop(dd->dma->z_dev, dd->uaol.fb_chan_idx); + dma_release_channel(dd->dma->z_dev, dd->uaol.fb_chan_idx); + dd->uaol.fb_chan_idx = -EINVAL; + } +#endif } void dai_release_llp_slot(struct dai_data *dd) diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 8e3073ab7797..9938d74fb14f 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -1300,6 +1300,43 @@ int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint3 return IPC4_SUCCESS; } +/* Unlike the above ipc4_find_dma_config(), this can find multiple DMA configs. + * For example, a UAOL copier may use two DMA channels: one for audio and one + * for clock feedback. This function can only work when all data in data_buffer + * is in TLV format; however, this is not always the case for all gateway types. + * Therefore, the above ipc4_find_dma_config() is still used as it can skip non-TLV + * blob data at the beginning of data_buffer. + */ +int ipc4_find_dma_config_tlv(struct ipc_config_dai *dai, uint8_t *data_buffer, size_t size) +{ + uint8_t *end_addr = data_buffer + size; + struct sof_tlv *tlvs; + struct ipc_dma_config *dma_cfg; + int count = 0; + + for (tlvs = (struct sof_tlv *)data_buffer; (uint8_t *)tlvs < end_addr; + tlvs = tlv_next(tlvs)) { + dma_cfg = tlv_value_ptr_get(tlvs, GTW_DMA_CONFIG_ID); + if (!dma_cfg) + continue; + + if (count >= GTW_DMA_DEVICE_MAX_COUNT) { + tr_err(&ipc_tr, "Unexpected DMA config count %d, max %d", + count, GTW_DMA_DEVICE_MAX_COUNT); + return IPC4_INVALID_REQUEST; + } + + dai->host_dma_config[count++] = dma_cfg; + } + + if (count == 0) { + tr_err(&ipc_tr, "No DMA config found"); + return IPC4_INVALID_REQUEST; + } + + return IPC4_SUCCESS; +} + int ipc4_find_dma_config_multiple(struct ipc_config_dai *dai, uint8_t *data_buffer, uint32_t size, uint32_t device_id, int dma_cfg_idx) { diff --git a/test/ztest/unit/dsrc/CMakeLists.txt b/test/ztest/unit/dsrc/CMakeLists.txt new file mode 100644 index 000000000000..a198ace9f231 --- /dev/null +++ b/test/ztest/unit/dsrc/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(test_dsrc) + +set(SOF_ROOT "${PROJECT_SOURCE_DIR}/../../../..") + +# Include SOF CMake functions +include(${SOF_ROOT}/scripts/cmake/misc.cmake) + +target_include_directories(app PRIVATE + ${SOF_ROOT}/zephyr/include + ${SOF_ROOT}/src/include + ${SOF_ROOT}/src/platform/posix/include +) + +# Define SOF-specific configurations for unit testing +target_compile_definitions(app PRIVATE + -DCONFIG_ZEPHYR_POSIX=1 + -DTEST_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_sources(app PRIVATE + test_dsrc_ztest.c + ${SOF_ROOT}/src/audio/dsrc.c +) + +# Add RELATIVE_FILE definitions for SOF trace functionality +sof_append_relative_path_definitions(app) diff --git a/test/ztest/unit/dsrc/prj.conf b/test/ztest/unit/dsrc/prj.conf new file mode 100644 index 000000000000..d34c7781cd0a --- /dev/null +++ b/test/ztest/unit/dsrc/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_SOF_FULL_ZEPHYR_APPLICATION=n diff --git a/test/ztest/unit/dsrc/test_dsrc_ztest.c b/test/ztest/unit/dsrc/test_dsrc_ztest.c new file mode 100644 index 000000000000..04af734f50fb --- /dev/null +++ b/test/ztest/unit/dsrc/test_dsrc_ztest.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright 2026 Intel Corporation. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include + +/* 200 seconds stereo */ +#define NUM_SAMPLES (48000 * 2 * 200) +static int32_t in_buf[NUM_SAMPLES], out_buf[NUM_SAMPLES]; + +/** + * @brief Read int32_t values from a text file, one number per line. + * + * @param path Path to the input text file. + * @param buf Destination array for the read values. + * @param max Maximum number of elements that fit in @a buf. + * @return Number of values actually read, or negative on error. + */ +static int read_data_from_file(const char *path, int32_t *buf, size_t max) +{ + FILE *f = fopen(path, "r"); + + if (!f) + return -1; + + size_t count = 0; + char line[64]; + + while (count < max && fgets(line, sizeof(line), f)) { + char *end; + long val = strtol(line, &end, 10); + + if (end == line) /* skip blank / non-numeric lines */ + continue; + buf[count++] = (int32_t)val; + } + + fclose(f); + return (int)count; +} + +/** + * @brief Write int32_t values to a text file, one number per line. + * + * @param path Path to the output text file. + * @param buf Source array of values to write. + * @param count Number of elements to write. + * @return 0 on success, negative on error. + */ +static int write_data_to_file(const char *path, const int32_t *buf, size_t count) +{ + FILE *f = fopen(path, "w"); + + if (!f) + return -1; + + for (size_t i = 0; i < count; i++) + fprintf(f, "%d\n", buf[i]); + + fclose(f); + return 0; +} + +/** + * @brief Compare two text files line by line for equality. + * + * @param path_a Path to the first file. + * @param path_b Path to the second file (expected / reference). + * @return 0 when the files are identical, or the 1-based line number + * of the first mismatch. Returns -1 on open/read error. + */ +static int compare_data_files(const char *path_a, const char *path_b) +{ + FILE *fa = fopen(path_a, "r"); + FILE *fb = fopen(path_b, "r"); + + if (!fa || !fb) { + if (fa) + fclose(fa); + if (fb) + fclose(fb); + return -1; + } + + char line_a[64]; + char line_b[64]; + int line = 1; + + while (true) { + char *a = fgets(line_a, sizeof(line_a), fa); + char *b = fgets(line_b, sizeof(line_b), fb); + + if (!a && !b) /* both reached EOF at the same time */ + break; + + if (!a || !b || strcmp(line_a, line_b) != 0) { + fclose(fa); + fclose(fb); + return line; /* first mismatching line (1-based) */ + } + line++; + } + + fclose(fa); + fclose(fb); + return 0; +} + +/* Just to avoid dependency on components.c, copy-paste impl here */ +void cir_buf_copy(void *src, void *src_addr, void *src_end, void *dst, + void *dst_addr, void *dst_end, size_t byte_size) +{ + size_t bytes = byte_size; + size_t bytes_src; + size_t bytes_dst; + size_t bytes_copied; + uint8_t *in = (uint8_t *)src; + uint8_t *out = (uint8_t *)dst; + + while (bytes) { + bytes_src = cir_buf_bytes_without_wrap(in, src_end); + bytes_dst = cir_buf_bytes_without_wrap(out, dst_end); + bytes_copied = MIN(bytes_src, bytes_dst); + bytes_copied = MIN(bytes, bytes_copied); + memcpy_s(out, bytes_copied, in, bytes_copied); + bytes -= bytes_copied; + in = cir_buf_wrap(in + bytes_copied, src_addr, src_end); + out = cir_buf_wrap(out + bytes_copied, dst_addr, dst_end); + } +} + +/**************************** Test cases *******************************/ + +ZTEST(dsrc_suite, test_48000_48000) +{ + struct dsrc dsrc; + dsrc_init(&dsrc, 2); + dsrc_set_rate(&dsrc, 48000, 48000); + + struct cir_buf_ptr in = { in_buf, &in_buf[NUM_SAMPLES], in_buf }; + struct cir_buf_ptr out = { out_buf, &out_buf[NUM_SAMPLES], out_buf }; + size_t added_frames = dsrc_process(&dsrc, &in, &out, 48000 * 100); + + /* same frequencies: zero added frames expected */ + zassert_equal(added_frames, 0); +} + +ZTEST(dsrc_suite, test_48000_48007) +{ + struct dsrc dsrc; + dsrc_init(&dsrc, 2); + dsrc_set_rate(&dsrc, 48000, 48007); + + struct cir_buf_ptr in = { in_buf, &in_buf[NUM_SAMPLES], in_buf }; + struct cir_buf_ptr out = { out_buf, &out_buf[NUM_SAMPLES], out_buf }; + size_t added_frames = dsrc_process(&dsrc, &in, &out, 48000 * 100); + + /* 7 added frames per each input second are expected */ + zassert_equal(added_frames, 7 * 100); +} + +ZTEST(dsrc_suite, test_48000_48007_1ms_chunks) +{ + struct dsrc dsrc; + dsrc_init(&dsrc, 2); + dsrc_set_rate(&dsrc, 48000, 48007); + + size_t frames = 48000 * 100; + size_t total_added_frames = 0; + + struct cir_buf_ptr in = { in_buf, &in_buf[48 * 2], in_buf }; + struct cir_buf_ptr out = { out_buf, &out_buf[48 * 2 + 2], out_buf }; + + while (frames) { + size_t added_frames = dsrc_process(&dsrc, &in, &out, 48); + /* with 1 ms chunks and small freq diff, periodically one extra frame is added */ + zassert_true(added_frames == 0 || added_frames == 1); + total_added_frames += added_frames; + frames -= 48; + } + + /* 7 added frames per each input second are expected */ + zassert_equal(total_added_frames, 7 * 100); +} + +ZTEST(dsrc_suite, test_file_48000_48000) +{ + int n = read_data_from_file(TEST_DATA_DIR "/test_input.txt", in_buf, NUM_SAMPLES); + zassert_true(n > 0, "failed to read test input data"); + + struct dsrc dsrc; + dsrc_init(&dsrc, 2); + dsrc_set_rate(&dsrc, 48000, 48000); + + struct cir_buf_ptr in = { in_buf, &in_buf[NUM_SAMPLES], in_buf }; + struct cir_buf_ptr out = { out_buf, &out_buf[NUM_SAMPLES], out_buf }; + size_t added_frames = dsrc_process(&dsrc, &in, &out, n / 2); + + /* same frequencies: zero added frames expected */ + zassert_equal(added_frames, 0); + + int ret = write_data_to_file(TEST_DATA_DIR "/test_output_1.txt", out_buf, n + added_frames * 2); + zassert_equal(ret, 0, "failed to write test output data"); + + /* no resampling: output should match input */ + int diff = compare_data_files(TEST_DATA_DIR "/test_input.txt", TEST_DATA_DIR "/test_output_1.txt"); + zassert_equal(diff, 0, "test output differs from expected at line %d", diff); +} + +ZTEST(dsrc_suite, test_file_100_102) +{ + int n = read_data_from_file(TEST_DATA_DIR "/test_input.txt", in_buf, NUM_SAMPLES); + zassert_true(n > 0, "failed to read test input data"); + + struct dsrc dsrc; + dsrc_init(&dsrc, 1); + dsrc_set_rate(&dsrc, 100, 102); + + struct cir_buf_ptr in = { in_buf, &in_buf[NUM_SAMPLES], in_buf }; + struct cir_buf_ptr out = { out_buf, &out_buf[NUM_SAMPLES], out_buf }; + size_t added_frames = dsrc_process(&dsrc, &in, &out, n); + + /* 2 added frames per each input second are expected */ + zassert_equal(added_frames, (double)n / 100 * 2); + + int ret = write_data_to_file(TEST_DATA_DIR "/test_output_2.txt", out_buf, n + added_frames); + zassert_equal(ret, 0, "failed to write test output data"); + + /* compare output with expected data */ + int diff = compare_data_files(TEST_DATA_DIR "/test_output_2.txt", TEST_DATA_DIR "/test_expected_2.txt"); + zassert_equal(diff, 0, "test output differs from expected at line %d", diff); +} + +ZTEST_SUITE(dsrc_suite, NULL, NULL, NULL, NULL, NULL); diff --git a/test/ztest/unit/dsrc/test_expected_2.txt b/test/ztest/unit/dsrc/test_expected_2.txt new file mode 100644 index 000000000000..2119b7f7adb8 --- /dev/null +++ b/test/ztest/unit/dsrc/test_expected_2.txt @@ -0,0 +1,1020 @@ +100 +198 +296 +394 +492 +590 +688 +786 +884 +982 +1080 +1178 +1276 +1374 +1472 +1570 +1668 +1766 +1864 +1962 +2060 +2158 +2256 +2354 +2452 +2550 +2648 +2746 +2844 +2942 +3040 +3138 +3236 +3334 +3432 +3530 +3628 +3726 +3824 +3922 +4020 +4118 +4216 +4314 +4412 +4510 +4608 +4706 +4804 +4902 +5000 +5100 +5198 +5296 +5394 +5492 +5590 +5688 +5786 +5884 +5982 +6080 +6178 +6276 +6374 +6472 +6570 +6668 +6766 +6864 +6962 +7060 +7158 +7256 +7354 +7452 +7550 +7648 +7746 +7844 +7942 +8040 +8138 +8236 +8334 +8432 +8530 +8628 +8726 +8824 +8922 +9020 +9118 +9216 +9314 +9412 +9510 +9608 +9706 +9804 +9902 +10000 +10100 +10198 +10296 +10394 +10492 +10590 +10688 +10786 +10884 +10982 +11080 +11178 +11276 +11374 +11472 +11570 +11668 +11766 +11864 +11962 +12060 +12158 +12256 +12354 +12452 +12550 +12648 +12746 +12844 +12942 +13040 +13138 +13236 +13334 +13432 +13530 +13628 +13726 +13824 +13922 +14020 +14118 +14216 +14314 +14412 +14510 +14608 +14706 +14804 +14902 +15000 +15100 +15198 +15296 +15394 +15492 +15590 +15688 +15786 +15884 +15982 +16080 +16178 +16276 +16374 +16472 +16570 +16668 +16766 +16864 +16962 +17060 +17158 +17256 +17354 +17452 +17550 +17648 +17746 +17844 +17942 +18040 +18138 +18236 +18334 +18432 +18530 +18628 +18726 +18824 +18922 +19020 +19118 +19216 +19314 +19412 +19510 +19608 +19706 +19804 +19902 +20000 +20100 +20198 +20296 +20394 +20492 +20590 +20688 +20786 +20884 +20982 +21080 +21178 +21276 +21374 +21472 +21570 +21668 +21766 +21864 +21962 +22060 +22158 +22256 +22354 +22452 +22550 +22648 +22746 +22844 +22942 +23040 +23138 +23236 +23334 +23432 +23530 +23628 +23726 +23824 +23922 +24020 +24118 +24216 +24314 +24412 +24510 +24608 +24706 +24804 +24902 +25000 +25100 +25198 +25296 +25394 +25492 +25590 +25688 +25786 +25884 +25982 +26080 +26178 +26276 +26374 +26472 +26570 +26668 +26766 +26864 +26962 +27060 +27158 +27256 +27354 +27452 +27550 +27648 +27746 +27844 +27942 +28040 +28138 +28236 +28334 +28432 +28530 +28628 +28726 +28824 +28922 +29020 +29118 +29216 +29314 +29412 +29510 +29608 +29706 +29804 +29902 +30000 +30100 +30198 +30296 +30394 +30492 +30590 +30688 +30786 +30884 +30982 +31080 +31178 +31276 +31374 +31472 +31570 +31668 +31766 +31864 +31962 +32060 +32158 +32256 +32354 +32452 +32550 +32648 +32746 +32844 +32942 +33040 +33138 +33236 +33334 +33432 +33530 +33628 +33726 +33824 +33922 +34020 +34118 +34216 +34314 +34412 +34510 +34608 +34706 +34804 +34902 +35000 +35100 +35198 +35296 +35394 +35492 +35590 +35688 +35786 +35884 +35982 +36080 +36178 +36276 +36374 +36472 +36570 +36668 +36766 +36864 +36962 +37060 +37158 +37256 +37354 +37452 +37550 +37648 +37746 +37844 +37942 +38040 +38138 +38236 +38334 +38432 +38530 +38628 +38726 +38824 +38922 +39020 +39118 +39216 +39314 +39412 +39510 +39608 +39706 +39804 +39902 +40000 +40100 +40198 +40296 +40394 +40492 +40590 +40688 +40786 +40884 +40982 +41080 +41178 +41276 +41374 +41472 +41570 +41668 +41766 +41864 +41962 +42060 +42158 +42256 +42354 +42452 +42550 +42648 +42746 +42844 +42942 +43040 +43138 +43236 +43334 +43432 +43530 +43628 +43726 +43824 +43922 +44020 +44118 +44216 +44314 +44412 +44510 +44608 +44706 +44804 +44902 +45000 +45100 +45198 +45296 +45394 +45492 +45590 +45688 +45786 +45884 +45982 +46080 +46178 +46276 +46374 +46472 +46570 +46668 +46766 +46864 +46962 +47060 +47158 +47256 +47354 +47452 +47550 +47648 +47746 +47844 +47942 +48040 +48138 +48236 +48334 +48432 +48530 +48628 +48726 +48824 +48922 +49020 +49118 +49216 +49314 +49412 +49510 +49608 +49706 +49804 +49902 +50000 +50100 +50198 +50296 +50394 +50492 +50590 +50688 +50786 +50884 +50982 +51080 +51178 +51276 +51374 +51472 +51570 +51668 +51766 +51864 +51962 +52060 +52158 +52256 +52354 +52452 +52550 +52648 +52746 +52844 +52942 +53040 +53138 +53236 +53334 +53432 +53530 +53628 +53726 +53824 +53922 +54020 +54118 +54216 +54314 +54412 +54510 +54608 +54706 +54804 +54902 +55000 +55100 +55198 +55296 +55394 +55492 +55590 +55688 +55786 +55884 +55982 +56080 +56178 +56276 +56374 +56472 +56570 +56668 +56766 +56864 +56962 +57060 +57158 +57256 +57354 +57452 +57550 +57648 +57746 +57844 +57942 +58040 +58138 +58236 +58334 +58432 +58530 +58628 +58726 +58824 +58922 +59020 +59118 +59216 +59314 +59412 +59510 +59608 +59706 +59804 +59902 +60000 +60100 +60198 +60296 +60394 +60492 +60590 +60688 +60786 +60884 +60982 +61080 +61178 +61276 +61374 +61472 +61570 +61668 +61766 +61864 +61962 +62060 +62158 +62256 +62354 +62452 +62550 +62648 +62746 +62844 +62942 +63040 +63138 +63236 +63334 +63432 +63530 +63628 +63726 +63824 +63922 +64020 +64118 +64216 +64314 +64412 +64510 +64608 +64706 +64804 +64902 +65000 +65100 +65198 +65296 +65394 +65492 +65590 +65688 +65786 +65884 +65982 +66080 +66178 +66276 +66374 +66472 +66570 +66668 +66766 +66864 +66962 +67060 +67158 +67256 +67354 +67452 +67550 +67648 +67746 +67844 +67942 +68040 +68138 +68236 +68334 +68432 +68530 +68628 +68726 +68824 +68922 +69020 +69118 +69216 +69314 +69412 +69510 +69608 +69706 +69804 +69902 +70000 +70100 +70198 +70296 +70394 +70492 +70590 +70688 +70786 +70884 +70982 +71080 +71178 +71276 +71374 +71472 +71570 +71668 +71766 +71864 +71962 +72060 +72158 +72256 +72354 +72452 +72550 +72648 +72746 +72844 +72942 +73040 +73138 +73236 +73334 +73432 +73530 +73628 +73726 +73824 +73922 +74020 +74118 +74216 +74314 +74412 +74510 +74608 +74706 +74804 +74902 +75000 +75100 +75198 +75296 +75394 +75492 +75590 +75688 +75786 +75884 +75982 +76080 +76178 +76276 +76374 +76472 +76570 +76668 +76766 +76864 +76962 +77060 +77158 +77256 +77354 +77452 +77550 +77648 +77746 +77844 +77942 +78040 +78138 +78236 +78334 +78432 +78530 +78628 +78726 +78824 +78922 +79020 +79118 +79216 +79314 +79412 +79510 +79608 +79706 +79804 +79902 +80000 +80100 +80198 +80296 +80394 +80492 +80590 +80688 +80786 +80884 +80982 +81080 +81178 +81276 +81374 +81472 +81570 +81668 +81766 +81864 +81962 +82060 +82158 +82256 +82354 +82452 +82550 +82648 +82746 +82844 +82942 +83040 +83138 +83236 +83334 +83432 +83530 +83628 +83726 +83824 +83922 +84020 +84118 +84216 +84314 +84412 +84510 +84608 +84706 +84804 +84902 +85000 +85100 +85198 +85296 +85394 +85492 +85590 +85688 +85786 +85884 +85982 +86080 +86178 +86276 +86374 +86472 +86570 +86668 +86766 +86864 +86962 +87060 +87158 +87256 +87354 +87452 +87550 +87648 +87746 +87844 +87942 +88040 +88138 +88236 +88334 +88432 +88530 +88628 +88726 +88824 +88922 +89020 +89118 +89216 +89314 +89412 +89510 +89608 +89706 +89804 +89902 +90000 +90100 +90198 +90296 +90394 +90492 +90590 +90688 +90786 +90884 +90982 +91080 +91178 +91276 +91374 +91472 +91570 +91668 +91766 +91864 +91962 +92060 +92158 +92256 +92354 +92452 +92550 +92648 +92746 +92844 +92942 +93040 +93138 +93236 +93334 +93432 +93530 +93628 +93726 +93824 +93922 +94020 +94118 +94216 +94314 +94412 +94510 +94608 +94706 +94804 +94902 +95000 +95100 +95198 +95296 +95394 +95492 +95590 +95688 +95786 +95884 +95982 +96080 +96178 +96276 +96374 +96472 +96570 +96668 +96766 +96864 +96962 +97060 +97158 +97256 +97354 +97452 +97550 +97648 +97746 +97844 +97942 +98040 +98138 +98236 +98334 +98432 +98530 +98628 +98726 +98824 +98922 +99020 +99118 +99216 +99314 +99412 +99510 +99608 +99706 +99804 +99902 +100000 diff --git a/test/ztest/unit/dsrc/test_input.txt b/test/ztest/unit/dsrc/test_input.txt new file mode 100644 index 000000000000..61b08f4f6e18 --- /dev/null +++ b/test/ztest/unit/dsrc/test_input.txt @@ -0,0 +1,1000 @@ +100 +200 +300 +400 +500 +600 +700 +800 +900 +1000 +1100 +1200 +1300 +1400 +1500 +1600 +1700 +1800 +1900 +2000 +2100 +2200 +2300 +2400 +2500 +2600 +2700 +2800 +2900 +3000 +3100 +3200 +3300 +3400 +3500 +3600 +3700 +3800 +3900 +4000 +4100 +4200 +4300 +4400 +4500 +4600 +4700 +4800 +4900 +5000 +5100 +5200 +5300 +5400 +5500 +5600 +5700 +5800 +5900 +6000 +6100 +6200 +6300 +6400 +6500 +6600 +6700 +6800 +6900 +7000 +7100 +7200 +7300 +7400 +7500 +7600 +7700 +7800 +7900 +8000 +8100 +8200 +8300 +8400 +8500 +8600 +8700 +8800 +8900 +9000 +9100 +9200 +9300 +9400 +9500 +9600 +9700 +9800 +9900 +10000 +10100 +10200 +10300 +10400 +10500 +10600 +10700 +10800 +10900 +11000 +11100 +11200 +11300 +11400 +11500 +11600 +11700 +11800 +11900 +12000 +12100 +12200 +12300 +12400 +12500 +12600 +12700 +12800 +12900 +13000 +13100 +13200 +13300 +13400 +13500 +13600 +13700 +13800 +13900 +14000 +14100 +14200 +14300 +14400 +14500 +14600 +14700 +14800 +14900 +15000 +15100 +15200 +15300 +15400 +15500 +15600 +15700 +15800 +15900 +16000 +16100 +16200 +16300 +16400 +16500 +16600 +16700 +16800 +16900 +17000 +17100 +17200 +17300 +17400 +17500 +17600 +17700 +17800 +17900 +18000 +18100 +18200 +18300 +18400 +18500 +18600 +18700 +18800 +18900 +19000 +19100 +19200 +19300 +19400 +19500 +19600 +19700 +19800 +19900 +20000 +20100 +20200 +20300 +20400 +20500 +20600 +20700 +20800 +20900 +21000 +21100 +21200 +21300 +21400 +21500 +21600 +21700 +21800 +21900 +22000 +22100 +22200 +22300 +22400 +22500 +22600 +22700 +22800 +22900 +23000 +23100 +23200 +23300 +23400 +23500 +23600 +23700 +23800 +23900 +24000 +24100 +24200 +24300 +24400 +24500 +24600 +24700 +24800 +24900 +25000 +25100 +25200 +25300 +25400 +25500 +25600 +25700 +25800 +25900 +26000 +26100 +26200 +26300 +26400 +26500 +26600 +26700 +26800 +26900 +27000 +27100 +27200 +27300 +27400 +27500 +27600 +27700 +27800 +27900 +28000 +28100 +28200 +28300 +28400 +28500 +28600 +28700 +28800 +28900 +29000 +29100 +29200 +29300 +29400 +29500 +29600 +29700 +29800 +29900 +30000 +30100 +30200 +30300 +30400 +30500 +30600 +30700 +30800 +30900 +31000 +31100 +31200 +31300 +31400 +31500 +31600 +31700 +31800 +31900 +32000 +32100 +32200 +32300 +32400 +32500 +32600 +32700 +32800 +32900 +33000 +33100 +33200 +33300 +33400 +33500 +33600 +33700 +33800 +33900 +34000 +34100 +34200 +34300 +34400 +34500 +34600 +34700 +34800 +34900 +35000 +35100 +35200 +35300 +35400 +35500 +35600 +35700 +35800 +35900 +36000 +36100 +36200 +36300 +36400 +36500 +36600 +36700 +36800 +36900 +37000 +37100 +37200 +37300 +37400 +37500 +37600 +37700 +37800 +37900 +38000 +38100 +38200 +38300 +38400 +38500 +38600 +38700 +38800 +38900 +39000 +39100 +39200 +39300 +39400 +39500 +39600 +39700 +39800 +39900 +40000 +40100 +40200 +40300 +40400 +40500 +40600 +40700 +40800 +40900 +41000 +41100 +41200 +41300 +41400 +41500 +41600 +41700 +41800 +41900 +42000 +42100 +42200 +42300 +42400 +42500 +42600 +42700 +42800 +42900 +43000 +43100 +43200 +43300 +43400 +43500 +43600 +43700 +43800 +43900 +44000 +44100 +44200 +44300 +44400 +44500 +44600 +44700 +44800 +44900 +45000 +45100 +45200 +45300 +45400 +45500 +45600 +45700 +45800 +45900 +46000 +46100 +46200 +46300 +46400 +46500 +46600 +46700 +46800 +46900 +47000 +47100 +47200 +47300 +47400 +47500 +47600 +47700 +47800 +47900 +48000 +48100 +48200 +48300 +48400 +48500 +48600 +48700 +48800 +48900 +49000 +49100 +49200 +49300 +49400 +49500 +49600 +49700 +49800 +49900 +50000 +50100 +50200 +50300 +50400 +50500 +50600 +50700 +50800 +50900 +51000 +51100 +51200 +51300 +51400 +51500 +51600 +51700 +51800 +51900 +52000 +52100 +52200 +52300 +52400 +52500 +52600 +52700 +52800 +52900 +53000 +53100 +53200 +53300 +53400 +53500 +53600 +53700 +53800 +53900 +54000 +54100 +54200 +54300 +54400 +54500 +54600 +54700 +54800 +54900 +55000 +55100 +55200 +55300 +55400 +55500 +55600 +55700 +55800 +55900 +56000 +56100 +56200 +56300 +56400 +56500 +56600 +56700 +56800 +56900 +57000 +57100 +57200 +57300 +57400 +57500 +57600 +57700 +57800 +57900 +58000 +58100 +58200 +58300 +58400 +58500 +58600 +58700 +58800 +58900 +59000 +59100 +59200 +59300 +59400 +59500 +59600 +59700 +59800 +59900 +60000 +60100 +60200 +60300 +60400 +60500 +60600 +60700 +60800 +60900 +61000 +61100 +61200 +61300 +61400 +61500 +61600 +61700 +61800 +61900 +62000 +62100 +62200 +62300 +62400 +62500 +62600 +62700 +62800 +62900 +63000 +63100 +63200 +63300 +63400 +63500 +63600 +63700 +63800 +63900 +64000 +64100 +64200 +64300 +64400 +64500 +64600 +64700 +64800 +64900 +65000 +65100 +65200 +65300 +65400 +65500 +65600 +65700 +65800 +65900 +66000 +66100 +66200 +66300 +66400 +66500 +66600 +66700 +66800 +66900 +67000 +67100 +67200 +67300 +67400 +67500 +67600 +67700 +67800 +67900 +68000 +68100 +68200 +68300 +68400 +68500 +68600 +68700 +68800 +68900 +69000 +69100 +69200 +69300 +69400 +69500 +69600 +69700 +69800 +69900 +70000 +70100 +70200 +70300 +70400 +70500 +70600 +70700 +70800 +70900 +71000 +71100 +71200 +71300 +71400 +71500 +71600 +71700 +71800 +71900 +72000 +72100 +72200 +72300 +72400 +72500 +72600 +72700 +72800 +72900 +73000 +73100 +73200 +73300 +73400 +73500 +73600 +73700 +73800 +73900 +74000 +74100 +74200 +74300 +74400 +74500 +74600 +74700 +74800 +74900 +75000 +75100 +75200 +75300 +75400 +75500 +75600 +75700 +75800 +75900 +76000 +76100 +76200 +76300 +76400 +76500 +76600 +76700 +76800 +76900 +77000 +77100 +77200 +77300 +77400 +77500 +77600 +77700 +77800 +77900 +78000 +78100 +78200 +78300 +78400 +78500 +78600 +78700 +78800 +78900 +79000 +79100 +79200 +79300 +79400 +79500 +79600 +79700 +79800 +79900 +80000 +80100 +80200 +80300 +80400 +80500 +80600 +80700 +80800 +80900 +81000 +81100 +81200 +81300 +81400 +81500 +81600 +81700 +81800 +81900 +82000 +82100 +82200 +82300 +82400 +82500 +82600 +82700 +82800 +82900 +83000 +83100 +83200 +83300 +83400 +83500 +83600 +83700 +83800 +83900 +84000 +84100 +84200 +84300 +84400 +84500 +84600 +84700 +84800 +84900 +85000 +85100 +85200 +85300 +85400 +85500 +85600 +85700 +85800 +85900 +86000 +86100 +86200 +86300 +86400 +86500 +86600 +86700 +86800 +86900 +87000 +87100 +87200 +87300 +87400 +87500 +87600 +87700 +87800 +87900 +88000 +88100 +88200 +88300 +88400 +88500 +88600 +88700 +88800 +88900 +89000 +89100 +89200 +89300 +89400 +89500 +89600 +89700 +89800 +89900 +90000 +90100 +90200 +90300 +90400 +90500 +90600 +90700 +90800 +90900 +91000 +91100 +91200 +91300 +91400 +91500 +91600 +91700 +91800 +91900 +92000 +92100 +92200 +92300 +92400 +92500 +92600 +92700 +92800 +92900 +93000 +93100 +93200 +93300 +93400 +93500 +93600 +93700 +93800 +93900 +94000 +94100 +94200 +94300 +94400 +94500 +94600 +94700 +94800 +94900 +95000 +95100 +95200 +95300 +95400 +95500 +95600 +95700 +95800 +95900 +96000 +96100 +96200 +96300 +96400 +96500 +96600 +96700 +96800 +96900 +97000 +97100 +97200 +97300 +97400 +97500 +97600 +97700 +97800 +97900 +98000 +98100 +98200 +98300 +98400 +98500 +98600 +98700 +98800 +98900 +99000 +99100 +99200 +99300 +99400 +99500 +99600 +99700 +99800 +99900 +100000 diff --git a/test/ztest/unit/dsrc/testcase.yaml b/test/ztest/unit/dsrc/testcase.yaml new file mode 100644 index 000000000000..3a5c8bfe6f77 --- /dev/null +++ b/test/ztest/unit/dsrc/testcase.yaml @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright 2026 Intel Corporation. All rights reserved. + +tests: + sof.unit.dsrc: + tags: dsrc + platform_allow: native_sim + integration_platforms: + - native_sim + build_only: false diff --git a/west.yml b/west.yml index faf374b914fb..fe9ebf70548d 100644 --- a/west.yml +++ b/west.yml @@ -11,6 +11,8 @@ manifest: url-base: https://github.com/thesofproject - name: zephyrproject url-base: https://github.com/zephyrproject-rtos + - name: sk + url-base: https://github.com/serhiy-katsyuba-intel # When upgrading projects here please run git log --oneline in the # project and if not too long then include the output in your commit @@ -43,8 +45,8 @@ manifest: - name: zephyr repo-path: zephyr - revision: c162980efd9ad8616d0e2fe886ca917d8d8d240a - remote: zephyrproject + revision: uaol_fb2 + remote: sk # Import some projects listed in zephyr/west.yml@revision #