From 72345ca64b31889dd360ffb4bad98c87646b24fe Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Fri, 17 Apr 2026 19:44:55 +0200 Subject: [PATCH 1/5] uaol: audio: introduce DSRC This implements a DSRC (Drift-compensating adaptive Sample Rate Converter) for use with the UAOL feedback feature to perform audio resampling and compensate for small dynamic drift. The implementation employs linear interpolation. Signed-off-by: Serhiy Katsyuba --- src/audio/dsrc.c | 92 ++++++++++++++++++++++++++++++++++++ src/include/sof/audio/dsrc.h | 25 ++++++++++ 2 files changed, 117 insertions(+) create mode 100644 src/audio/dsrc.c create mode 100644 src/include/sof/audio/dsrc.h 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/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__ */ From b88f705b5f0f3ab13b29771298bf46c5abf96259 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Mon, 27 Apr 2026 18:09:14 +0200 Subject: [PATCH 2/5] test: uaol: add DSRC unit tests This adds unit tests for DSRC using Zephyr's ztest framework. Signed-off-by: Serhiy Katsyuba --- test/ztest/unit/dsrc/CMakeLists.txt | 29 + test/ztest/unit/dsrc/prj.conf | 2 + test/ztest/unit/dsrc/test_dsrc_ztest.c | 240 +++++ test/ztest/unit/dsrc/test_expected_2.txt | 1020 ++++++++++++++++++++++ test/ztest/unit/dsrc/test_input.txt | 1000 +++++++++++++++++++++ test/ztest/unit/dsrc/testcase.yaml | 11 + 6 files changed, 2302 insertions(+) create mode 100644 test/ztest/unit/dsrc/CMakeLists.txt create mode 100644 test/ztest/unit/dsrc/prj.conf create mode 100644 test/ztest/unit/dsrc/test_dsrc_ztest.c create mode 100644 test/ztest/unit/dsrc/test_expected_2.txt create mode 100644 test/ztest/unit/dsrc/test_input.txt create mode 100644 test/ztest/unit/dsrc/testcase.yaml 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..1f8556f1ae95 --- /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(const void *src, const void *src_addr, const 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 From 87cd82e2af87426ed9f28042ca44a98ddc50cea2 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Tue, 10 Mar 2026 11:22:50 +0100 Subject: [PATCH 3/5] uaol: add UAOL feedback support This extends UAOL functionality to support audio rate adjustment based on the "desired" clock reported by the USB playback device via the USB feedback endpoint. The firmware calculates drift from this feedback and instructs UAOL hardware to increase or decrease the transfer rate accordingly. A DSRC (Drift-compensating adaptive Sample Rate Converter) is used when necessary to perform audio resampling and compensate for small dynamic drift. Signed-off-by: Serhiy Katsyuba --- src/audio/CMakeLists.txt | 2 +- src/audio/dai-zephyr.c | 167 +++++++++++++++-- src/audio/intel_uaol.c | 287 +++++++++++++++++++++++++++++ src/include/sof/audio/intel_uaol.h | 21 +++ src/include/sof/lib/dai-zephyr.h | 25 +++ src/ipc/ipc4/dai.c | 14 ++ src/lib/dai.c | 2 +- 7 files changed, 498 insertions(+), 20 deletions(-) diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index 92002c8b7c1c..56604d514cda 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -130,7 +130,7 @@ if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) add_subdirectory(tone) endif() if(CONFIG_UAOL_INTEL_ADSP) - add_local_sources(sof intel_uaol.c) + add_local_sources(sof intel_uaol.c dsrc.c) endif() if(CONFIG_ZEPHYR_NATIVE_DRIVERS) list(APPEND base_files host-zephyr.c) diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 9f4e5dc57295..0b40aa05edb3 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -45,6 +45,10 @@ #include #include +#ifdef CONFIG_UAOL_INTEL_ADSP +#include +#include +#endif #include @@ -392,8 +396,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_UAOL_INTEL_ADSP + if (dd->uaol.feedback_drift) + ret = uaol_dma_buffer_copy_to(dd, bytes); + else +#endif /* CONFIG_UAOL_INTEL_ADSP */ + 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); /* @@ -475,6 +485,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_UAOL_INTEL_ADSP + if (dd->uaol.fb_chan_idx >= 0) + process_uaol_feedback(dev, dd); +#endif /* CONFIG_UAOL_INTEL_ADSP */ + #ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS /* Increment performance counters */ io_perf_monitor_update_data(dd->io_perf_dai_byte_count, bytes); @@ -633,6 +649,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) @@ -689,11 +774,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); @@ -701,6 +782,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) @@ -1183,8 +1268,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 intel_uaol.c, but + * there is no easy access to "params" there to set up the buffer format. + */ +#ifdef CONFIG_UAOL_INTEL_ADSP + /* 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_UAOL_INTEL_ADSP */ + out: /* * Make sure to free all allocated items, all functions @@ -1250,6 +1360,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_UAOL_INTEL_ADSP + /* Does nothing if feedback DMA is not needed */ + setup_uaol_feedback_dma(dd, dev); +#endif /* CONFIG_UAOL_INTEL_ADSP */ + return 0; } @@ -1273,6 +1388,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_UAOL_INTEL_ADSP + if (dd->uaol.fb_dma_buf) + memset(dd->uaol.fb_dma_buf, 0, dd->uaol.fb_dma_buf_size); +#endif /* CONFIG_UAOL_INTEL_ADSP */ /* dma reconfig not required if XRUN handling */ if (dd->xrun) { @@ -1281,7 +1400,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); @@ -1332,6 +1451,10 @@ void dai_common_reset(struct dai_data *dd, struct comp_dev *dev) dd->dma_buffer = NULL; } +#ifdef CONFIG_UAOL_INTEL_ADSP + uaol_free(dd); +#endif /* CONFIG_UAOL_INTEL_ADSP */ + dd->wallclock = 0; dd->total_data_processed = 0; dd->xrun = 0; @@ -1368,7 +1491,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; @@ -1389,6 +1512,14 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, buffer_zero(dd->dma_buffer); } +#ifdef CONFIG_UAOL_INTEL_ADSP + /* 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_UAOL_INTEL_ADSP */ + /* 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 @@ -1406,16 +1537,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; @@ -1443,11 +1574,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; @@ -1457,11 +1588,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: @@ -1892,7 +2023,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/intel_uaol.c b/src/audio/intel_uaol.c index baeb4a217103..c94c2c337cd3 100644 --- a/src/audio/intel_uaol.c +++ b/src/audio/intel_uaol.c @@ -7,6 +7,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(uaol, CONFIG_SOF_LOG_LEVEL); @@ -77,3 +78,289 @@ __cold int uaol_stream_id_to_hda_link_stream_id(int uaol_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/intel_uaol.h b/src/include/sof/audio/intel_uaol.h index e8964d2d7450..b5066fdffbe7 100644 --- a/src/include/sof/audio/intel_uaol.h +++ b/src/include/sof/audio/intel_uaol.h @@ -10,6 +10,7 @@ #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); @@ -17,4 +18,24 @@ __cold void tlv_value_set_uaol_caps(struct sof_tlv *tuple, uint32_t type); __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_INTEL_UAOL_H__ */ diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index a0c42bff351e..4a2c3dc9d511 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -29,6 +29,9 @@ #include #include #include +#ifdef CONFIG_UAOL_INTEL_ADSP +#include +#endif #include #include #include @@ -113,6 +116,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_UAOL_INTEL_ADSP +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 */ @@ -147,6 +168,10 @@ struct dai_data { uint64_t wallclock; /* wall clock at stream start */ +#ifdef CONFIG_UAOL_INTEL_ADSP + 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 c0ed1f52c3a1..0a736c96773b 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -28,6 +28,9 @@ #include #include #include +#ifdef CONFIG_UAOL_INTEL_ADSP +#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_UAOL_INTEL_ADSP 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) sof_dma_release_channel(dd->dma, dd->chan_index); dd->chan_index = -EINVAL; } + +#ifdef CONFIG_UAOL_INTEL_ADSP + 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/lib/dai.c b/src/lib/dai.c index 68163282adc1..6f8c2f720a26 100644 --- a/src/lib/dai.c +++ b/src/lib/dai.c @@ -192,7 +192,7 @@ const struct device *zephyr_dev[] = { #if CONFIG_DAI_AMD_TDM DT_FOREACH_STATUS_OKAY(amd_tdm_dai, GET_DEVICE_LIST) #endif -#if CONFIG_DAI_INTEL_UAOL +#if CONFIG_UAOL_INTEL_ADSP DT_FOREACH_STATUS_OKAY(intel_uaol_dai, GET_DEVICE_LIST) #endif #if DT_HAS_COMPAT_STATUS_OKAY(mediatek_afe) From f2ca0bb3fa8de8ecbd4a19460d0afe8976ece8fc Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Fri, 11 Sep 2026 10:39:37 +0200 Subject: [PATCH 4/5] audio: uaol: use sof_heap_alloc() *** SQUASH *** Signed-off-by: Serhiy Katsyuba --- src/audio/dai-zephyr.c | 3 ++- src/audio/intel_uaol.c | 35 ++++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 0b40aa05edb3..f25f531af8ff 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -1282,7 +1282,8 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, 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, + dd->uaol.dsrc_buf = buffer_alloc_range(&dd->alloc_ctx, dsrc_buf_size, + dsrc_buf_size, SOF_MEM_FLAG_USER, PLATFORM_DCACHE_ALIGN, BUFFER_USAGE_NOT_SHARED); if (!dd->uaol.dsrc_buf) { diff --git a/src/audio/intel_uaol.c b/src/audio/intel_uaol.c index c94c2c337cd3..328656019ec0 100644 --- a/src/audio/intel_uaol.c +++ b/src/audio/intel_uaol.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -281,18 +282,20 @@ int setup_uaol_feedback_dma(struct dai_data *dd, struct comp_dev *dev) 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); + dd->uaol.fb_dma_buf = sof_heap_alloc(dd->alloc_ctx.heap, + 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)); + dma_cfg = sof_heap_alloc(dd->alloc_ctx.heap, + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT | SOF_MEM_FLAG_DMA, + sizeof(struct dma_config), 0); if (!dma_cfg) { - rfree(dd->uaol.fb_dma_buf); + sof_heap_free(dd->alloc_ctx.heap, dd->uaol.fb_dma_buf); dd->uaol.fb_dma_buf = NULL; comp_err(dev, "dma_cfg allocation failed"); return -ENOMEM; @@ -308,11 +311,13 @@ int setup_uaol_feedback_dma(struct dai_data *dd, struct comp_dev *dev) 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)); + dma_cfg->head_block = sof_heap_alloc(dd->alloc_ctx.heap, + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT | + SOF_MEM_FLAG_DMA, + sizeof(struct dma_block_config), 0); if (!dma_cfg->head_block) { - rfree(dma_cfg); - rfree(dd->uaol.fb_dma_buf); + sof_heap_free(dd->alloc_ctx.heap, dma_cfg); + sof_heap_free(dd->alloc_ctx.heap, dd->uaol.fb_dma_buf); dd->uaol.fb_dma_buf = NULL; comp_err(dev, "dma_block_config allocation failed"); return -ENOMEM; @@ -330,9 +335,9 @@ int setup_uaol_feedback_dma(struct dai_data *dd, struct comp_dev *dev) 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); + sof_heap_free(dd->alloc_ctx.heap, dma_cfg->head_block); + sof_heap_free(dd->alloc_ctx.heap, dma_cfg); + sof_heap_free(dd->alloc_ctx.heap, dd->uaol.fb_dma_buf); dd->uaol.fb_dma_buf = NULL; comp_err(dev, "dma_request_channel() failed"); return -EIO; @@ -348,13 +353,13 @@ int setup_uaol_feedback_dma(struct dai_data *dd, struct comp_dev *dev) 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); + sof_heap_free(dd->alloc_ctx.heap, dd->uaol.fb_z_config->head_block); + sof_heap_free(dd->alloc_ctx.heap, dd->uaol.fb_z_config); dd->uaol.fb_z_config = NULL; } if (dd->uaol.fb_dma_buf) { - rfree(dd->uaol.fb_dma_buf); + sof_heap_free(dd->alloc_ctx.heap, dd->uaol.fb_dma_buf); dd->uaol.fb_dma_buf = NULL; dd->uaol.fb_dma_buf_size = 0; } From 7094c13984a420151f39505f708b75d37e15f285 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Fri, 11 Sep 2026 11:09:42 +0200 Subject: [PATCH 5/5] [***DNM***] use private Zephyr Signed-off-by: Serhiy Katsyuba --- west.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/west.yml b/west.yml index 5848ac114220..c56a9bf20c10 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: 256e764458c653104eed6fe7a0b211060fc187be - remote: zephyrproject + revision: uaol_feedback_0909 + remote: sk # Import some projects listed in zephyr/west.yml@revision #