diff --git a/.github/workflows/sparse-zephyr.yml b/.github/workflows/sparse-zephyr.yml index a0e7c8f3a0e7..9c63e11586fd 100644 --- a/.github/workflows/sparse-zephyr.yml +++ b/.github/workflows/sparse-zephyr.yml @@ -57,12 +57,15 @@ jobs: # --pristine is important to reproduce _warnings_. It makes no # difference for github but it's useful for anyone trying to # reproduce and copying the command from the logs. + # "sparse" is currently incompatible with PICOLIBC (the new Zephyr default), + # see https://github.com/zephyrproject-rtos/zephyr/issues/63003 - name: analyze zephyr working-directory: ./workspace run: | ./sof/zephyr/docker-run.sh \ ./sof/zephyr/docker-build.sh ${{ matrix.platform }} \ --cmake-args=-DZEPHYR_SCA_VARIANT=sparse --cmake-args=-DCONFIG_LOG_USE_VLA=n \ + --cmake-args=-DCONFIG_MINIMAL_LIBC=y \ --pristine 2>&1 | tee _.log printf '\n\n\t\t\t ---- Messages below are treated as sparse errors --- \n\n\n' diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml index a1cb163c158d..25af4e96cd8a 100644 --- a/.github/workflows/zephyr.yml +++ b/.github/workflows/zephyr.yml @@ -107,11 +107,10 @@ jobs: IPC_platforms: [ # - IPC3 default imx8 imx8x imx8m, - tgl tgl-h, # UNSUPPORTED! Will be removed # - IPC4 default mtl, lnl, # Temporary testbed for Zephyr development. - -i IPC4 tgl tgl-h, + tgl tgl-h, ] build_opts: [""] # Sparse matrices are complicated, you must read this page slowly: @@ -213,11 +212,9 @@ jobs: platforms: [ # - IPC3 default imx8 imx8x imx8m, - tgl tgl-h, # UNSUPPORTED! Will be removed # - IPC4 default mtl, - # Very few IPC3 platforms support IPC4 too. - -i IPC4 tgl tgl-h, + tgl tgl-h, ] build_opts: [""] # Sparse matrices are complicated, see comments on Linux matrix above. @@ -329,7 +326,18 @@ jobs: working-directory: ${{ github.workspace }}/workspace run: pip install -r zephyr/scripts/requirements.txt + # Ninja has been coming and going, see #8250 + - name: choco install ninja + run: | + choco install ninja + ninja.exe --version + # MSYS2 provides gcc x64_86 toolchain & openssl + # Installs in D:/a/_temp/msys64 + # + # Note there is already C:/msys64/ provided by + # https://github.com/actions/runner-images/blob/win22/20230918.1/images/win/Windows2022-Readme.md + # Is it not good enough? Maybe it could save 20-30s. - name: Initialize MSYS2 uses: msys2/setup-msys2@v2 with: @@ -397,7 +405,7 @@ jobs: # http://mywiki.wooledge.org/ParsingLs for regdir in 'linux-build *mtl' \ 'windows-build *mtl' \ - 'windows-build *-i IPC4 tgl tgl-h'; do + 'windows-build *tgl tgl-h'; do find . -maxdepth 1 | grep -q "\./${regdir}\$" || { >&2 printf 'Missing %s\n' "${regdir}"; exit 1; } done diff --git a/.gitmodules b/.gitmodules index da3426a76e3d..99bed093e833 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,19 +1,17 @@ -[submodule "rimage"] - path = rimage -# This is a _relative_ submodule URL. In some use cases it's better than -# an _absolute_ submodule URL, in other cases it's not. One size does -# unfortunately not fit all. -# -# Among other pages, http://blog.tremily.us/posts/Relative_submodules/ -# has a good comparison -# -# If you use Zephyr you must also look at the comments in sof/west.yml. -# -# If you want to fork or mirror sof.git _without_ doing the same for -# rimage.git then your automation may want you to change and git commit -# an absolute URL in your branch. No need to git commit for interactive -# use; a local and temporary edit of this file is enough for interactive -# use because .gitmodules is used only once to --init[ialize] -# .git/config the first time. Then .gitmodules is never used again after -# cloning. - url = ../rimage +# This is required for non-Zephyr ("XTOS") configurations. Zephyr +# configs also get it from sof/west.yml which adds the burden of keeping +# both tomlc99 SHA1s synchronized but in practice this barely ever moves. +[submodule "tomlc99"] + path = tools/rimage/tomlc99 + # This is a _absolute_ submodule URL. In some use cases it's + # better than an _relative_ submodule URL, in other cases it's + # not. One size does unfortunately not fit all. Among other + # pages, http://blog.tremily.us/posts/Relative_submodules/ has a + # good comparison. + # + # A local and temporary edit of this url can be enough because + # .gitmodules is used _only once_ to submodule --init[ialize] + # .git/config the first time. Then .gitmodules is never used + # again after cloning tomlc99 the first time. + url = https://github.com/thesofproject/tomlc99.git + branch = master diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d951e86a2de..075d1a33c636 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,8 @@ project(SOF C ASM) set(SOF_ROOT_SOURCE_DIRECTORY "${PROJECT_SOURCE_DIR}") set(SOF_ROOT_BINARY_DIRECTORY "${PROJECT_BINARY_DIR}") +set(RIMAGE_TOP "${PROJECT_SOURCE_DIR}/tools/rimage") + # check git hooks include(scripts/cmake/git-hooks.cmake) @@ -159,8 +161,8 @@ install( ${PROJECT_SOURCE_DIR}/src/include/ipc ${PROJECT_SOURCE_DIR}/src/include/kernel ${PROJECT_SOURCE_DIR}/src/include/user - ${PROJECT_SOURCE_DIR}/rimage/src/include/sof/kernel - ${PROJECT_SOURCE_DIR}/rimage/src/include/sof/user + ${RIMAGE_TOP}/src/include/sof/kernel + ${RIMAGE_TOP}/src/include/sof/user DESTINATION include/sof PATTERN "*.h" ) diff --git a/app/boards/intel_adsp_ace15_mtpm.conf b/app/boards/intel_adsp_ace15_mtpm.conf index 8bbcc0278c58..ac1a3c846441 100644 --- a/app/boards/intel_adsp_ace15_mtpm.conf +++ b/app/boards/intel_adsp_ace15_mtpm.conf @@ -67,6 +67,7 @@ CONFIG_SYS_CLOCK_TICKS_PER_SEC=12000 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=38400000 CONFIG_LOG_BACKEND_ADSP_MTRACE=y +CONFIG_LOG_BACKEND_SOF_PROBE=n CONFIG_SOF_LOG_LEVEL_INF=y CONFIG_ZEPHYR_LOG=y CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y diff --git a/app/overlays/lnl/fpga_overlay.conf b/app/overlays/lnl/fpga_overlay.conf index 0fc3ac375789..eebbfee72648 100644 --- a/app/overlays/lnl/fpga_overlay.conf +++ b/app/overlays/lnl/fpga_overlay.conf @@ -1,2 +1,3 @@ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=19200000 CONFIG_DAI_DMIC_HW_IOCLK=19200000 +CONFIG_XTENSA_CCOUNT_HZ=40000000 diff --git a/app/overlays/mtl/fpga_overlay.conf b/app/overlays/mtl/fpga_overlay.conf index 0fc3ac375789..eebbfee72648 100644 --- a/app/overlays/mtl/fpga_overlay.conf +++ b/app/overlays/mtl/fpga_overlay.conf @@ -1,2 +1,3 @@ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=19200000 CONFIG_DAI_DMIC_HW_IOCLK=19200000 +CONFIG_XTENSA_CCOUNT_HZ=40000000 diff --git a/app/overlays/tgl-h/ipc4_overlay.conf b/app/overlays/tgl-h/ipc4_overlay.conf deleted file mode 100644 index fc4739a27eb6..000000000000 --- a/app/overlays/tgl-h/ipc4_overlay.conf +++ /dev/null @@ -1,5 +0,0 @@ -# This file is empty as IPC4 now the default. -# -# The file is kept around for the time being to -# smoothen the transition for users who use -# this overlay file in their build scripts. diff --git a/app/overlays/tgl/ipc4_overlay.conf b/app/overlays/tgl/ipc4_overlay.conf deleted file mode 100644 index fc4739a27eb6..000000000000 --- a/app/overlays/tgl/ipc4_overlay.conf +++ /dev/null @@ -1,5 +0,0 @@ -# This file is empty as IPC4 now the default. -# -# The file is kept around for the time being to -# smoothen the transition for users who use -# this overlay file in their build scripts. diff --git a/app/prj.conf b/app/prj.conf index 49b09f62789b..b3f1016620ea 100644 --- a/app/prj.conf +++ b/app/prj.conf @@ -14,6 +14,10 @@ CONFIG_OUTPUT_DISASSEMBLY=y CONFIG_HAVE_AGENT=n +# Since Zephyr commit f0daf904bb0202c PICOLIBC is the new default. +# We need more time to test and evaluate. +CONFIG_MINIMAL_LIBC=y + CONFIG_LOG=y CONFIG_LOG_PRINTK=y # Log processing is offloaded to a low-priority thread. diff --git a/app/stub_build_all_ipc3.conf b/app/stub_build_all_ipc3.conf index c64fc4790da1..9dcfbb50f1fb 100644 --- a/app/stub_build_all_ipc3.conf +++ b/app/stub_build_all_ipc3.conf @@ -1,6 +1,6 @@ CONFIG_COMP_STUBS=y CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=y -CONFIG_COMP_TONE=y +CONFIG_COMP_TONE=n CONFIG_COMP_CROSSOVER=y CONFIG_COMP_DRC=y CONFIG_COMP_MULTIBAND_DRC=y diff --git a/posix/include/CMakeLists.txt b/posix/include/CMakeLists.txt new file mode 100644 index 000000000000..fd819740233b --- /dev/null +++ b/posix/include/CMakeLists.txt @@ -0,0 +1 @@ +target_include_directories(sof_public_headers INTERFACE include) diff --git a/posix/include/rtos/alloc.h b/posix/include/rtos/alloc.h new file mode 100644 index 000000000000..d64ea319f48e --- /dev/null +++ b/posix/include/rtos/alloc.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +/** + * \file xtos/include/rtos/alloc.h + * \brief Memory Allocation API definition + * \author Liam Girdwood + * \author Keyon Jie + */ + +#ifndef __SOF_LIB_ALLOC_H__ +#define __SOF_LIB_ALLOC_H__ + +#include +#include +#include +#include + +#include +#include + +/** \addtogroup alloc_api Memory Allocation API + * @{ + */ + +/** + * \brief Heap Memory Zones + * + * The heap has three different zones from where memory can be allocated :- + * + * 1) System Zone. Fixed size heap where alloc always succeeds and is never + * freed. Used by any init code that will never give up the memory. + * + * 2) System Runtime Zone. Heap zone intended for runtime objects allocated + * by the kernel part of the code. + * + * 3) Runtime Zone. Main and larger heap zone where allocs are not guaranteed to + * succeed. Memory can be freed here. + * + * 4) Buffer Zone. Largest heap zone intended for audio buffers. + * + * 5) Runtime Shared Zone. Similar to Runtime Zone, but content may be used and + * fred from any enabled core. + * + * 6) System Shared Zone. Similar to System Zone, but content may be used from + * any enabled core. + * + * See platform/memory.h for heap size configuration and mappings. + */ +enum mem_zone { + SOF_MEM_ZONE_SYS = 0, /**< System zone */ + SOF_MEM_ZONE_SYS_RUNTIME, /**< System-runtime zone */ + SOF_MEM_ZONE_RUNTIME, /**< Runtime zone */ + SOF_MEM_ZONE_BUFFER, /**< Buffer zone */ + SOF_MEM_ZONE_RUNTIME_SHARED, /**< Runtime shared zone */ + SOF_MEM_ZONE_SYS_SHARED, /**< System shared zone */ +}; + +/** \name Heap zone flags + * @{ + */ + +/** \brief Indicates that original content should not be copied by realloc. */ +#define SOF_MEM_FLAG_NO_COPY BIT(1) +/** \brief Indicates that if we should return uncached address. */ +#define SOF_MEM_FLAG_COHERENT BIT(2) + +/** @} */ + +/** + * Allocates memory block. + * @param zone Zone to allocate memory from, see enum mem_zone. + * @param flags Flags, see SOF_MEM_FLAG_... + * @param caps Capabilities, see SOF_MEM_CAPS_... + * @param bytes Size in bytes. + * @return Pointer to the allocated memory or NULL if failed. + * + * @note Do not use for buffers (SOF_MEM_ZONE_BUFFER zone). + * Use rballoc(), rballoc_align() to allocate memory for buffers. + */ +void *rmalloc(enum mem_zone zone, uint32_t flags, uint32_t caps, size_t bytes); + +/** + * Similar to rmalloc(), guarantees that returned block is zeroed. + * + * @note Do not use for buffers (SOF_MEM_ZONE_BUFFER zone). + * rballoc(), rballoc_align() to allocate memory for buffers. + */ +void *rzalloc(enum mem_zone zone, uint32_t flags, uint32_t caps, size_t bytes); + +/** + * Allocates memory block from SOF_MEM_ZONE_BUFFER. + * @param flags Flags, see SOF_MEM_FLAG_... + * @param caps Capabilities, see SOF_MEM_CAPS_... + * @param bytes Size in bytes. + * @param alignment Alignment in bytes. + * @return Pointer to the allocated memory or NULL if failed. + */ +void *rballoc_align(uint32_t flags, uint32_t caps, size_t bytes, + uint32_t alignment); + +/** + * Similar to rballoc_align(), returns buffer aligned to PLATFORM_DCACHE_ALIGN. + */ +static inline void *rballoc(uint32_t flags, uint32_t caps, size_t bytes) +{ + return rballoc_align(flags, caps, bytes, PLATFORM_DCACHE_ALIGN); +} + +/** + * Changes size of the memory block allocated from SOF_MEM_ZONE_BUFFER. + * @param ptr Address of the block to resize. + * @param flags Flags, see SOF_MEM_FLAG_... + * @param caps Capabilities, see SOF_MEM_CAPS_... + * @param bytes New size in bytes. + * @param old_bytes Old size in bytes. + * @param alignment Alignment in bytes. + * @return Pointer to the resized memory of NULL if failed. + */ +void *rbrealloc_align(void *ptr, uint32_t flags, uint32_t caps, size_t bytes, + size_t old_bytes, uint32_t alignment); + +/** + * Similar to rballoc_align(), returns resized buffer aligned to + * PLATFORM_DCACHE_ALIGN. + */ +static inline void *rbrealloc(void *ptr, uint32_t flags, uint32_t caps, + size_t bytes, size_t old_bytes) +{ + return rbrealloc_align(ptr, flags, caps, bytes, old_bytes, + PLATFORM_DCACHE_ALIGN); +} + +/** + * Frees the memory block. + * @param ptr Pointer to the memory block. + * + * @note Blocks from SOF_MEM_ZONE_SYS cannot be freed, such a call causes + * panic. + */ +void rfree(void *ptr); + +/** + * Allocates memory block from the system heap reserved for the specified core. + * @param core Core id. + * @param bytes Size in bytes. + */ +void *rzalloc_core_sys(int core, size_t bytes); + +/** + * Calculates length of the null-terminated string. + * @param s String. + * @return Length of the string in bytes. + */ +int rstrlen(const char *s); + +/** + * Compares two strings, see man strcmp. + * @param s1 First string to compare. + * @param s2 Second string to compare. + * @return See man strcmp. + */ +int rstrcmp(const char *s1, const char *s2); + +/** @}*/ + +#endif /* __SOF_LIB_ALLOC_H__ */ diff --git a/posix/include/rtos/atomic.h b/posix/include/rtos/atomic.h new file mode 100644 index 000000000000..6d16b6b6c9e6 --- /dev/null +++ b/posix/include/rtos/atomic.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOF_ATOMIC_H__ +#define __SOF_ATOMIC_H__ + +#include +#include + +static inline void atomic_init(atomic_t *a, int32_t value) +{ + arch_atomic_init(a, value); +} + +static inline int32_t atomic_read(const atomic_t *a) +{ + return arch_atomic_read(a); +} + +static inline void atomic_set(atomic_t *a, int32_t value) +{ + arch_atomic_set(a, value); +} + +static inline int32_t atomic_add(atomic_t *a, int32_t value) +{ + return arch_atomic_add(a, value); +} + +static inline int32_t atomic_sub(atomic_t *a, int32_t value) +{ + return arch_atomic_sub(a, value); +} + +#endif /* __SOF_ATOMIC_H__ */ diff --git a/posix/include/rtos/bit.h b/posix/include/rtos/bit.h new file mode 100644 index 000000000000..3dde908c2d6b --- /dev/null +++ b/posix/include/rtos/bit.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __XTOS_RTOS_BIT_H__ +#define __XTOS_RTOS_BIT_H__ + +#if ASSEMBLY +#define BIT(b) (1 << (b)) +#else +#define BIT(b) (1UL << (b)) +#endif + +#define MASK(b_hi, b_lo) \ + (((1ULL << ((b_hi) - (b_lo) + 1ULL)) - 1ULL) << (b_lo)) +#define SET_BIT(b, x) (((x) & 1) << (b)) +#define SET_BITS(b_hi, b_lo, x) \ + (((x) & ((1ULL << ((b_hi) - (b_lo) + 1ULL)) - 1ULL)) << (b_lo)) +#define GET_BIT(b, x) \ + (((x) & (1ULL << (b))) >> (b)) +#define GET_BITS(b_hi, b_lo, x) \ + (((x) & MASK(b_hi, b_lo)) >> (b_lo)) + +#endif /* __XTOS_RTOS_BIT_H__ */ diff --git a/posix/include/rtos/cache.h b/posix/include/rtos/cache.h new file mode 100644 index 000000000000..914e61b52984 --- /dev/null +++ b/posix/include/rtos/cache.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Tomasz Lauda + */ + +/** + * \file xtos/include/rtos/cache.h + * \brief Cache header file + * \authors Tomasz Lauda + */ + +#ifndef __SOF_LIB_CACHE_H__ +#define __SOF_LIB_CACHE_H__ + +#include + +/* writeback and invalidate data */ +#define CACHE_WRITEBACK_INV 0 + +/* invalidate data */ +#define CACHE_INVALIDATE 1 + +#endif /* __SOF_LIB_CACHE_H__ */ diff --git a/posix/include/rtos/clk.h b/posix/include/rtos/clk.h new file mode 100644 index 000000000000..e9a36796bc42 --- /dev/null +++ b/posix/include/rtos/clk.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + * Janusz Jankowski + */ + +#ifndef __SOF_LIB_CLK_H__ +#define __SOF_LIB_CLK_H__ + +#include +#include +#include +#include +#include + +struct timer; + +#define CLOCK_NOTIFY_PRE 0 +#define CLOCK_NOTIFY_POST 1 + +struct clock_notify_data { + uint32_t old_freq; + uint32_t old_ticks_per_msec; + uint32_t freq; + uint32_t ticks_per_msec; + uint32_t message; +}; + +struct freq_table { + uint32_t freq; + uint32_t ticks_per_msec; +}; + +struct clock_info { + uint32_t freqs_num; + const struct freq_table *freqs; + uint32_t default_freq_idx; + uint32_t current_freq_idx; + uint32_t lowest_freq_idx; /* lowest possible clock */ + uint32_t notification_id; + uint32_t notification_mask; + + /* persistent change clock value in active state, caller must hold clk_lock */ + int (*set_freq)(int clock, int freq_idx); + + /* temporary change clock - don't modify default clock settings */ + void (*low_power_mode)(int clock, bool enable); +}; + +uint32_t clock_get_freq(int clock); + +void clock_set_freq(int clock, uint32_t hz); + +void clock_low_power_mode(int clock, bool enable); + +uint64_t clock_ms_to_ticks(int clock, uint64_t ms); + +uint64_t clock_us_to_ticks(int clock, uint64_t us); + +uint64_t clock_ns_to_ticks(int clock, uint64_t ns); + +uint64_t clock_ticks_per_sample(int clock, uint32_t sample_rate); + +extern struct k_spinlock clk_lock; + +static inline k_spinlock_key_t clock_lock(void) +{ + return k_spin_lock(&clk_lock); +} + +static inline void clock_unlock(k_spinlock_key_t key) +{ + k_spin_unlock(&clk_lock, key); +} + +static inline struct clock_info *clocks_get(void) +{ + return sof_get()->clocks; +} + +#endif /* __SOF_LIB_CLK_H__ */ diff --git a/posix/include/rtos/idc.h b/posix/include/rtos/idc.h new file mode 100644 index 000000000000..d6dd69f3e9e9 --- /dev/null +++ b/posix/include/rtos/idc.h @@ -0,0 +1,201 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Tomasz Lauda + */ + +/** + * \file include/rtos/idc.h + * \brief IDC header file + * \authors Tomasz Lauda + */ + +#ifndef __POSIX_RTOS_IDC_H__ +#define __POSIX_RTOS_IDC_H__ + +#include +#include +#include +#include +#include +#include +#include + +/** \brief IDC send blocking flag. */ +#define IDC_BLOCKING 0 + +/** \brief IDC send non-blocking flag. */ +#define IDC_NON_BLOCKING 1 + +/** \brief IDC send core power up flag. */ +#define IDC_POWER_UP 2 + +/** \brief IDC send core power down flag. */ +#define IDC_POWER_DOWN 3 + +/** \brief IDC send timeout in microseconds. */ +#define IDC_TIMEOUT 10000 + +/** \brief IDC task deadline. */ +#define IDC_DEADLINE 100 + +/** \brief ROM wake version parsed by ROM during core wake up. */ +#define IDC_ROM_WAKE_VERSION 0x2 + +/** \brief IDC message type. */ +#define IDC_TYPE_SHIFT 24 +#define IDC_TYPE_MASK 0x7f +#define IDC_TYPE(x) (((x) & IDC_TYPE_MASK) << IDC_TYPE_SHIFT) + +#define IDC_MSG_BIND IDC_TYPE(0xD) +#define IDC_MSG_UNBIND IDC_TYPE(0xE) +#define IDC_MSG_GET_ATTRIBUTE IDC_TYPE(0xF) + +/** \brief IDC pipeline set state message. */ +#define IDC_MSG_PPL_STATE IDC_TYPE(0xC) +#define IDC_PPL_STATE_PPL_ID_SHIFT 0 +#define IDC_PPL_STATE_PPL_ID_MASK MASK(23, 0) +#define IDC_PPL_STATE_PHASE_SHIFT 24 +#define IDC_PPL_STATE_PHASE_MASK MASK(27, 24) +#define IDC_PPL_STATE_PHASE_SET(x) (((x) << IDC_PPL_STATE_PHASE_SHIFT) & \ + IDC_PPL_STATE_PHASE_MASK) +#define IDC_PPL_STATE_PHASE_GET(x) (((x) & IDC_PPL_STATE_PHASE_MASK) >> \ + IDC_PPL_STATE_PHASE_SHIFT) +#define IDC_PPL_STATE_PHASE_PREPARE BIT(0) +#define IDC_PPL_STATE_PHASE_TRIGGER BIT(1) +#define IDC_PPL_STATE_PHASE_ONESHOT (IDC_PPL_STATE_PHASE_PREPARE | \ + IDC_PPL_STATE_PHASE_TRIGGER) + +#define IDC_MSG_PPL_STATE_EXT(_ppl_id, _action) \ + IDC_EXTENSION(((_ppl_id) & IDC_PPL_STATE_PPL_ID_MASK) | \ + IDC_PPL_STATE_PHASE_SET(_action)) + +/** \brief IDC message header. */ +#define IDC_HEADER_MASK 0xffffff +#define IDC_HEADER(x) ((x) & IDC_HEADER_MASK) + +/** \brief IDC message extension. */ +#define IDC_EXTENSION_MASK 0x3fffffff +#define IDC_EXTENSION(x) ((x) & IDC_EXTENSION_MASK) + +/** \brief IDC power up message. */ +#define IDC_MSG_POWER_UP (IDC_TYPE(0x1) | \ + IDC_HEADER(IDC_ROM_WAKE_VERSION)) +#define IDC_MSG_POWER_UP_EXT IDC_EXTENSION(SOF_TEXT_START >> 2) + +/** \brief IDC power down message. */ +#define IDC_MSG_POWER_DOWN IDC_TYPE(0x2) +#define IDC_MSG_POWER_DOWN_EXT IDC_EXTENSION(0x0) + +/** \brief IDC notify message. */ +#define IDC_MSG_NOTIFY IDC_TYPE(0x3) +#define IDC_MSG_NOTIFY_EXT IDC_EXTENSION(0x0) + +/** \brief IDC IPC processing message. */ +#define IDC_MSG_IPC IDC_TYPE(0x4) +#define IDC_MSG_IPC_EXT IDC_EXTENSION(0x0) + +/** \brief IDC component params message. */ +#define IDC_MSG_PARAMS IDC_TYPE(0x5) +#define IDC_MSG_PARAMS_EXT(x) IDC_EXTENSION(x) + +/** \brief IDC component prepare message. */ +#define IDC_MSG_PREPARE IDC_TYPE(0x6) +#define IDC_MSG_PREPARE_EXT(x) IDC_EXTENSION(x) + +/** \brief IDC component trigger message. */ +#define IDC_MSG_TRIGGER IDC_TYPE(0x7) +#define IDC_MSG_TRIGGER_EXT(x) IDC_EXTENSION(x) + +/** \brief IDC component reset message. */ +#define IDC_MSG_RESET IDC_TYPE(0x8) +#define IDC_MSG_RESET_EXT(x) IDC_EXTENSION(x) + +/** \brief IDC prepare D0ix message. */ +#define IDC_MSG_PREPARE_D0ix IDC_TYPE(0x9) +#define IDC_MSG_PREPARE_D0ix_EXT IDC_EXTENSION(0x0) + +/** \brief IDC secondary core crashed notify message. */ +#define IDC_MSG_SECONDARY_CORE_CRASHED IDC_TYPE(0xA) +#define IDC_MSG_SECONDARY_CORE_CRASHED_EXT(x) IDC_EXTENSION(x) + +/** \brief IDC process async msg */ +#define IDC_MSG_AMS IDC_TYPE(0xB) +#define IDC_MSG_AMS_EXT IDC_EXTENSION(0x0) + +#define IDC_HEADER_TO_AMS_SLOT_MASK(x) (x & 0xFFFF) + +/** \brief IDC_MSG_SECONDARY_CORE_CRASHED header fields. */ +#define IDC_SCC_CORE_SHIFT 0 +#define IDC_SCC_CORE_MASK 0xff +#define IDC_SCC_CORE(x) (((x) & IDC_SCC_CORE_MASK) << IDC_SCC_CORE_SHIFT) + +#define IDC_SCC_REASON_SHIFT 8 +#define IDC_SCC_REASON_MASK 0xff +#define IDC_SCC_REASON(x) (((x) & IDC_SCC_REASON_MASK) << IDC_SCC_REASON_SHIFT) + +/** \brief Secondary core crash reasons. */ +#define IDC_SCC_REASON_WATCHDOG 0x00 +#define IDC_SCC_REASON_EXCEPTION 0x01 + +/** \brief Decodes IDC message type. */ +#define iTS(x) (((x) >> IDC_TYPE_SHIFT) & IDC_TYPE_MASK) + +/** \brief Max IDC message payload size in bytes. */ +#define IDC_MAX_PAYLOAD_SIZE (DCACHE_LINE_SIZE * 2) + +/** \brief IDC free function flags */ +#define IDC_FREE_IRQ_ONLY BIT(0) /**< disable only irqs */ + +/** \brief IDC message payload. */ +struct idc_payload { + uint8_t data[IDC_MAX_PAYLOAD_SIZE]; +}; + +/** \brief IDC message. */ +struct idc_msg { + uint32_t header; /**< header value */ + uint32_t extension; /**< extension value */ + uint32_t core; /**< core id */ + uint32_t size; /**< payload size in bytes */ + void *payload; /**< pointer to payload data */ +}; + +/** \brief IDC data. */ +struct idc { + uint32_t busy_bit_mask; /**< busy interrupt mask */ + struct idc_msg received_msg; /**< received message */ + struct task idc_task; /**< IDC processing task */ + struct idc_payload *payload; + int irq; +}; + +/* idc trace context, used by multiple units */ +extern struct tr_ctx idc_tr; + +static inline struct idc_payload *idc_payload_get(struct idc *idc, + uint32_t core) +{ + return idc->payload + core; +} + +void idc_enable_interrupts(int target_core, int source_core); + +void idc_free(uint32_t flags); + +int platform_idc_init(void); + +int platform_idc_restore(void); + +enum task_state idc_do_cmd(void *data); + +void idc_cmd(struct idc_msg *msg); + +int idc_wait_in_blocking_mode(uint32_t target_core, bool (*cond)(int)); + +int idc_msg_status_get(uint32_t core); + +void idc_init_thread(void); + +#endif /* __POSIX_RTOS_IDC_H__ */ diff --git a/posix/include/rtos/init.h b/posix/include/rtos/init.h new file mode 100644 index 000000000000..7744d6b5b1f3 --- /dev/null +++ b/posix/include/rtos/init.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2023 Intel Corporation. All rights reserved. + */ + +#ifndef __POSIX_RTOS_INIT_H__ +#define __POSIX_RTOS_INIT_H__ + +#define SOF_MODULE_INIT(name, init) + +#endif /* __POSIX_RTOS_INIT_H__ */ diff --git a/posix/include/rtos/interrupt.h b/posix/include/rtos/interrupt.h new file mode 100644 index 000000000000..839b4bef3ca3 --- /dev/null +++ b/posix/include/rtos/interrupt.h @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Janusz Jankowski + */ + +#ifndef __SOF_DRIVERS_INTERRUPT_H__ +#define __SOF_DRIVERS_INTERRUPT_H__ + +#include + +#if !defined(__ASSEMBLER__) && !defined(LINKER) +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * \brief child IRQ descriptor for cascading IRQ controllers. + */ +struct irq_child { + int enable_count[CONFIG_CORE_COUNT]; /**< IRQ enable counter */ + struct list_item list; /**< head for IRQ descriptors, + * sharing this interrupt + */ +}; + +/** + * \brief interrupt client descriptor + */ +struct irq_desc { + int irq; /**< virtual IRQ number */ + void (*handler)(void *arg); /**< interrupt handler function */ + void *handler_arg; /**< interrupt handler argument */ + uint32_t cpu_mask; /**< a mask of CPUs on which this + * interrupt is enabled + */ + struct list_item irq_list; /**< to link to other irq_desc */ +}; + +/** + * \brief cascading IRQ controller operations. + */ +struct irq_cascade_ops { + void (*mask)(struct irq_desc *desc, uint32_t irq, + unsigned int cpu); /**< mask */ + void (*unmask)(struct irq_desc *desc, uint32_t irq, + unsigned int cpu); /**< unmask */ +}; + +/** + * \brief cascading interrupt controller descriptor. + */ +struct irq_cascade_desc { + const char *name; /**< name of the + * controller + */ + int irq_base; /**< first virtual IRQ + * number, assigned to + * this controller + */ + const struct irq_cascade_ops *ops; /**< cascading interrupt + * controller driver + * operations + */ + struct irq_desc desc; /**< the interrupt, that + * this controller is + * generating + */ + struct irq_cascade_desc *next; /**< link to the global + * list of interrupt + * controllers + */ + bool global_mask; /**< the controller + * cannot mask input + * interrupts per core + */ + struct k_spinlock lock; /**< protect child + * lists, enable and + * child counters + */ + int enable_count[CONFIG_CORE_COUNT]; /**< enabled child + * interrupt counter + */ + unsigned int num_children[CONFIG_CORE_COUNT]; /**< number of children + */ + struct irq_child child[PLATFORM_IRQ_CHILDREN]; /**< array of child + * lists - one per + * multiplexed IRQ + */ +}; + +/* A descriptor for cascading interrupt controller template */ +struct irq_cascade_tmpl { + const char *name; + const struct irq_cascade_ops *ops; + int irq; + void (*handler)(void *arg); + bool global_mask; +}; + +/** + * \brief Cascading interrupt controller root. + */ +struct cascade_root { + struct k_spinlock lock; /**< locking mechanism */ + struct irq_cascade_desc *list; /**< list of child cascade irqs */ + int last_irq; /**< last registered cascade irq */ +}; + +static inline struct cascade_root *cascade_root_get(void) +{ + return sof_get()->cascade_root; +} + +/* For i.MX, while building SOF with Zephyr use the interrupt_* + * functions from second level interrupt handling and IRQ_STEER. + */ +#if defined(__ZEPHYR__) && defined(CONFIG_IMX) +int mux_interrupt_get_irq(unsigned int irq, const char *cascade); +int mux_interrupt_register(uint32_t irq, void(*handler)(void *arg), void *arg); +void mux_interrupt_unregister(uint32_t irq, const void *arg); +uint32_t mux_interrupt_enable(uint32_t irq, void *arg); +uint32_t mux_interrupt_disable(uint32_t irq, void *arg); +#endif + +int interrupt_register(uint32_t irq, void(*handler)(void *arg), void *arg); +void interrupt_unregister(uint32_t irq, const void *arg); +uint32_t interrupt_enable(uint32_t irq, void *arg); +uint32_t interrupt_disable(uint32_t irq, void *arg); + +/* Zephyr compat */ +#if !defined(__ZEPHYR__) +#define arch_irq_lock() arch_interrupt_disable_mask(0xffffffff) +#endif + +void platform_interrupt_init(void); + +void platform_interrupt_set(uint32_t irq); +void platform_interrupt_clear(uint32_t irq, uint32_t mask); +uint32_t platform_interrupt_get_enabled(void); +void interrupt_mask(uint32_t irq, unsigned int cpu); +void interrupt_unmask(uint32_t irq, unsigned int cpu); + +/* + * On platforms, supporting cascading interrupts cascaded interrupt numbers + * are greater than or equal to PLATFORM_IRQ_HW_NUM + */ +#define interrupt_is_dsp_direct(irq) (!PLATFORM_IRQ_CHILDREN || \ + irq < PLATFORM_IRQ_HW_NUM) + +void interrupt_init(struct sof *sof); +int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl); +struct irq_cascade_desc *interrupt_get_parent(uint32_t irq); +int interrupt_get_irq(unsigned int irq, const char *cascade); + +static inline void interrupt_set(int irq) +{ + platform_interrupt_set(irq); +} + +static inline void interrupt_clear_mask(int irq, uint32_t mask) +{ + platform_interrupt_clear(irq, mask); +} + +static inline void interrupt_clear(int irq) +{ + interrupt_clear_mask(irq, 1); +} + +static inline uint32_t interrupt_global_disable(void) +{ + return arch_interrupt_global_disable(); +} + +static inline void interrupt_global_enable(uint32_t flags) +{ + arch_interrupt_global_enable(flags); +} + +#if CONFIG_LIBRARY + +/* temporary fix to remove build warning for testbench that will need shortly + * realigned when Zephyr native APIs are used. + */ +static inline void __irq_local_disable(unsigned long flags) {} +static inline void __irq_local_enable(unsigned long flags) {} + +/* disables all IRQ sources on current core - NO effect on library */ +#define irq_local_disable(flags) \ + do { \ + flags = 0; \ + __irq_local_disable(flags); \ + } while (0) + +/* re-enables IRQ sources on current core - NO effect on library*/ +#define irq_local_enable(flags) \ + __irq_local_enable(flags) + +#else +/* disables all IRQ sources on current core */ +#define irq_local_disable(flags) \ + (flags = interrupt_global_disable()) + +/* re-enables IRQ sources on current core */ +#define irq_local_enable(flags) \ + interrupt_global_enable(flags) +#endif +#endif +#endif /* __SOF_DRIVERS_INTERRUPT_H__ */ diff --git a/posix/include/rtos/kernel.h b/posix/include/rtos/kernel.h new file mode 100644 index 000000000000..5921d86b0012 --- /dev/null +++ b/posix/include/rtos/kernel.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022 Intel Corporation. All rights reserved. + * + * Author: Jyri Sarha + */ + +#ifndef __POSIX_RTOS_KERNEL_H__ +#define __POSIX_RTOS_KERNEL_H__ + +#include + +#include + +#ifdef __ZEPHYR__ +#error "This file should only be included in XTOS builds." +#endif + +typedef uint32_t k_ticks_t; + +typedef struct { + k_ticks_t ticks; +} k_timeout_t; + +#define Z_TIMEOUT_TICKS(t) ((k_timeout_t) { .ticks = (t) }) + +#define Z_TIMEOUT_US(t) ((k_timeout_t) { .ticks = clock_us_to_ticks(PLATFORM_DEFAULT_CLOCK, t) }) + +#define Z_TIMEOUT_MS(t) ((k_timeout_t) { .ticks = clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, t) }) + +static inline void k_sleep(k_timeout_t timeout) +{ + wait_delay(timeout.ticks); +} + +static inline void k_msleep(int32_t ms) +{ + wait_delay_ms(ms); +} + +static inline void k_usleep(int32_t us) +{ + wait_delay_us(us); +} + +#endif /* __POSIX_RTOS_KERNEL_H__ */ diff --git a/posix/include/rtos/mutex.h b/posix/include/rtos/mutex.h new file mode 100644 index 000000000000..16c773f4cae4 --- /dev/null +++ b/posix/include/rtos/mutex.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022 Intel Corporation. All rights reserved. + * + */ + +/* + * Simple mutex implementation for SOF. + */ + +#ifndef __POSIX_RTOS_MUTEX_H +#define __POSIX_RTOS_MUTEX_H + +#include +#include +#include + +#define K_FOREVER ((k_timeout_t) { .ticks = 0xffffffff }) + +struct k_mutex { + struct k_spinlock lock; + k_spinlock_key_t key; +}; + +static inline int k_mutex_init(struct k_mutex *mutex) +{ + k_spinlock_init(&mutex->lock); + return 0; +} + +static inline int k_mutex_lock(struct k_mutex *mutex, k_timeout_t timeout) +{ + mutex->key = k_spin_lock(&mutex->lock); + return 0; +} + +static inline int k_mutex_unlock(struct k_mutex *mutex) +{ + k_spin_unlock(&mutex->lock, mutex->key); + return 0; +} + +#endif diff --git a/posix/include/rtos/panic.h b/posix/include/rtos/panic.h new file mode 100644 index 000000000000..65b06a1cab43 --- /dev/null +++ b/posix/include/rtos/panic.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2023 NXP + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __POSIX_RTOS_PANIC_H__ +#define __POSIX_RTOS_PANIC_H__ + +#include +#include +#include + +#ifdef __ZEPHYR__ +#error "This file should only be included in XTOS builds." +#endif /* __ZEPHYR__ */ + +#ifdef __clang_analyzer__ +#define SOF_NORETURN __attribute__((analyzer_noreturn)) +#elif __GNUC__ +#define SOF_NORETURN __attribute__((noreturn)) +#else +#define SOF_NORETURN +#endif + +#ifndef RELATIVE_FILE +#error "This file requires RELATIVE_FILE to be defined. "\ + "Add it to CMake's target with sof_append_relative_path_definitions." +#endif + +void dump_panicinfo(void *addr, struct sof_ipc_panic_info *panic_info); +void panic_dump(uint32_t p, struct sof_ipc_panic_info *panic_info, + uintptr_t *data) SOF_NORETURN; +void __panic(uint32_t p, char *filename, uint32_t linenum) SOF_NORETURN; + +/** panic dump filename and linenumber of the call + * + * \param x panic code defined in ipc/trace.h + */ +#define sof_panic(x) __panic((x), (RELATIVE_FILE), (__LINE__)) + +/* runtime assertion */ +#ifndef assert +#define assert(cond) (void)((cond) || (sof_panic(SOF_IPC_PANIC_ASSERT), 0)) +#endif + +#endif /* __POSIX_RTOS_PANIC_H__ */ diff --git a/posix/include/rtos/sof.h b/posix/include/rtos/sof.h new file mode 100644 index 000000000000..3cbb2e7bfefa --- /dev/null +++ b/posix/include/rtos/sof.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __POSIX_RTOS_SOF_H__ +#define __POSIX_RTOS_SOF_H__ + +#include +#include +#include + +struct cascade_root; +struct clock_info; +struct comp_driver_list; +struct dai_info; +struct dma_info; +struct dma_trace_data; +struct ipc; +struct ll_schedule_domain; +struct mm; +struct mn; +struct ams_shared_context; +struct notify_data; +struct pm_runtime_data; +struct sa; +struct timer; +struct trace; +struct pipeline_posn; +struct probe_pdata; + +/** + * \brief General firmware context. + * This structure holds all the global pointers, which can potentially + * be accessed by SMP code, hence it should be aligned to platform's + * data cache line size. Alignments in the both beginning and end are needed + * to avoid potential before and after data evictions. + */ +struct sof { + /* init data */ + int argc; + char **argv; + + /* ipc */ + struct ipc *ipc; + + /* system agent */ + struct sa *sa; + + /* DMA for Trace*/ + struct dma_trace_data *dmat; + + /* generic trace structure */ + struct trace *trace; + + /* platform clock information */ + struct clock_info *clocks; + + /* default platform timer */ + struct timer *platform_timer; + + /* cpu (arch) timers - 1 per core */ + struct timer *cpu_timers; + + /* timer domain for driving timer LL scheduler */ + struct ll_schedule_domain *platform_timer_domain; + + /* DMA domain for driving DMA LL scheduler */ + struct ll_schedule_domain *platform_dma_domain; + + /* memory map */ + struct mm *memory_map; + + /* runtime power management data */ + struct pm_runtime_data *prd; + +#ifdef CONFIG_AMS + /* asynchronous messaging service */ + struct ams_shared_context *ams_shared_ctx; +#endif + + /* shared notifier data */ + struct notify_data *notify_data; + + /* platform dai information */ + const struct dai_info *dai_info; + + /* platform DMA information */ + const struct dma_info *dma_info; + + /* cascading interrupt controller root */ + struct cascade_root *cascade_root; + + /* list of registered component drivers */ + struct comp_driver_list *comp_drivers; + + /* M/N dividers */ + struct mn *mn; + + /* probes */ + struct probe_pdata *probe; + + /* pipelines stream position */ + struct pipeline_posn *pipeline_posn; + +#ifdef CONFIG_LIBRARY_MANAGER + /* dynamically loaded libraries */ + struct ext_library *ext_library; +#endif + +#if CONFIG_IPC_MAJOR_4 + /* lock for fw_reg access */ + struct k_spinlock fw_reg_lock; +#endif + + __aligned(PLATFORM_DCACHE_ALIGN) int alignment[0]; +} __aligned(PLATFORM_DCACHE_ALIGN); + +struct sof *sof_get(void); + +#endif /* __POSIX_RTOS_SOF_H__ */ diff --git a/posix/include/rtos/spinlock.h b/posix/include/rtos/spinlock.h new file mode 100644 index 000000000000..beb20ab6e847 --- /dev/null +++ b/posix/include/rtos/spinlock.h @@ -0,0 +1,163 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +/* + * Simple spinlock implementation for SOF. + */ + +#ifndef __POSIX_RTOS_SPINLOCK_H__ +#define __POSIX_RTOS_SPINLOCK_H__ + +#include +typedef uint32_t k_spinlock_key_t; +#include +#include + +#include + +/* + * Lock debugging provides a simple interface to debug deadlocks. The rmbox + * trace output will show an output :- + * + * 0xd70 [41.306406] delta [0.359638] lock eal + * 0xd80 [41.306409] delta [0.000002] value 0x00000000000001b7 + * 0xd90 [41.306411] delta [0.000002] value 0x0000000000000001 + * 0xda0 [41.306413] delta [0.000002] value 0x0000000001000348 + * + * "eal" indicates we are holding a lock with interrupts OFF. The next value + * is the line number of where the lock was acquired. The second number is the + * number of other locks held whilst this lock is held and the subsequent + * numbers list each lock and the line number of it's holder. e.g. to find + * the locks :- + * + * grep -rn lock --include *.c | grep 840 (search for lock at line 0x348) + * src/drivers/dw-dma.c:840: spinlock_init(&dma->lock); + * + * grep -rn lock --include *.c | grep 439 + * src/lib/alloc.c:439: k_spin_lock_irq(&memmap.lock, flags); + * + * Every lock entry and exit shows LcE and LcX in trace alongside the lock + * line numbers in hex. e.g. + * + * 0xfd60 [11032.730567] delta [0.000004] lock LcE + * 0xfd70 [11032.730569] delta [0.000002] value 0x00000000000000ae + * + * Deadlock can be confirmed in rmbox :- + * + * Debug log: + * debug: 0x0 (00) = 0xdead0007 (-559087609) |....| + * .... + * Error log: + * using 19.20MHz timestamp clock + * 0xc30 [26.247240] delta [26.245851] lock DED + * 0xc40 [26.247242] delta [0.000002] value 0x00000000000002b4 + * 0xc50 [26.247244] delta [0.000002] value 0x0000000000000109 + * + * DED means deadlock has been detected and the DSP is now halted. The first + * value after DEA is the line number where deadlock occurs and the second + * number is the line number where the lock is allocated. These can be grepped + * like above. + */ + +#if CONFIG_DEBUG_LOCKS + +#include +#include +#include +#include + +#define DBG_LOCK_USERS 8 +#define DBG_LOCK_TRIES 10000 + +extern uint32_t lock_dbg_atomic; +extern uint32_t lock_dbg_user[DBG_LOCK_USERS]; + +extern struct tr_ctx sl_tr; + +/* panic on deadlock */ +#define spin_try_lock_dbg(lock, line) \ + do { \ + int __tries; \ + for (__tries = DBG_LOCK_TRIES; __tries > 0; __tries--) { \ + if (arch_try_lock(lock)) \ + break; /* lock acquired */ \ + } \ + if (__tries == 0) { \ + tr_err_atomic(&sl_tr, "DED"); \ + tr_err_atomic(&sl_tr, "line: %d", line); \ + tr_err_atomic(&sl_tr, "user: %d", (lock)->user); \ + panic(SOF_IPC_PANIC_DEADLOCK); /* lock not acquired */ \ + } \ + } while (0) + +#if CONFIG_DEBUG_LOCKS_VERBOSE +#define spin_lock_log(lock, line) \ + do { \ + if (lock_dbg_atomic) { \ + int __i = 0; \ + int __count = lock_dbg_atomic >= DBG_LOCK_USERS \ + ? DBG_LOCK_USERS : lock_dbg_atomic; \ + tr_err_atomic(&sl_tr, "eal"); \ + tr_err_atomic(&sl_tr, "line: %d", line); \ + tr_err_atomic(&sl_tr, "dbg_atomic: %d", lock_dbg_atomic); \ + for (__i = 0; __i < __count; __i++) { \ + tr_err_atomic(&sl_tr, "value: %d", \ + (lock_dbg_atomic << 24) | \ + lock_dbg_user[__i]); \ + } \ + } \ + } while (0) + +#define spin_lock_dbg(line) \ + do { \ + tr_info(&sl_tr, "LcE"); \ + tr_info(&sl_tr, "line: %d", line); \ + } while (0) + +#define spin_unlock_dbg(line) \ + do { \ + tr_info(&sl_tr, "LcX"); \ + tr_info(&sl_tr, "line: %d", line); \ + } while (0) + +#else /* CONFIG_DEBUG_LOCKS_VERBOSE */ +#define spin_lock_log(lock, line) do {} while (0) +#define spin_lock_dbg(line) do {} while (0) +#define spin_unlock_dbg(line) do {} while (0) +#endif /* CONFIG_DEBUG_LOCKS_VERBOSE */ + +#else /* CONFIG_DEBUG_LOCKS */ + +#define trace_lock(__e) do {} while (0) +#define tracev_lock(__e) do {} while (0) + +#define spin_lock_dbg(line) do {} while (0) +#define spin_unlock_dbg(line) do {} while (0) + +#endif /* CONFIG_DEBUG_LOCKS */ + +/* all SMP spinlocks need init, nothing todo on UP */ +static inline void _spinlock_init(struct k_spinlock *lock, int line) +{ + arch_spinlock_init(lock); +#if CONFIG_DEBUG_LOCKS + lock->user = line; +#endif +} + +#define k_spinlock_init(lock) _spinlock_init(lock, __LINE__) + +/* disables all IRQ sources and takes lock - enter atomic context */ +k_spinlock_key_t _k_spin_lock_irq(struct k_spinlock *lock); +#define k_spin_lock(lock) _k_spin_lock_irq(lock) + +/* re-enables current IRQ sources and releases lock - leave atomic context */ +void _k_spin_unlock_irq(struct k_spinlock *lock, k_spinlock_key_t key, int line); +#define k_spin_unlock(lock, key) _k_spin_unlock_irq(lock, key, __LINE__) + +#endif /* __POSIX_RTOS_SPINLOCK_H__ */ diff --git a/posix/include/rtos/string.h b/posix/include/rtos/string.h new file mode 100644 index 000000000000..b3ca03f9ca4e --- /dev/null +++ b/posix/include/rtos/string.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __POSIX_RTOS_STRING_H__ +#define __POSIX_RTOS_STRING_H__ + +#include +#include + +/* C memcpy for arch that don't have arch_memcpy() */ +void cmemcpy(void *dest, void *src, size_t size); +int memcmp(const void *p, const void *q, size_t count); +int rstrlen(const char *s); +int rstrcmp(const char *s1, const char *s2); + +#if defined(arch_memcpy) +#define rmemcpy(dest, src, size) \ + arch_memcpy(dest, src, size) +#else +#define rmemcpy(dest, src, size) \ + cmemcpy(dest, src, size) +#endif + +#endif /* __POSIX_RTOS_STRING_H__ */ diff --git a/posix/include/rtos/task.h b/posix/include/rtos/task.h new file mode 100644 index 000000000000..5aca574a5787 --- /dev/null +++ b/posix/include/rtos/task.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __POSIX_RTOS_TASK_H__ +#define __POSIX_RTOS_TASK_H__ + +#include +#include +#include +#include +#include +#include +#include + +struct comp_dev; +struct sof; + +/** \brief Predefined LL task priorities. */ +#define SOF_TASK_PRI_HIGH 0 /* priority level 0 - high */ +#define SOF_TASK_PRI_MED 4 /* priority level 4 - medium */ +#define SOF_TASK_PRI_LOW 9 /* priority level 9 - low */ + +/** \brief Predefined EDF task deadlines. */ +#define SOF_TASK_DEADLINE_IDLE UINT64_MAX +#define SOF_TASK_DEADLINE_ALMOST_IDLE (SOF_TASK_DEADLINE_IDLE - 1) +#define SOF_TASK_DEADLINE_NOW 0 + +/** \brief Task counter initial value. */ +#define SOF_TASK_SKIP_COUNT 0xFFFFu + +/** \brief Task states. */ +enum task_state { + SOF_TASK_STATE_INIT = 0, + SOF_TASK_STATE_QUEUED, + SOF_TASK_STATE_PENDING, + SOF_TASK_STATE_RUNNING, + SOF_TASK_STATE_PREEMPTED, + SOF_TASK_STATE_COMPLETED, + SOF_TASK_STATE_FREE, + SOF_TASK_STATE_CANCEL, + SOF_TASK_STATE_RESCHEDULE, +}; + +/** \brief Task operations. */ +struct task_ops { + enum task_state (*run)(void *data); /**< task's main operation */ + void (*complete)(void *data); /**< executed on completion */ + uint64_t (*get_deadline)(void *data); /**< returns current deadline */ +}; + +/** \brief Task used by schedulers. */ +struct task { + uint64_t start; /**< start time in [ms] since now (LL only) */ + const struct sof_uuid_entry *uid; /**< Uuid */ + uint16_t type; /**< type of the task (LL or EDF) */ + uint16_t priority; /**< priority of the task (used by LL) */ + uint16_t core; /**< execution core */ + uint16_t flags; /**< custom flags */ + enum task_state state; /**< current state */ + void *data; /**< custom data passed to all ops */ + struct list_item list; /**< used by schedulers to hold tasks */ + void *priv_data; /**< task private data */ + struct task_ops ops; /**< task operations */ +#if defined(CONFIG_SCHEDULE_LOG_CYCLE_STATISTICS) + uint32_t cycles_sum; + uint32_t cycles_max; + uint32_t cycles_cnt; +#endif +#if CONFIG_PERFORMANCE_COUNTERS + struct perf_cnt_data pcd; +#endif +}; + +static inline bool task_is_active(struct task *task) +{ + switch (task->state) { + case SOF_TASK_STATE_QUEUED: + case SOF_TASK_STATE_PENDING: + case SOF_TASK_STATE_RUNNING: + case SOF_TASK_STATE_PREEMPTED: + case SOF_TASK_STATE_RESCHEDULE: + return true; + default: + return false; + } +} + +static inline enum task_state task_run(struct task *task) +{ + assert(task->ops.run); + + return task->ops.run(task->data); +} + +static inline void task_complete(struct task *task) +{ + if (task->ops.complete) + task->ops.complete(task->data); +} + +static inline uint64_t task_get_deadline(struct task *task) +{ + assert(task->ops.get_deadline); + + return task->ops.get_deadline(task->data); +} + +enum task_state task_main_primary_core(void *data); + +enum task_state task_main_secondary_core(void *data); + +void task_main_init(void); + +void task_main_free(void); + +int task_main_start(struct sof *sof); +int start_complete(void); + +#endif /* __POSIX_RTOS_TASK_H__ */ diff --git a/posix/include/rtos/timer.h b/posix/include/rtos/timer.h new file mode 100644 index 000000000000..b9756b66c87c --- /dev/null +++ b/posix/include/rtos/timer.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Janusz Jankowski + */ + +#ifndef __SOF_DRIVERS_TIMER_H__ +#define __SOF_DRIVERS_TIMER_H__ + +#include +#include +#include +#include +#include +#include + +struct comp_dev; +struct sof_ipc_stream_posn; + +#define TIMER0 0 +#define TIMER1 1 +#define TIMER2 2 +#define TIMER3 3 +#define TIMER4 4 + +int timer_register(struct timer *timer, void (*handler)(void *arg), void *arg); +void timer_unregister(struct timer *timer, void *arg); +void timer_enable(struct timer *timer, void *arg, int core); +void timer_disable(struct timer *timer, void *arg, int core); + +static inline struct timer *timer_get(void) +{ + return sof_get()->platform_timer; +} + +static inline struct timer *cpu_timer_get(void) +{ + return &(sof_get()->cpu_timers[cpu_get_id()]); +} + +static inline int64_t timer_set(struct timer *timer, uint64_t ticks) +{ + return arch_timer_set(timer, ticks); +} + +void timer_set_ms(struct timer *timer, unsigned int ms); + +static inline void timer_clear(struct timer *timer) +{ + arch_timer_clear(timer); +} + +unsigned int timer_get_count(struct timer *timer); + +unsigned int timer_get_count_delta(struct timer *timer); + +static inline uint64_t timer_get_system(struct timer *timer) +{ + return arch_timer_get_system(timer); +} + +int64_t platform_timer_set(struct timer *timer, uint64_t ticks); +void platform_timer_clear(struct timer *timer); +uint64_t platform_timer_get(struct timer *timer); +uint64_t platform_timer_get_atomic(struct timer *timer); + +static inline uint64_t platform_safe_get_time(struct timer *timer) +{ + /* Default to something small but at least 1.0 microsecond so it + * does not look like an uninitialized zero; not even when the + * user does not request any microseconds decimals. See + * DEFAULT_CLOCK constant in logger.c + */ + return timer ? platform_timer_get(timer) : 50; +} + +void platform_timer_start(struct timer *timer); +void platform_timer_stop(struct timer *timer); + +static inline uint64_t k_ms_to_cyc_ceil64(uint64_t ms) +{ + return clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, ms); +} + +static inline uint64_t k_us_to_cyc_ceil64(uint64_t us) +{ + return clock_us_to_ticks(PLATFORM_DEFAULT_CLOCK, us); +} + +static inline uint64_t k_ns_to_cyc_near64(uint64_t ns) +{ + return clock_ns_to_ticks(PLATFORM_DEFAULT_CLOCK, ns); +} + +static inline uint64_t k_cyc_to_ms_near64(uint64_t ticks) +{ + return ticks / clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, 1); +} + +static inline uint64_t k_cyc_to_us_near64(uint64_t ticks) +{ + return ticks / clock_us_to_ticks(PLATFORM_DEFAULT_CLOCK, 1); +} + +static inline uint64_t sof_cycle_get_64(void) +{ + return platform_timer_get(timer_get()); +} + +static inline uint64_t sof_cycle_get_64_atomic(void) +{ + return platform_timer_get_atomic(timer_get()); +} + +static inline uint64_t sof_cycle_get_64_safe(void) +{ + return platform_safe_get_time(timer_get()); +} + +/* get timestamp for host stream DMA position */ +void platform_host_timestamp(struct comp_dev *host, + struct sof_ipc_stream_posn *posn); + +/* get timestamp for DAI stream DMA position */ +void platform_dai_timestamp(struct comp_dev *dai, + struct sof_ipc_stream_posn *posn); + +/* get current wallclock for componnent */ +void platform_dai_wallclock(struct comp_dev *dai, uint64_t *wallclock); + +#endif /* __SOF_DRIVERS_TIMER_H__ */ diff --git a/posix/include/rtos/wait.h b/posix/include/rtos/wait.h new file mode 100644 index 000000000000..b6874888a763 --- /dev/null +++ b/posix/include/rtos/wait.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +/* + * Simple wait for event completion and signaling with timeouts. + */ + +#ifndef __POSIX_RTOS_WAIT_H__ +#define __POSIX_RTOS_WAIT_H__ + +#include +#include + +#if !CONFIG_LIBRARY +#include +#include +#include +#include +#include +#include + +extern struct tr_ctx wait_tr; + +static inline void wait_for_interrupt(int level) +{ + LOG_MODULE_DECLARE(wait, CONFIG_SOF_LOG_LEVEL); + + tr_dbg(&wait_tr, "WFE"); +#if CONFIG_DEBUG_LOCKS + if (lock_dbg_atomic) + tr_err_atomic(&wait_tr, "atm"); +#endif + platform_wait_for_interrupt(level); + tr_dbg(&wait_tr, "WFX"); +} + +/** + * \brief Waits at least passed number of clocks. + * \param[in] number_of_clks Minimum number of clocks to wait. + */ +void wait_delay(uint64_t number_of_clks); + +/** + * \brief Waits at least passed number of milliseconds. + * \param[in] ms Minimum number of milliseconds to wait. + */ +void wait_delay_ms(uint64_t ms); + +/** + * \brief Waits at least passed number of microseconds. + * \param[in] us Minimum number of microseconds to wait. + */ +void wait_delay_us(uint64_t us); +#else +static inline void wait_delay(uint64_t number_of_clks) {} +static inline void wait_delay_ms(uint64_t ms) {} +static inline void wait_delay_us(uint64_t us) {} +#endif + +int poll_for_register_delay(uint32_t reg, uint32_t mask, + uint32_t val, uint64_t us); + +#endif /* __POSIX_RTOS_WAIT_H__ */ diff --git a/posix/include/sof/compiler_attributes.h b/posix/include/sof/compiler_attributes.h new file mode 100644 index 000000000000..bf88bfac4369 --- /dev/null +++ b/posix/include/sof/compiler_attributes.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski + */ + +#ifdef __ZEPHYR__ + +/* Get __sparse_cache and __sparse_force definitions if __CHECKER__ is defined */ +#include + +#else + +#define __sparse_cache +#define __sparse_force + +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + +#ifndef __unused +#define __unused __attribute__((unused)) +#endif + +#endif + +#ifndef __aligned +#define __aligned(x) __attribute__((__aligned__(x))) +#endif + +#ifndef __section +#define __section(x) __attribute__((section(x))) +#endif + +/* The fallthrough attribute is supported since GCC 7.0 + * and Clang 10.0.0. + * + * Note that Clang sets __GNUC__ == 4 so the GCC version + * test will not be true here, and must go through + * the Clang version test. + */ +#if ((defined(__GNUC__) && (__GNUC__ >= 7)) || \ + (defined(__clang__) && (__clang_major__ >= 10))) && !defined(__CHECKER__) + +#define COMPILER_FALLTHROUGH __attribute__((fallthrough)) + +#else + +#define COMPILER_FALLTHROUGH /* fallthrough */ + +#endif diff --git a/posix/include/sof/compiler_info.h b/posix/include/sof/compiler_info.h new file mode 100644 index 000000000000..9716575b7188 --- /dev/null +++ b/posix/include/sof/compiler_info.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski + */ + +/** + * \file xtos/include/sof/compiler_info.h + * \brief Compiler version and name descriptor + * \author Karol Trzcinski + */ + +#ifndef __SOF_COMPILER_INFO_H__ +#define __SOF_COMPILER_INFO_H__ + +#include + +#endif /* __SOF_COMPILER_INFO_H__ */ diff --git a/posix/include/sof/init.h b/posix/include/sof/init.h new file mode 100644 index 000000000000..ce8522cd34ad --- /dev/null +++ b/posix/include/sof/init.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOF_INIT_H__ +#define __SOF_INIT_H__ + +struct sof; + +/* main firmware entry point - argc and argv not currently used */ +#ifndef CONFIG_ARCH_POSIX +int main(int argc, char *argv[]); +#endif + +#if CONFIG_MULTICORE + +int secondary_core_init(struct sof *sof); + +#endif /* CONFIG_MULTICORE */ + +int arch_init(void); + +#endif /* __SOF_INIT_H__ */ diff --git a/posix/include/sof/lib/agent.h b/posix/include/sof/lib/agent.h new file mode 100644 index 000000000000..6e70a4ce997d --- /dev/null +++ b/posix/include/sof/lib/agent.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOF_LIB_AGENT_H__ +#define __SOF_LIB_AGENT_H__ + +#include +#include +#include +#include +#include + +#include +#include + +struct sof; + +/* simple agent */ +struct sa { + uint64_t last_check; /* time of last activity checking */ + uint64_t panic_timeout; /* threshold of panic */ + uint64_t warn_timeout; /* threshold of warning */ +#if CONFIG_PERFORMANCE_COUNTERS + struct perf_cnt_data pcd; +#endif + struct task work; + atomic_t panic_cnt; /**< ref counter for panic_on_delay property */ + bool panic_on_delay; /**< emits panic on delay if true */ +}; + +#if CONFIG_HAVE_AGENT + +/** + * Enables or disables panic on agent delay. + * @param enabled True for panic enabling, false otherwise. + */ +static inline void sa_set_panic_on_delay(bool enabled) +{ + struct sa *sa = sof_get()->sa; + + if (enabled) + atomic_add(&sa->panic_cnt, 1); + else + atomic_sub(&sa->panic_cnt, 1); + + /* enable panic only if no refs */ + sa->panic_on_delay = !atomic_read(&sa->panic_cnt); + +} + +void sa_init(struct sof *sof, uint64_t timeout); +void sa_exit(struct sof *sof); + +#else + +static inline void sa_init(struct sof *sof, uint64_t timeout) { } +static inline void sa_exit(struct sof *sof) { } +static inline void sa_set_panic_on_delay(bool enabled) { } + +#endif + +#endif /* __SOF_LIB_AGENT_H__ */ diff --git a/posix/include/sof/lib/cpu.h b/posix/include/sof/lib/cpu.h new file mode 100644 index 000000000000..d53e15e7535a --- /dev/null +++ b/posix/include/sof/lib/cpu.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Tomasz Lauda + */ + +/** + * \file xtos/include/sof/lib/cpu.h + * \brief CPU header file + * \authors Tomasz Lauda + */ + +#ifndef __SOF_LIB_CPU_H__ +#define __SOF_LIB_CPU_H__ +#ifndef __ZEPHYR__ + +#include + +#if !defined(__ASSEMBLER__) && !defined(LINKER) + +#include +#include + +/* let the compiler optimise when in single core mode */ +#if CONFIG_CORE_COUNT == 1 + +static inline int cpu_get_id(void) +{ + return 0; +} + +static inline bool cpu_is_primary(int id) +{ + return 1; +} + +static inline bool cpu_is_me(int id) +{ + return 1; +} + +#else + +static inline int cpu_get_id(void) +{ + return arch_cpu_get_id(); +} + +static inline bool cpu_is_primary(int id) +{ + return id == PLATFORM_PRIMARY_CORE_ID; +} + +static inline bool cpu_is_me(int id) +{ + return id == cpu_get_id(); +} +#endif + +static inline int cpu_enable_core(int id) +{ + return arch_cpu_enable_core(id); +} + +static inline void cpu_disable_core(int id) +{ + arch_cpu_disable_core(id); +} + +static inline int cpu_is_core_enabled(int id) +{ + return arch_cpu_is_core_enabled(id); +} + +static inline int cpu_enabled_cores(void) +{ + return arch_cpu_enabled_cores(); +} + +static inline int cpu_restore_secondary_cores(void) +{ + return arch_cpu_restore_secondary_cores(); +} + +static inline int cpu_secondary_cores_prepare_d0ix(void) +{ + return arch_cpu_secondary_cores_prepare_d0ix(); +} + +#endif +#endif +#endif /* __SOF_LIB_CPU_H__ */ diff --git a/posix/include/sof/lib/dai.h b/posix/include/sof/lib/dai.h new file mode 100644 index 000000000000..47677c19ae4c --- /dev/null +++ b/posix/include/sof/lib/dai.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +/** + * \file xtos/include/sof/lib/dai.h + * \brief DAI Drivers definition + * \author Liam Girdwood + * \author Keyon Jie + */ + +#ifndef __SOF_LIB_DAI_H__ +#define __SOF_LIB_DAI_H__ + +#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS +#include +#else +#include +#endif + +struct ipc4_ipcgtw_cmd; + +static inline int ipcgtw_process_cmd(const struct ipc4_ipcgtw_cmd *cmd, + void *reply_payload, uint32_t *reply_payload_size) +{ + return 0; +} + +#endif /* __SOF_LIB_DAI_H__ */ diff --git a/posix/include/sof/lib/dma.h b/posix/include/sof/lib/dma.h new file mode 100644 index 000000000000..af9e4191cbbb --- /dev/null +++ b/posix/include/sof/lib/dma.h @@ -0,0 +1,589 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +/** + * \file xtos/include/sof/lib/dma.h + * \brief DMA Drivers definition + * \author Liam Girdwood + * \author Keyon Jie + */ + +#ifndef __SOF_LIB_DMA_H__ +#define __SOF_LIB_DMA_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ZEPHYR__ +#include +#include +#endif + +struct comp_buffer; + +/** \addtogroup sof_dma_drivers DMA Drivers + * DMA Drivers API specification. + * @{ + */ + +/* DMA direction bitmasks used to define DMA copy direction */ +#define DMA_DIR_MEM_TO_MEM BIT(0) /**< local memory copy */ +#define DMA_DIR_HMEM_TO_LMEM BIT(1) /**< host memory to local mem copy */ +#define DMA_DIR_LMEM_TO_HMEM BIT(2) /**< local mem to host mem copy */ +#define DMA_DIR_MEM_TO_DEV BIT(3) /**< local mem to dev copy */ +#define DMA_DIR_DEV_TO_MEM BIT(4) /**< dev to local mem copy */ +#define DMA_DIR_DEV_TO_DEV BIT(5) /**< dev to dev copy */ + +/* DMA capabilities bitmasks used to define the type of DMA */ +#define DMA_CAP_HDA BIT(0) /**< HDA DMA */ +#define DMA_CAP_GP_LP BIT(1) /**< GP LP DMA */ +#define DMA_CAP_GP_HP BIT(2) /**< GP HP DMA */ +#define DMA_CAP_BT BIT(3) /**< BT DMA */ +#define DMA_CAP_SP BIT(4) /**< SP DMA */ +#define DMA_CAP_DMIC BIT(5) /**< ACP DMA DMIC > */ +#define DMA_CAP_SP_VIRTUAL BIT(6) /**< SP VIRTUAL DMA */ +#define DMA_CAP_HS_VIRTUAL BIT(7) /**< HS VIRTUAL DMA */ + +/* DMA dev type bitmasks used to define the type of DMA */ + +#define DMA_DEV_HOST BIT(0) /**< connectable to host */ +#define DMA_DEV_HDA BIT(1) /**< connectable to HD/A link */ +#define DMA_DEV_SSP BIT(2) /**< connectable to SSP fifo */ +#define DMA_DEV_DMIC BIT(3) /**< connectable to DMIC fifo */ +#define DMA_DEV_SSI BIT(4) /**< connectable to SSI / SPI fifo */ +#define DMA_DEV_ALH BIT(5) /**< connectable to ALH link */ +#define DMA_DEV_SAI BIT(6) /**< connectable to SAI fifo */ +#define DMA_DEV_ESAI BIT(7) /**< connectable to ESAI fifo */ +#define DMA_DEV_BT BIT(8) /**< connectable to ACP BT I2S */ +#define DMA_DEV_SP BIT(9) /**< connectable to ACP SP I2S */ +#define DMA_DEV_AFE_MEMIF BIT(10) /**< connectable to AFE fifo */ +#define DMA_DEV_SP_VIRTUAL BIT(11) /**< connectable to ACP SP VIRTUAL I2S */ +#define DMA_DEV_HS_VIRTUAL BIT(12) /**< connectable to ACP HS VIRTUAL I2S */ + +/* DMA access privilege flag */ +#define DMA_ACCESS_EXCLUSIVE 1 +#define DMA_ACCESS_SHARED 0 + +/* DMA copy flags */ +#define DMA_COPY_BLOCKING BIT(0) +#define DMA_COPY_ONE_SHOT BIT(1) + +/* We will use this enum in cb handler to inform dma what + * action we need to perform. + */ +enum dma_cb_status { + DMA_CB_STATUS_RELOAD = 0, + DMA_CB_STATUS_END, +}; + +/* DMA interrupt commands */ +enum dma_irq_cmd { + DMA_IRQ_STATUS_GET = 0, + DMA_IRQ_CLEAR, + DMA_IRQ_MASK, + DMA_IRQ_UNMASK +}; + +#define DMA_CHAN_INVALID 0xFFFFFFFF +#define DMA_CORE_INVALID 0xFFFFFFFF + +/* Attributes have been ported to Zephyr. This condition is necessary until full support of + * CONFIG_SOF_ZEPHYR_STRICT_HEADERS. + */ +#ifndef CONFIG_ZEPHYR_NATIVE_DRIVERS +/* DMA attributes */ +#define DMA_ATTR_BUFFER_ALIGNMENT 0 +#define DMA_ATTR_COPY_ALIGNMENT 1 +#define DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT 2 +#define DMA_ATTR_BUFFER_PERIOD_COUNT 3 +#endif + +struct dma; + +/** + * \brief Element of SG list (as array item). + */ +struct dma_sg_elem { + uint32_t src; /**< source address */ + uint32_t dest; /**< destination address */ + uint32_t size; /**< size (in bytes) */ +}; + +/** + * \brief Data used in DMA callbacks. + */ +struct dma_cb_data { + struct dma_chan_data *channel; + struct dma_sg_elem elem; + enum dma_cb_status status; +}; + +/** + * \brief SG elem array. + */ +struct dma_sg_elem_array { + uint32_t count; /**< number of elements in elems */ + struct dma_sg_elem *elems; /**< elements */ +}; + +/* DMA physical SG params */ +struct dma_sg_config { + uint32_t src_width; /* in bytes */ + uint32_t dest_width; /* in bytes */ + uint32_t burst_elems; + uint32_t direction; + uint32_t src_dev; + uint32_t dest_dev; + uint32_t cyclic; /* circular buffer */ + uint64_t period; + struct dma_sg_elem_array elem_array; /* array of dma_sg elems */ + bool scatter; + bool irq_disabled; + /* true if configured DMA channel is the scheduling source */ + bool is_scheduling_source; +}; + +struct dma_chan_status { + uint32_t state; + uint32_t flags; + uint32_t w_pos; + uint32_t r_pos; + uint32_t timestamp; + + /* dma position info for ipc4 */ + void *ipc_posn_data; +}; + +/* DMA operations */ +struct dma_ops { + + struct dma_chan_data *(*channel_get)(struct dma *dma, + unsigned int req_channel); + void (*channel_put)(struct dma_chan_data *channel); + + int (*start)(struct dma_chan_data *channel); + int (*stop)(struct dma_chan_data *channel); + int (*stop_delayed)(struct dma_chan_data *channel); + int (*copy)(struct dma_chan_data *channel, int bytes, uint32_t flags); + int (*pause)(struct dma_chan_data *channel); + int (*release)(struct dma_chan_data *channel); + int (*status)(struct dma_chan_data *channel, + struct dma_chan_status *status, uint8_t direction); + + int (*set_config)(struct dma_chan_data *channel, + struct dma_sg_config *config); + + int (*probe)(struct dma *dma); + int (*remove)(struct dma *dma); + + int (*get_data_size)(struct dma_chan_data *channel, uint32_t *avail, + uint32_t *free); + + int (*get_attribute)(struct dma *dma, uint32_t type, uint32_t *value); + + int (*interrupt)(struct dma_chan_data *channel, enum dma_irq_cmd cmd); +}; + +/* DMA platform data */ +struct dma_plat_data { + uint32_t id; + uint32_t dir; /* bitmask of supported copy directions */ + uint32_t caps; /* bitmask of supported capabilities */ + uint32_t devs; /* bitmask of supported devs */ + uint32_t base; + uint32_t channels; + int irq; + const char *irq_name; + uint32_t chan_size; + const void *drv_plat_data; +#ifdef __ZEPHYR__ + uint32_t period_count; +#endif +}; + +struct dma { + struct dma_plat_data plat_data; + struct k_spinlock lock; /**< locking mechanism */ + int sref; /**< simple ref counter, guarded by lock */ + const struct dma_ops *ops; + atomic_t num_channels_busy; /* number of busy channels */ + struct dma_chan_data *chan; /* channels array */ +#ifdef __ZEPHYR__ + const struct device *z_dev; /* Zephyr driver */ +#endif + void *priv_data; +}; + +struct dma_chan_data { + struct dma *dma; + + uint32_t status; + uint32_t direction; + uint32_t desc_count; + uint32_t index; + uint32_t core; + uint64_t period; /* DMA channel's transfer period in us */ + /* true if this DMA channel is the scheduling source */ + bool is_scheduling_source; + + /* device specific data set by the device that requests the DMA channel */ + void *dev_data; + + void *priv_data; +}; + +struct dma_info { + struct dma *dma_array; + size_t num_dmas; +}; + +struct audio_stream; +typedef int (*dma_process_func)(const struct audio_stream __sparse_cache *source, + uint32_t ioffset, struct audio_stream __sparse_cache *sink, + uint32_t ooffset, uint32_t frames); + +/** + * \brief API to initialize a platform DMA controllers. + * + * \param[in] sof Pointer to firmware main context. + */ +int dmac_init(struct sof *sof); + +/** + * \brief API to request a platform DMAC. + * + * Users can request DMAC based on dev type, copy direction, capabilities + * and access privilege. + * For exclusive access, ret DMAC with no channels draining. + * For shared access, ret DMAC with the least number of channels draining. + */ +struct dma *dma_get(uint32_t dir, uint32_t caps, uint32_t dev, uint32_t flags); + +/** + * \brief API to release a platform DMAC. + * + * @param[in] dma DMAC to relese. + */ +void dma_put(struct dma *dma); + +#define dma_set_drvdata(dma, data) \ + (dma->priv_data = data) +#define dma_get_drvdata(dma) \ + dma->priv_data +#define dma_base(dma) \ + dma->plat_data.base +#define dma_irq(dma) \ + dma->plat_data.irq +#define dma_irq_name(dma) \ + dma->plat_data.irq_name +#define dma_chan_size(dma) \ + dma->plat_data.chan_size +#define dma_chan_base(dma, chan) \ + (dma->plat_data.base + chan * dma->plat_data.chan_size) +#define dma_chan_get_data(chan) \ + ((chan)->priv_data) +#define dma_chan_set_data(chan, data) \ + ((chan)->priv_data = data) + +/* DMA API + * Programming flow is :- + * + * 1) dma_channel_get() + * 2) notifier_register() + * 3) dma_set_config() + * 4) dma_start() + * ... DMA now running ... + * 5) dma_stop() + * 6) dma_stop_delayed() + * 7) dma_channel_put() + */ + +static inline struct dma_chan_data *dma_channel_get_legacy(struct dma *dma, + int req_channel) +{ + if (!dma || !dma->ops || !dma->ops->channel_get) + return NULL; + + struct dma_chan_data *chan = dma->ops->channel_get(dma, req_channel); + + return chan; +} + +static inline void dma_channel_put_legacy(struct dma_chan_data *channel) +{ + channel->dma->ops->channel_put(channel); +} + +static inline int dma_start_legacy(struct dma_chan_data *channel) +{ + return channel->dma->ops->start(channel); +} + +static inline int dma_stop_legacy(struct dma_chan_data *channel) +{ + if (channel->dma->ops->stop) + return channel->dma->ops->stop(channel); + + return 0; +} + +static inline int dma_stop_delayed_legacy(struct dma_chan_data *channel) +{ + if (channel->dma->ops->stop_delayed) + return channel->dma->ops->stop_delayed(channel); + + return 0; +} + +/** \defgroup sof_dma_copy_func static int dma_copy (struct dma_chan_data * channel, int bytes, uint32_t flags) + * + * This function is in a separate subgroup to solve a name clash with + * struct dma_copy {} + * @{ + */ +static inline int dma_copy_legacy(struct dma_chan_data *channel, int bytes, + uint32_t flags) +{ + return channel->dma->ops->copy(channel, bytes, flags); +} +/** @} */ + +static inline int dma_pause_legacy(struct dma_chan_data *channel) +{ + if (channel->dma->ops->pause) + return channel->dma->ops->pause(channel); + + return 0; +} + +static inline int dma_release_legacy(struct dma_chan_data *channel) +{ + if (channel->dma->ops->release) + return channel->dma->ops->release(channel); + + return 0; +} + +static inline int dma_status_legacy(struct dma_chan_data *channel, + struct dma_chan_status *status, uint8_t direction) +{ + return channel->dma->ops->status(channel, status, direction); +} + +static inline int dma_set_config_legacy(struct dma_chan_data *channel, + struct dma_sg_config *config) +{ + return channel->dma->ops->set_config(channel, config); +} + +static inline int dma_probe_legacy(struct dma *dma) +{ + return dma->ops->probe(dma); +} + +static inline int dma_remove_legacy(struct dma *dma) +{ + return dma->ops->remove(dma); +} + +static inline int dma_get_data_size_legacy(struct dma_chan_data *channel, + uint32_t *avail, uint32_t *free) +{ + return channel->dma->ops->get_data_size(channel, avail, free); +} + +static inline int dma_get_attribute_legacy(struct dma *dma, uint32_t type, + uint32_t *value) +{ + return dma->ops->get_attribute(dma, type, value); +} + +static inline int dma_interrupt_legacy(struct dma_chan_data *channel, + enum dma_irq_cmd cmd) +{ + return channel->dma->ops->interrupt(channel, cmd); +} + +/* DMA hardware register operations */ +static inline uint32_t dma_reg_read(struct dma *dma, uint32_t reg) +{ + return io_reg_read(dma_base(dma) + reg); +} + +static inline uint16_t dma_reg_read16(struct dma *dma, uint32_t reg) +{ + return io_reg_read16(dma_base(dma) + reg); +} + +static inline void dma_reg_write(struct dma *dma, uint32_t reg, uint32_t value) +{ + io_reg_write(dma_base(dma) + reg, value); +} + +static inline void dma_reg_write16(struct dma *dma, uint32_t reg, + uint16_t value) +{ + io_reg_write16(dma_base(dma) + reg, value); +} + +static inline void dma_reg_update_bits(struct dma *dma, uint32_t reg, + uint32_t mask, uint32_t value) +{ + io_reg_update_bits(dma_base(dma) + reg, mask, value); +} + +static inline uint32_t dma_chan_reg_read(struct dma_chan_data *channel, + uint32_t reg) +{ + return io_reg_read(dma_chan_base(channel->dma, channel->index) + reg); +} + +static inline uint16_t dma_chan_reg_read16(struct dma_chan_data *channel, + uint32_t reg) +{ + return io_reg_read16(dma_chan_base(channel->dma, channel->index) + reg); +} + +static inline void dma_chan_reg_write(struct dma_chan_data *channel, + uint32_t reg, uint32_t value) +{ + io_reg_write(dma_chan_base(channel->dma, channel->index) + reg, value); +} + +static inline void dma_chan_reg_write16(struct dma_chan_data *channel, + uint32_t reg, uint16_t value) +{ + io_reg_write16(dma_chan_base(channel->dma, channel->index) + reg, + value); +} + +static inline void dma_chan_reg_update_bits(struct dma_chan_data *channel, + uint32_t reg, uint32_t mask, + uint32_t value) +{ + io_reg_update_bits(dma_chan_base(channel->dma, channel->index) + reg, + mask, value); +} + +static inline void dma_chan_reg_update_bits16(struct dma_chan_data *channel, + uint32_t reg, uint16_t mask, + uint16_t value) +{ + io_reg_update_bits16(dma_chan_base(channel->dma, channel->index) + reg, + mask, value); +} + +static inline bool dma_is_scheduling_source(struct dma_chan_data *channel) +{ + return channel->is_scheduling_source; +} + +static inline void dma_sg_init(struct dma_sg_elem_array *ea) +{ + ea->count = 0; + ea->elems = NULL; +} + +int dma_sg_alloc(struct dma_sg_elem_array *ea, + enum mem_zone zone, + uint32_t direction, + uint32_t buffer_count, uint32_t buffer_bytes, + uintptr_t dma_buffer_addr, uintptr_t external_addr); + +void dma_sg_free(struct dma_sg_elem_array *ea); + +/** + * \brief Get the total size of SG buffer + * + * \param ea Array of SG elements. + * \return Size of the buffer. + */ +static inline uint32_t dma_sg_get_size(struct dma_sg_elem_array *ea) +{ + int i; + uint32_t size = 0; + + for (i = 0 ; i < ea->count; i++) + size += ea->elems[i].size; + + return size; +} + +struct audio_stream; +typedef void (*dma_process)(const struct audio_stream *, + struct audio_stream *, uint32_t); + +/* copies data from DMA buffer using provided processing function */ +int dma_buffer_copy_from(struct comp_buffer __sparse_cache *source, + struct comp_buffer __sparse_cache *sink, + dma_process_func process, uint32_t source_bytes); + +/* copies data to DMA buffer using provided processing function */ +int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, + struct comp_buffer __sparse_cache *sink, + dma_process_func process, uint32_t sink_bytes); + +/* + * Used when copying DMA buffer bytes into multiple sink buffers, one at a time using the provided + * conversion function. DMA buffer consume should be performed after the data has been copied + * to all sinks. + */ +int dma_buffer_copy_from_no_consume(struct comp_buffer __sparse_cache *source, + struct comp_buffer __sparse_cache *sink, + dma_process_func process, uint32_t source_bytes); + +/* generic DMA DSP <-> Host copier */ + +struct dma_copy { + struct dma_chan_data *chan; + struct dma *dmac; +}; + +/* init dma copy context */ +int dma_copy_new(struct dma_copy *dc); + +/* free dma copy context resources */ +static inline void dma_copy_free(struct dma_copy *dc) +{ + dma_channel_put_legacy(dc->chan); +} + +/* DMA copy data from host to DSP */ +int dma_copy_from_host(struct dma_copy *dc, struct dma_sg_config *host_sg, + int32_t host_offset, void *local_ptr, int32_t size); +int dma_copy_from_host_nowait(struct dma_copy *dc, + struct dma_sg_config *host_sg, + int32_t host_offset, void *local_ptr, + int32_t size); + +/* DMA copy data from DSP to host */ +int dma_copy_to_host(struct dma_copy *dc, struct dma_sg_config *host_sg, + int32_t host_offset, void *local_ptr, int32_t size); +int dma_copy_to_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg, + int32_t host_offset, void *local_ptr, int32_t size); + + +int dma_copy_set_stream_tag(struct dma_copy *dc, uint32_t stream_tag); + +static inline const struct dma_info *dma_info_get(void) +{ + return sof_get()->dma_info; +} + +/** @}*/ + +#endif /* __SOF_LIB_DMA_H__ */ diff --git a/posix/include/sof/lib/io.h b/posix/include/sof/lib/io.h new file mode 100644 index 000000000000..07f1e5aa1fbe --- /dev/null +++ b/posix/include/sof/lib/io.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __XTOS_POSIX_LIB_IO_H__ +#define __XTOS_POSIX_LIB_IO_H__ + + +#include + +#if CONFIG_LIBRARY + +static inline uint32_t io_reg_read(uint32_t reg) { return 0; } +static inline void io_reg_write(uint32_t reg, uint32_t val) {} +static inline void io_reg_update_bits(uint32_t reg, uint32_t mask, + uint32_t value) {} +static inline uint16_t io_reg_read16(uint32_t reg) { return 0; } +static inline void io_reg_write16(uint32_t reg, uint16_t val) {} +static inline void io_reg_update_bits16(uint32_t reg, uint16_t mask, + uint16_t value) {} + +#else + +static inline uint32_t io_reg_read(uint32_t reg) +{ + return *((volatile uint32_t *)reg); +} + +static inline void io_reg_write(uint32_t reg, uint32_t val) +{ + *((volatile uint32_t *)reg) = val; +} + +static inline void io_reg_update_bits(uint32_t reg, uint32_t mask, + uint32_t value) +{ + io_reg_write(reg, (io_reg_read(reg) & (~mask)) | (value & mask)); +} + +static inline uint16_t io_reg_read16(uint32_t reg) +{ + return *((volatile uint16_t *)reg); +} + +static inline void io_reg_write16(uint32_t reg, uint16_t val) +{ + *((volatile uint16_t *)reg) = val; +} + +static inline uint64_t io_reg_read64(uint32_t reg) +{ + return (uint64_t)io_reg_read(reg) + + (((uint64_t)io_reg_read(reg + 4)) << 32); +} + +static inline void io_reg_write64(uint32_t reg, uint64_t val) +{ + *((volatile uint64_t *)reg) = val; +} + +static inline void io_reg_update_bits16(uint32_t reg, uint16_t mask, + uint16_t value) +{ + io_reg_write16(reg, (io_reg_read16(reg) & (~mask)) | (value & mask)); +} + +static inline uint8_t io_reg_read8(uint32_t reg) +{ + return *((volatile uint8_t *)reg); +} + +static inline void io_reg_write8(uint32_t reg, uint8_t val) +{ + *((volatile uint8_t *)reg) = val; +} + +static inline void io_reg_update_bits8(uint32_t reg, uint8_t mask, + uint8_t value) +{ + io_reg_write8(reg, (io_reg_read8(reg) & (~mask)) | (value & mask)); +} + +#endif + +#endif /* __XTOS_POSIX_LIB_IO_H__ */ diff --git a/posix/include/sof/lib/mailbox.h b/posix/include/sof/lib/mailbox.h new file mode 100644 index 000000000000..3d43a22e10ec --- /dev/null +++ b/posix/include/sof/lib/mailbox.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + * Xiuli Pan + */ + +#ifndef __SOF_LIB_MAILBOX_H__ +#define __SOF_LIB_MAILBOX_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define mailbox_get_exception_base() \ + MAILBOX_EXCEPTION_BASE + +#define mailbox_get_exception_size() \ + MAILBOX_EXCEPTION_SIZE + +#define mailbox_get_dspbox_base() \ + MAILBOX_DSPBOX_BASE + +#define mailbox_get_dspbox_size() \ + MAILBOX_DSPBOX_SIZE + +#define mailbox_get_hostbox_base() \ + MAILBOX_HOSTBOX_BASE + +#define mailbox_get_hostbox_size() \ + MAILBOX_HOSTBOX_SIZE + +#define mailbox_get_debug_base() \ + MAILBOX_DEBUG_BASE + +#define mailbox_get_debug_size() \ + MAILBOX_DEBUG_SIZE + +static inline +void mailbox_dspbox_write(size_t offset, const void *src, size_t bytes) +{ + int dsp_write_err __unused = memcpy_s((void *)(MAILBOX_DSPBOX_BASE + offset), + MAILBOX_DSPBOX_SIZE - offset, src, bytes); + + assert(!dsp_write_err); + dcache_writeback_region((__sparse_force void __sparse_cache *)(MAILBOX_DSPBOX_BASE + + offset), bytes); +} + +static inline +void mailbox_dspbox_read(void *dest, size_t dest_size, + size_t offset, size_t bytes) +{ + int dsp_read_err __unused; + + dcache_invalidate_region((__sparse_force void __sparse_cache *)(MAILBOX_DSPBOX_BASE + + offset), bytes); + dsp_read_err = memcpy_s(dest, dest_size, + (void *)(MAILBOX_DSPBOX_BASE + offset), bytes); + assert(!dsp_read_err); +} + +#if CONFIG_LIBRARY + +#define mailbox_hostbox_write(_offset, _src, _bytes) \ + memcpy((char *)ipc->comp_data + _offset, _src, _bytes) + +static inline uint64_t mailbox_sw_reg_read64(uint32_t offset) +{ + return 0; +} +#else + +static inline +void mailbox_hostbox_write(size_t offset, const void *src, size_t bytes) +{ + int host_write_err __unused = memcpy_s((void *)(MAILBOX_HOSTBOX_BASE + offset), + MAILBOX_HOSTBOX_SIZE - offset, src, bytes); + + assert(!host_write_err); + dcache_writeback_region((__sparse_force void __sparse_cache *)(MAILBOX_HOSTBOX_BASE + + offset), bytes); +} + +#endif + +static inline +void mailbox_hostbox_read(void *dest, size_t dest_size, + size_t offset, size_t bytes) +{ + int host_read_err __unused; + + dcache_invalidate_region((__sparse_force void __sparse_cache *)(MAILBOX_HOSTBOX_BASE + + offset), bytes); + host_read_err = memcpy_s(dest, dest_size, + (void *)(MAILBOX_HOSTBOX_BASE + offset), bytes); + assert(!host_read_err); +} + +static inline +void mailbox_stream_write(size_t offset, const void *src, size_t bytes) +{ + int stream_write_err __unused = memcpy_s((void *)(MAILBOX_STREAM_BASE + offset), + MAILBOX_STREAM_SIZE - offset, src, bytes); + + assert(!stream_write_err); + dcache_writeback_region((__sparse_force void __sparse_cache *)(MAILBOX_STREAM_BASE + + offset), bytes); +} + +#endif /* __SOF_LIB_MAILBOX_H__ */ diff --git a/posix/include/sof/lib/memory.h b/posix/include/sof/lib/memory.h new file mode 100644 index 000000000000..8fcbc1f9adbe --- /dev/null +++ b/posix/include/sof/lib/memory.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Tomasz Lauda + */ + +#ifndef __SOF_LIB_MEMORY_H__ +#define __SOF_LIB_MEMORY_H__ + +#include + +#endif /* __SOF_LIB_MEMORY_H__ */ diff --git a/posix/include/sof/lib/mm_heap.h b/posix/include/sof/lib/mm_heap.h new file mode 100644 index 000000000000..7bdab176eb5f --- /dev/null +++ b/posix/include/sof/lib/mm_heap.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +#ifndef __SOF_LIB_MM_HEAP_H__ +#define __SOF_LIB_MM_HEAP_H__ + +#include +#include +#include +#include +#include +#include + +#include +#include + +struct dma_copy; +struct dma_sg_config; + +struct mm_info { + uint32_t used; + uint32_t free; +}; + +struct block_hdr { + uint16_t size; /* size in blocks for continuous allocation */ + uint16_t used; /* usage flags for page */ + void *unaligned_ptr; /* align ptr */ +} __packed; + +struct block_map { + uint16_t block_size; /* size of block in bytes */ + uint16_t count; /* number of blocks in map */ + uint16_t free_count; /* number of free blocks */ + uint16_t first_free; /* index of first free block */ + struct block_hdr *block; /* base block header */ + uint32_t base; /* base address of space */ +}; + +#define BLOCK_DEF(sz, cnt, hdr) \ + {.block_size = sz, .count = cnt, .free_count = cnt, .block = hdr, \ + .first_free = 0} + +struct mm_heap { + uint32_t blocks; + struct block_map *map; +#if CONFIG_LIBRARY + unsigned long heap; +#else + uint32_t heap; +#endif + uint32_t size; + uint32_t caps; + struct mm_info info; +}; + +/* heap block memory map */ +struct mm { + /* system heap - used during init cannot be freed */ + struct mm_heap system[PLATFORM_HEAP_SYSTEM]; + /* system runtime heap - used for runtime system components */ + struct mm_heap system_runtime[PLATFORM_HEAP_SYSTEM_RUNTIME]; +#if CONFIG_CORE_COUNT > 1 + /* object shared between different cores - used during init cannot be freed */ + struct mm_heap system_shared[PLATFORM_HEAP_SYSTEM_SHARED]; + /* object shared between different cores */ + struct mm_heap runtime_shared[PLATFORM_HEAP_RUNTIME_SHARED]; +#endif + /* general heap for components */ + struct mm_heap runtime[PLATFORM_HEAP_RUNTIME]; + /* general component buffer heap */ + struct mm_heap buffer[PLATFORM_HEAP_BUFFER]; + + struct mm_info total; + uint32_t heap_trace_updated; /* updates that can be presented */ + struct k_spinlock lock; /* all allocs and frees are atomic */ +}; + +/* Heap save/restore contents and context for PM D0/D3 events */ +uint32_t mm_pm_context_size(void); + +/* heap initialisation */ +void init_heap(struct sof *sof); + +/* frees entire heap (supported for secondary core system heap atm) */ +void free_heap(enum mem_zone zone); + +/* status */ +void heap_trace_all(int force); +void heap_trace(struct mm_heap *heap, int size); + +#if CONFIG_DEBUG_MEMORY_USAGE_SCAN +/** Fetch runtime information about heap, like used and free memory space + * @param zone to check, see enum mem_zone. + * @param index heap index, eg. cpu core index for any *SYS* zone + * @param out output variable + * @return error code or zero + */ +int heap_info(enum mem_zone zone, int index, struct mm_info *out); +#endif + +/* retrieve memory map pointer */ +static inline struct mm *memmap_get(void) +{ + return sof_get()->memory_map; +} + +#endif /* __SOF_LIB_MM_HEAP_H__ */ diff --git a/posix/include/sof/lib/perf_cnt.h b/posix/include/sof/lib/perf_cnt.h new file mode 100644 index 000000000000..bddda9c8e06b --- /dev/null +++ b/posix/include/sof/lib/perf_cnt.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Marcin Maka + */ + +/** + * \file xtos/include/sof/lib/perf_cnt.h + * \brief Simple performance counters + * \author Marcin Maka + */ + +#ifndef __SOF_LIB_PERF_CNT_H__ +#define __SOF_LIB_PERF_CNT_H__ + +#include + +struct perf_cnt_data { + uint32_t plat_ts; + uint32_t cpu_ts; + uint32_t plat_delta_last; + uint32_t plat_delta_peak; + uint32_t cpu_delta_last; + uint32_t cpu_delta_peak; + uint32_t cpu_delta_sum; + uint32_t sample_cnt; +}; + +#if CONFIG_PERFORMANCE_COUNTERS + +#define perf_cnt_trace(ctx, pcd) \ + tr_info(ctx, "perf plat last %u peak %u cpu last %u, peak %u", \ + (uint32_t)((pcd)->plat_delta_last), \ + (uint32_t)((pcd)->plat_delta_peak), \ + (uint32_t)((pcd)->cpu_delta_last), \ + (uint32_t)((pcd)->cpu_delta_peak)) + +/** \brief Clears performance counters data. */ +#define perf_cnt_clear(pcd) memset((pcd), 0, sizeof(struct perf_cnt_data)) + +/* NOTE: Zephyr's arch_timing_counter_get() might not be implemented + * for a particular platform. In this case let's fallback to use + * Zephyr's k_cycle_get_64(). This will result in both "platform" and + * "cpu" timestamps to be equal. + */ +#ifdef __ZEPHYR__ + #ifdef CONFIG_TIMING_FUNCTIONS + #define perf_cnt_get_cpu_ts arch_timing_counter_get + #else + #define perf_cnt_get_cpu_ts sof_cycle_get_64 + #endif /* CONFIG_TIMING_FUNCTIONS */ +#else + #define perf_cnt_get_cpu_ts() timer_get_system(cpu_timer_get()) +#endif /* __ZEPHYR__ */ + +/** \brief Initializes timestamps with current timer values. */ +#define perf_cnt_init(pcd) do { \ + (pcd)->plat_ts = sof_cycle_get_64(); \ + (pcd)->cpu_ts = perf_cnt_get_cpu_ts(); \ + } while (0) + +/* Trace macros that can be used as trace_m argument of the perf_cnt_stamp() + * to trace PCD values if the last arch timer reading exceeds the previous + * peak value. + * + * arg passed to perf_cnt_stamp() is forwarded to the trace_m() macro + * as the second argument. + */ + +/** \brief No trace when detecting peak value. */ +#define perf_trace_null(pcd, arg) + +/** \brief Simple trace, all values are printed, arg should be a tr_ctx address. + */ +#define perf_trace_simple(pcd, arg) perf_cnt_trace(arg, pcd) + +/* perf measurement windows size 2^x */ +#define PERF_CNT_CHECK_WINDOW_SIZE 10 +#define task_perf_avg_info(pcd, task_p, class) \ + tr_info(task_p, "perf_cycle task %p, %pU cpu avg %u peak %u",\ + class, (class)->uid, \ + (uint32_t)((pcd)->cpu_delta_sum), \ + (uint32_t)((pcd)->cpu_delta_peak)) +#define task_perf_cnt_avg(pcd, trace_m, arg, class) do { \ + (pcd)->cpu_delta_sum += (pcd)->cpu_delta_last; \ + if (++(pcd)->sample_cnt == 1 << PERF_CNT_CHECK_WINDOW_SIZE) { \ + (pcd)->cpu_delta_sum >>= PERF_CNT_CHECK_WINDOW_SIZE; \ + trace_m(pcd, arg, class); \ + (pcd)->cpu_delta_sum = 0; \ + (pcd)->sample_cnt = 0; \ + (pcd)->plat_delta_peak = 0; \ + (pcd)->cpu_delta_peak = 0; \ + } \ + } while (0) + +/** \brief Accumulates cpu timer delta samples calculated by perf_cnt_stamp(). + * + * If current sample count reaches the window size, compute the average and run trace_m. + * \param pcd Performance counters data. + * \param trace_m Trace function trace_m(pcd, arg) or trace macro if a + * more precise line number is desired in the logs. + * \param arg Argument passed to trace_m as arg. + */ +#define perf_cnt_average(pcd, trace_m, arg) do { \ + (pcd)->cpu_delta_sum += (pcd)->cpu_delta_last; \ + if (++(pcd)->sample_cnt == 1 << PERF_CNT_CHECK_WINDOW_SIZE) {\ + (pcd)->cpu_delta_sum >>= PERF_CNT_CHECK_WINDOW_SIZE; \ + trace_m(pcd, arg); \ + (pcd)->cpu_delta_sum = 0; \ + (pcd)->sample_cnt = 0; \ + (pcd)->plat_delta_peak = 0; \ + (pcd)->cpu_delta_peak = 0; \ + } \ + } while (0) + +/** \brief Reads the timers and computes delta to the previous readings. + * + * If current arch delta exceeds the previous peak value, trace_m is run. + * \param pcd Performance counters data. + * \param trace_m Trace function trace_m(pcd, arg) or trace macro if a + * more precise line number is desired in the logs. + * \param arg Argument passed to trace_m as arg. + */ +#define perf_cnt_stamp(pcd, trace_m, arg) do { \ + uint32_t plat_ts = \ + (uint32_t)sof_cycle_get_64(); \ + uint32_t cpu_ts = \ + (uint32_t)perf_cnt_get_cpu_ts(); \ + if (plat_ts > (pcd)->plat_ts) \ + (pcd)->plat_delta_last = plat_ts - (pcd)->plat_ts; \ + else \ + (pcd)->plat_delta_last = UINT32_MAX - (pcd)->plat_ts \ + + plat_ts; \ + if (cpu_ts > (pcd)->cpu_ts) \ + (pcd)->cpu_delta_last = cpu_ts - (pcd)->cpu_ts; \ + else \ + (pcd)->cpu_delta_last = UINT32_MAX - (pcd)->cpu_ts \ + + cpu_ts;\ + if ((pcd)->plat_delta_last > (pcd)->plat_delta_peak) \ + (pcd)->plat_delta_peak = (pcd)->plat_delta_last; \ + if ((pcd)->cpu_delta_last > (pcd)->cpu_delta_peak) { \ + (pcd)->cpu_delta_peak = (pcd)->cpu_delta_last; \ + trace_m(pcd, arg); \ + } \ + } while (0) + +/** + * For simple performance measurement and optimization in development stage, + * tic-toc api is provided. Performance data are traced at each tok call, + * to allow fast clocks usage deviation estimation. Example: + * + * \code{.c} + * void foo(struct comp_dev *dev) { + * static struct perf_cnt_data pcd; + * + * perf_tic(&pcd); + * bar(); + * perf_toc(&pcd, dev); + * } + * \endcode + */ + +/** \brief Save start timestamp in pcd structure + * + * \param pcd Performance counters data. + */ +#define perf_tic(pcd) \ + perf_cnt_init(pcd) + +/** \brief Save start timestamp in pcd structure + * + * \param pcd Performance counters data. + * \param comp Component used to get corresponding trace context. + */ +#define perf_toc(pcd, comp) do { \ + perf_cnt_stamp(pcd, perf_trace_null, NULL); \ + perf_trace_simple(pcd, trace_comp_get_tr_ctx(comp)); \ + } while (0) + +#else +#define perf_cnt_clear(pcd) +#define perf_cnt_init(pcd) +#define perf_cnt_stamp(pcd, trace_m, arg) +#define perf_cnt_average(pcd, trace_m, arg) +#endif + +#endif /* __SOF_LIB_PERF_CNT_H__ */ diff --git a/posix/include/sof/lib/pm_runtime.h b/posix/include/sof/lib/pm_runtime.h new file mode 100644 index 000000000000..c0a24116e629 --- /dev/null +++ b/posix/include/sof/lib/pm_runtime.h @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Tomasz Lauda + * Janusz Jankowski + */ + +/** + * \file xtos/include/sof/lib/pm_runtime.h + * \brief Runtime power management header file + * \author Tomasz Lauda + */ + +#ifndef __SOF_LIB_PM_RUNTIME_H__ +#define __SOF_LIB_PM_RUNTIME_H__ + +#include +#include +#include +#include +#include +#include + +/** \addtogroup pm_runtime PM Runtime + * PM runtime specification. + * @{ + */ + +/* PM runtime flags */ + +#define RPM_ASYNC 0x01 /**< Request is asynchronous */ + +/** \brief Runtime power management context */ +enum pm_runtime_context { + PM_RUNTIME_HOST_DMA_L1 = 0, /**< Host DMA L1 */ + SSP_CLK, /**< SSP Clock */ + SSP_POW, /**< SSP Power */ + DMIC_CLK, /**< DMIC Clock */ + DMIC_POW, /**< DMIC Power */ + DW_DMAC_CLK, /**< DW DMAC Clock */ + CORE_MEMORY_POW, /**< Core Memory power */ + CORE_HP_CLK, /**< High Performance Clock*/ + PM_RUNTIME_DSP /**< DSP */ +}; + +/** \brief Runtime power management data. */ +struct pm_runtime_data { + struct k_spinlock lock; /**< lock mechanism */ + void *platform_data; /**< platform specific data */ +#if CONFIG_DSP_RESIDENCY_COUNTERS + struct r_counters_data *r_counters; /**< diagnostic DSP residency counters */ +#endif +}; + +#if CONFIG_DSP_RESIDENCY_COUNTERS +/** + * \brief DSP residency counters + * R0, R1, R2 are DSP residency counters which can be used differently + * based on platform implementation. + * In general R0 is the highest power consumption state while R2 is + * the lowest power consumption state. See platform specific pm_runtime.h + * for the platform HW specific mapping. + */ +enum dsp_r_state { + r0_r_state = 0, + r1_r_state, + r2_r_state +}; + +/** \brief Diagnostic DSP residency counters data */ +struct r_counters_data { + enum dsp_r_state cur_r_state; /**< current dsp_r_state */ + uint64_t ts; /**< dsp_r_state timestamp */ +}; +#endif + +/** + * \brief Initializes runtime power management. + */ +void pm_runtime_init(struct sof *sof); + +/** + * \brief Retrieves power management resource (async). + * + * \param[in] context Type of power management context. + * \param[in] index Index of the device. + */ +void pm_runtime_get(enum pm_runtime_context context, uint32_t index); + +/** + * \brief Retrieves power management resource. + * + * \param[in] context Type of power management context. + * \param[in] index Index of the device. + */ +void pm_runtime_get_sync(enum pm_runtime_context context, uint32_t index); + +/** + * \brief Releases power management resource (async). + * + * \param[in] context Type of power management context. + * \param[in] index Index of the device. + */ +void pm_runtime_put(enum pm_runtime_context context, uint32_t index); + +/** + * \brief Releases power management resource. + * + * \param[in] context Type of power management context. + * \param[in] index Index of the device. + */ +void pm_runtime_put_sync(enum pm_runtime_context context, uint32_t index); + +/** + * \brief Enables power management operations for the resource. + * + * \param[in] context Type of power management context. + * \param[in] index Index of the device. + */ +void pm_runtime_enable(enum pm_runtime_context context, uint32_t index); + +/** + * \brief Disables power management operations for the resource. + * + * \param[in] context Type of power management context. + * \param[in] index Index of the device. + */ +void pm_runtime_disable(enum pm_runtime_context context, uint32_t index); + +/** + * \brief Reports state of the power managed resource. + * + * @param context Type of power management context. + * @param index Index of the resource. + * + * @return true if the resource is active or pm disabled, false otherwise. + */ +bool pm_runtime_is_active(enum pm_runtime_context context, uint32_t index); + +/** + * \brief Retrieves pointer to runtime power management data. + * + * @return Runtime power management data pointer. + */ +static inline struct pm_runtime_data *pm_runtime_data_get(void) +{ + return sof_get()->prd; +} + +#if CONFIG_DSP_RESIDENCY_COUNTERS +/** + * \brief Initializes DSP residency counters. + * + * \param[in] context Type of power management context. + */ +void init_dsp_r_state(enum dsp_r_state); + +/** + * \brief Reports DSP residency state. + * + * \param[in] new state + */ +void report_dsp_r_state(enum dsp_r_state); + +/** + * \brief Retrieves current DSP residency state. + * + * @return active DSP residency state + */ +enum dsp_r_state get_dsp_r_state(void); +#endif + +/** @}*/ + +#endif /* __SOF_LIB_PM_RUNTIME_H__ */ diff --git a/posix/include/sof/lib/shim.h b/posix/include/sof/lib/shim.h new file mode 100644 index 000000000000..518880f1f953 --- /dev/null +++ b/posix/include/sof/lib/shim.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Tomasz Lauda + */ + +#ifndef __SOF_LIB_SHIM_H__ +#define __SOF_LIB_SHIM_H__ + +#include + +#endif /* __SOF_LIB_SHIM_H__ */ diff --git a/posix/include/sof/list.h b/posix/include/sof/list.h new file mode 100644 index 000000000000..a81576fb5e68 --- /dev/null +++ b/posix/include/sof/list.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +#ifndef __SOF_LIST_H__ +#define __SOF_LIST_H__ + +/* Really simple list manipulation */ + +struct list_item; + +struct list_item { + struct list_item *next; + struct list_item *prev; +}; + +/* a static list head initialiser */ +#define LIST_INIT(head) {&head, &head} + +/* initialise list before any use - list will point to itself */ +static inline void list_init(struct list_item *list) +{ + list->next = list; + list->prev = list; +} + +/* add new item to the start or head of the list */ +static inline void list_item_prepend(struct list_item *item, + struct list_item *list) +{ + struct list_item *next = list->next; + + next->prev = item; + item->next = next; + item->prev = list; + list->next = item; +} + +/* add new item to the end or tail of the list */ +static inline void list_item_append(struct list_item *item, + struct list_item *list) +{ + struct list_item *tail = list->prev; + + tail->next = item; + item->next = list; + item->prev = tail; + list->prev = item; +} + +/* delete item from the list leaves deleted list item + *in undefined state list_is_empty will return true + */ +static inline void list_item_del(struct list_item *item) +{ + item->next->prev = item->prev; + item->prev->next = item->next; + list_init(item); +} + +/* is list item the last item in list ? */ +static inline int list_item_is_last(struct list_item *item, + struct list_item *list) +{ + return item->next == list; +} + +/* is list empty ? */ +#define list_is_empty(item) \ + ((item)->next == item) + +#define __list_object(item, type, offset) \ + ((type *)((char *)(item) - (offset))) + +/* get the container object of the list item */ +#define list_item(item, type, member) \ + __list_object(item, type, offsetof(type, member)) + +/* get the container object of the first item in the list */ +#define list_first_item(list, type, member) \ + __list_object((list)->next, type, offsetof(type, member)) + +/* get the next container object in the list */ +#define list_next_item(object, member) \ + list_item((object)->member.next, typeof(*(object)), member) + +/* list iterator */ +#define list_for_item(item, list) \ + for (item = (list)->next; item != (list); item = item->next) + +/* list iterator */ +#define list_for_item_prev(item, list) \ + for (item = (list)->prev; item != (list); item = item->prev) + +/* list iterator - safe to delete items */ +#define list_for_item_safe(item, tmp, list) \ + for (item = (list)->next, tmp = item->next;\ + item != (list); \ + item = tmp, tmp = item->next) + +/** + * Re-links the list when head address changed (list moved). + * @param new_list New address of the head. + * @param old_list Old address of the head. + */ +static inline void list_relink(struct list_item *new_list, + struct list_item *old_list) +{ + struct list_item *li; + + if (new_list->next == old_list) { + list_init(new_list); + } else { + list_for_item(li, new_list) + if (li->next == old_list) + li->next = new_list; /* for stops here */ + list_for_item_prev(li, new_list) + if (li->prev == old_list) + li->prev = new_list; /* for stops here */ + } +} + +#endif /* __SOF_LIST_H__ */ diff --git a/rimage b/rimage deleted file mode 160000 index 4fb9fe00575b..000000000000 --- a/rimage +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4fb9fe00575bc2e9f14570803d811987fb27f010 diff --git a/scripts/cmake/git-submodules.cmake b/scripts/cmake/git-submodules.cmake index 5b486e4af87c..56c559491b90 100644 --- a/scripts/cmake/git-submodules.cmake +++ b/scripts/cmake/git-submodules.cmake @@ -1,11 +1,17 @@ # SPDX-License-Identifier: BSD-3-Clause -find_package(Git) -set(RIMAGE_CMAKE "${SOF_ROOT_SOURCE_DIRECTORY}/rimage/CMakeLists.txt") +set(RIMAGE_SUBMODULE "${SOF_ROOT_SOURCE_DIRECTORY}/rimage") +if(EXISTS "${RIMAGE_SUBMODULE}/CMakeLists.txt") + message(WARNING + "${RIMAGE_SUBMODULE} is deprecated and ignored" + ) +endif() +find_package(Git) +set(TOMLC99_MAKE "${SOF_ROOT_SOURCE_DIRECTORY}/tools/rimage/tomlc99/Makefile") if(GIT_FOUND AND EXISTS "${SOF_ROOT_SOURCE_DIRECTORY}/.git") - if(EXISTS "${RIMAGE_CMAKE}") + if(EXISTS "${TOMLC99_MAKE}") # As incredible as it sounds, some people run neither # "git status" nor "git diff" every few minutes and not @@ -36,10 +42,10 @@ if(GIT_FOUND AND EXISTS "${SOF_ROOT_SOURCE_DIRECTORY}/.git") NOT CONFIG_LIBRARY) message(FATAL_ERROR -"${RIMAGE_CMAKE} not found. You should have used 'git clone --recursive'. \ +"${TOMLC99_MAKE} not found. You should have used 'git clone --recursive'. \ To fix this existing git clone run: -git submodule update --init --merge --recursive +git submodule update --init --merge tools/rimage/tomlc99 ") - endif() # rimage/CMakeLists.txt + endif() # tomlc99/Makefile endif() # .git/ diff --git a/scripts/xtensa-build-zephyr.py b/scripts/xtensa-build-zephyr.py index 8a2b3532708a..0d8e28921c3d 100755 --- a/scripts/xtensa-build-zephyr.py +++ b/scripts/xtensa-build-zephyr.py @@ -176,9 +176,6 @@ def parse_args(): help="List of platforms to build") parser.add_argument("-d", "--debug", required=False, action="store_true", help="Shortcut for: -o sof/app/debug_overlay.conf") - parser.add_argument("-i", "--ipc", required=False, choices=["IPC4"], - help="""Applies --overlay /ipc4_overlay.conf -and a different rimage config. Valid only for IPC3 platforms supporting IPC4 too.""") # NO SOF release will ever user the option --fw-naming. # This option is only for disguising SOF IPC4 as CAVS IPC4 and only in cases where # the kernel 'ipc_type' expects CAVS IPC4. In this way, developers and CI can test @@ -265,10 +262,6 @@ def parse_args(): if not args.use_platform_subdir: args.use_platform_subdir=True warnings.warn("The option '--fw-naming AVS' has to be used with '--use-platform-subdir'. Enable '--use-platform-subdir' automatically.") - if args.ipc != "IPC4": - args.ipc="IPC4" - warnings.warn("The option '--fw-naming AVS' has to be used with '-i IPC4'. Enable '-i IPC4' automatically.") - def execute_command(*run_args, **run_kwargs): """[summary] Provides wrapper for subprocess.run that prints @@ -519,7 +512,7 @@ def clean_staging(platform): # for now we must stick to `sof/rimage/[tomlc99]` for # backwards-compatibility with XTOS platforms and git submodules, see more # detailed comments in west.yml -RIMAGE_SOURCE_DIR = west_top / "sof" / "rimage" +RIMAGE_SOURCE_DIR = west_top / "sof" / "tools" / "rimage" def rimage_west_configuration(platform_dict, dest_dir): @@ -570,14 +563,11 @@ def rimage_west_configuration(platform_dict, dest_dir): def build_rimage(): - # Detect non-west rimage duplicates, example: git submdule - # SOF_TOP/rimage = sof2/rimage - nested_rimage = pathlib.Path(SOF_TOP, "rimage") - if nested_rimage.is_dir() and not nested_rimage.samefile(RIMAGE_SOURCE_DIR): - raise RuntimeError( - f"""Two rimage source directories found. - Move non-west {nested_rimage} out of west workspace {west_top}. - See output of 'west list'.""" + old_rimage_loc = SOF_TOP / "rimage" + # Don't warn on empty directories + if ( old_rimage_loc / "CMakeLists.txt" ).exists(): + warnings.warn(f"""{old_rimage_loc} is now ignored, + new location is {RIMAGE_SOURCE_DIR}""" ) rimage_dir_name = RIMAGE_BUILD_DIR.name # CMake build rimage module @@ -626,7 +616,7 @@ def rimage_options(platform_dict): # test_00_01_load_fw_and_check_version opts.append(("-b", "1")) - if args.ipc == "IPC4": + if platform_dict.get("IPC4_RIMAGE_DESC", None) is not None: rimage_desc = platform_dict["IPC4_RIMAGE_DESC"] else: rimage_desc = platform_dict["name"] + ".toml" @@ -725,13 +715,6 @@ def build_platforms(): if args.debug: overlays.append(str(pathlib.Path(SOF_TOP, "app", "debug_overlay.conf"))) - # The '-i IPC4' is a shortcut for '-o path_to_ipc4_overlay' (and more), we - # are good if both are provided, because it's no harm to merge the same - # overlay twice. - if args.ipc == "IPC4": - overlays.append(str(pathlib.Path(SOF_TOP, "app", "overlays", platform, - platform_dict["IPC4_CONFIG_OVERLAY"]))) - if overlays: overlays = ";".join(overlays) build_cmd.append(f"-DOVERLAY_CONFIG={overlays}") diff --git a/smex/CMakeLists.txt b/smex/CMakeLists.txt index 5d198832f472..23eeb3a775f3 100644 --- a/smex/CMakeLists.txt +++ b/smex/CMakeLists.txt @@ -28,7 +28,7 @@ target_link_options(smex PRIVATE target_include_directories(smex PRIVATE "${SOF_ROOT_SOURCE_DIRECTORY}/src/include" - "${SOF_ROOT_SOURCE_DIRECTORY}/rimage/src/include" + "${SOF_ROOT_SOURCE_DIRECTORY}/tools/rimage/src/include" ) # TODO: smex should not need RTOS headers: FIX. diff --git a/smex/elf.c b/smex/elf.c index bd088716691d..0d0e976dcb8a 100644 --- a/smex/elf.c +++ b/smex/elf.c @@ -17,7 +17,7 @@ static int elf_read_sections(struct elf_module *module, bool verbose) { Elf32_Ehdr *hdr = &module->hdr; - Elf32_Shdr *section = module->section; + Elf32_Shdr *section; size_t count; int i, ret; uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); @@ -27,7 +27,7 @@ static int elf_read_sections(struct elf_module *module, bool verbose) if (ret < 0) { fprintf(stderr, "error: can't seek to %s section header %d\n", module->elf_file, ret); - return ret; + return -errno; } /* allocate space for each section header */ @@ -41,7 +41,7 @@ static int elf_read_sections(struct elf_module *module, bool verbose) if (count != hdr->shnum) { fprintf(stderr, "error: failed to read %s section header %d\n", module->elf_file, -errno); - return -errno; + return count < 0 ? -errno : -ENODATA; } /* read in strings */ @@ -56,7 +56,7 @@ static int elf_read_sections(struct elf_module *module, bool verbose) if (ret < 0) { fprintf(stderr, "error: can't seek to %s stringss %d\n", module->elf_file, ret); - return ret; + return -errno; } count = fread(module->strings, 1, section[hdr->shstrndx].size, @@ -64,7 +64,7 @@ static int elf_read_sections(struct elf_module *module, bool verbose) if (count != section[hdr->shstrndx].size) { fprintf(stderr, "error: failed to read %s strings %d\n", module->elf_file, -errno); - return -errno; + return count < 0 ? -errno : -ENODATA; } module->bss_index = elf_find_section(module, ".bss"); @@ -128,7 +128,7 @@ static int elf_read_sections(struct elf_module *module, bool verbose) static int elf_read_programs(struct elf_module *module, bool verbose) { Elf32_Ehdr *hdr = &module->hdr; - Elf32_Phdr *prg = module->prg; + Elf32_Phdr *prg; size_t count; int i, ret; @@ -137,7 +137,7 @@ static int elf_read_programs(struct elf_module *module, bool verbose) if (ret < 0) { fprintf(stderr, "error: cant seek to %s program header %d\n", module->elf_file, ret); - return ret; + return -errno; } /* allocate space for programs */ @@ -151,7 +151,7 @@ static int elf_read_programs(struct elf_module *module, bool verbose) if (count != hdr->phnum) { fprintf(stderr, "error: failed to read %s program header %d\n", module->elf_file, -errno); - return -errno; + return count < 0 ? -errno : -ENODATA; } /* check each program */ @@ -191,7 +191,7 @@ static int elf_read_hdr(struct elf_module *module, bool verbose) if (count != 1) { fprintf(stderr, "error: failed to read %s elf header %d\n", module->elf_file, -errno); - return -errno; + return count < 0 ? -errno : -ENODATA; } if (!verbose) @@ -398,6 +398,7 @@ int elf_find_section(const struct elf_module *module, const char *name) ret = fseek(module->fd, section->off, SEEK_SET); if (ret < 0) { fprintf(stderr, "error: cant seek to string section %d\n", ret); + ret = -errno; goto out; } @@ -405,13 +406,20 @@ int elf_find_section(const struct elf_module *module, const char *name) if (count != section->size) { fprintf(stderr, "error: can't read string section %d\n", -errno); - ret = -errno; + ret = count < 0 ? -errno : -ENODATA; goto out; } + buffer[section->size - 1] = '\0'; /* find section with name */ for (i = 0; i < hdr->shnum; i++) { s = &module->section[i]; + if (s->name >= section->size) { + fprintf(stderr, "error: invalid section name string index %d\n", s->name); + ret = -EINVAL; + goto out; + } + if (!strcmp(name, buffer + s->name)) { ret = i; goto out; @@ -431,8 +439,8 @@ int elf_read_section(const struct elf_module *module, const char *section_name, const Elf32_Shdr **dst_section, void **dst_buff) { const Elf32_Shdr *section; - int section_index = -1; - int read; + int section_index; + int ret; section_index = elf_find_section(module, section_name); if (section_index < 0) { @@ -451,17 +459,25 @@ int elf_read_section(const struct elf_module *module, const char *section_name, return -ENOMEM; /* fill buffer with section content */ - fseek(module->fd, section->off, SEEK_SET); - read = fread(*dst_buff, 1, section->size, module->fd); - if (read != section->size) { - fprintf(stderr, - "error: can't read %s section %d\n", section_name, - -errno); - free(*dst_buff); - return -errno; + ret = fseek(module->fd, section->off, SEEK_SET); + if (ret) { + fprintf(stderr, "error: can't seek to %s section %d\n", section_name, -errno); + ret = -errno; + goto error; + } + + ret = fread(*dst_buff, 1, section->size, module->fd); + if (ret != section->size) { + fprintf(stderr, "error: can't read %s section %d\n", section_name, -errno); + ret = ret < 0 ? -errno : -ENODATA; + goto error; } return section->size; + +error: + free(*dst_buff); + return ret; } int elf_read_module(struct elf_module *module, const char *name, bool verbose) @@ -479,12 +495,16 @@ int elf_read_module(struct elf_module *module, const char *name, bool verbose) /* get file size */ ret = fseek(module->fd, 0, SEEK_END); - if (ret < 0) + if (ret < 0) { + ret = -errno; goto hdr_err; + } module->file_size = ftell(module->fd); ret = fseek(module->fd, 0, SEEK_SET); - if (ret < 0) + if (ret < 0) { + ret = -errno; goto hdr_err; + } /* read in elf header */ ret = elf_read_hdr(module, verbose); diff --git a/src/arch/host/CMakeLists.txt b/src/arch/host/CMakeLists.txt index 39b0ea640bd4..75314f00f556 100644 --- a/src/arch/host/CMakeLists.txt +++ b/src/arch/host/CMakeLists.txt @@ -5,10 +5,9 @@ target_include_directories(sof_public_headers INTERFACE ${PROJECT_SOURCE_DIR}/sr target_include_directories(sof_public_headers INTERFACE ${PROJECT_SOURCE_DIR}/src/platform/library/include) include(CheckCCompilerFlag) -# TODO: library should not need RTOS headers: FIX. if (NOT CONFIG_SOF_ZEPHYR_STRICT_HEADERS) target_include_directories(sof_public_headers INTERFACE - ${PROJECT_SOURCE_DIR}/xtos/include + ${PROJECT_SOURCE_DIR}/posix/include ) endif() @@ -19,8 +18,9 @@ if (supports_implicit_fallthrough) endif() # C & ASM flags -target_compile_options(sof_options INTERFACE -g -O3 -fPIC -DPIC -Wall -Werror -Wmissing-prototypes - ${implicit_fallthrough} -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -Wpointer-arith +target_compile_options(sof_options INTERFACE -g -O3 -fPIC -DPIC -std=c99 -std=gnu99 -fgnu89-inline + -Wall -Werror -Wmissing-prototypes ${implicit_fallthrough} -Wno-pointer-to-int-cast + -Wno-int-to-pointer-cast -Wpointer-arith -DCONFIG_LIBRARY "-imacros${CONFIG_H_PATH}") if(NOT BUILD_UNIT_TESTS_HOST) diff --git a/src/arch/host/configs/plugin_ipc4_defconfig b/src/arch/host/configs/plugin_ipc4_defconfig new file mode 100644 index 000000000000..43529dc87726 --- /dev/null +++ b/src/arch/host/configs/plugin_ipc4_defconfig @@ -0,0 +1,22 @@ +CONFIG_IPC_MAJOR_4=y +CONFIG_LIBRARY=y +CONFIG_TRACEV=y +CONFIG_DEBUG_MEMORY_USAGE_SCAN=n +CONFIG_COMP_CROSSOVER=y +CONFIG_COMP_DRC=y +CONFIG_COMP_MULTIBAND_DRC=y +CONFIG_COMP_SRC=y +CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y +CONFIG_COMP_MFCC=y +CONFIG_COMP_GAIN=y +CONFIG_COMP_VOLUME_WINDOWS_FADE=y +CONFIG_COMP_MODULES_SO=y +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_COMP_MIXER=y +CONFIG_IPC4_GATEWAY=n +CONFIG_COMP_DAI_GROUP=n +CONFIG_FORMAT_S16LE=y +CONFIG_FORMAT_S32LE=y +CONFIG_FORMAT_S24LE=y +CONFIG_COMP_PEAK_VOL=n +CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD=y diff --git a/src/arch/host/include/arch/debug/panic.h b/src/arch/host/include/arch/debug/panic.h index 67fb04aa70eb..85f47a5ecbbc 100644 --- a/src/arch/host/include/arch/debug/panic.h +++ b/src/arch/host/include/arch/debug/panic.h @@ -5,7 +5,7 @@ * Author: Tomasz Lauda */ -#ifdef __XTOS_RTOS_PANIC_H__ +#ifdef __POSIX_RTOS_PANIC_H__ #ifndef __ARCH_DEBUG_PANIC_H__ #define __ARCH_DEBUG_PANIC_H__ @@ -21,4 +21,4 @@ static inline void arch_dump_regs(void *dump_buf, uintptr_t stack_ptr, #error "This file shouldn't be included from outside of XTOS's rtos/panic.h" -#endif /* __XTOS_RTOS_PANIC_H__ */ +#endif /* __POSIX_RTOS_PANIC_H__ */ diff --git a/src/arch/host/include/arch/drivers/idc.h b/src/arch/host/include/arch/drivers/idc.h index 73719e55f2b8..3f3e67b89d76 100644 --- a/src/arch/host/include/arch/drivers/idc.h +++ b/src/arch/host/include/arch/drivers/idc.h @@ -5,7 +5,7 @@ * Author: Tomasz Lauda */ -#ifdef __XTOS_RTOS_IDC_H__ +#ifdef __POSIX_RTOS_IDC_H__ #ifndef __ARCH_DRIVERS_IDC_H__ #define __ARCH_DRIVERS_IDC_H__ @@ -16,4 +16,4 @@ #error "This file shouldn't be included from outside of XTOS's rtos/idc.h" -#endif /* __XTOS_RTOS_IDC_H__ */ +#endif /* __POSIX_RTOS_IDC_H__ */ diff --git a/src/arch/host/include/arch/schedule/task.h b/src/arch/host/include/arch/schedule/task.h index 5c6cbf102744..2b89d264e0a6 100644 --- a/src/arch/host/include/arch/schedule/task.h +++ b/src/arch/host/include/arch/schedule/task.h @@ -11,7 +11,7 @@ * \authors Liam Girdwood */ -#ifdef __XTOS_RTOS_TASK_H__ +#ifdef __POSIX_RTOS_TASK_H__ #ifndef __ARCH_SCHEDULE_TASK_H__ #define __ARCH_SCHEDULE_TASK_H__ @@ -20,6 +20,6 @@ #else -#error "This file shouldn't be included from outside of XTOS's rtos/task.h" +#error "This file shouldn't be included from outside of XTOS's posix/task.h" -#endif /* __XTOS_RTOS_TASK_H__ */ +#endif /* __POSIX_RTOS_TASK_H__ */ diff --git a/src/arch/host/include/arch/spinlock.h b/src/arch/host/include/arch/spinlock.h index 273133490e72..360cb72bdb1f 100644 --- a/src/arch/host/include/arch/spinlock.h +++ b/src/arch/host/include/arch/spinlock.h @@ -6,7 +6,7 @@ */ /* TODO: this needs fixed as part of the "host does not need rtos headers work" */ -#ifdef __XTOS_RTOS_SPINLOCK_H__ +#ifdef __POSIX_RTOS_SPINLOCK_H__ #ifndef __ARCH_SPINLOCK_H__ #define __ARCH_SPINLOCK_H__ diff --git a/src/arch/host/include/arch/string.h b/src/arch/host/include/arch/string.h index 166b417173f0..125f7bf555a6 100644 --- a/src/arch/host/include/arch/string.h +++ b/src/arch/host/include/arch/string.h @@ -5,7 +5,7 @@ * Author: Liam Girdwood */ -#ifdef __XTOS_RTOS_STRING_H__ +#ifdef __POSIX_RTOS_STRING_H__ #ifndef __ARCH_STRING_H__ #define __ARCH_STRING_H__ diff --git a/src/arch/xtensa/CMakeLists.txt b/src/arch/xtensa/CMakeLists.txt index 474be5988727..ba045fe6ccb1 100644 --- a/src/arch/xtensa/CMakeLists.txt +++ b/src/arch/xtensa/CMakeLists.txt @@ -330,7 +330,7 @@ add_custom_target( ExternalProject_Add(rimage_ep DEPENDS check_version_h - SOURCE_DIR "${PROJECT_SOURCE_DIR}/rimage" + SOURCE_DIR "${RIMAGE_TOP}" PREFIX "${PROJECT_BINARY_DIR}/rimage_ep" BINARY_DIR "${PROJECT_BINARY_DIR}/rimage_ep/build" EXCLUDE_FROM_ALL TRUE @@ -386,7 +386,7 @@ if(MEU_PATH OR DEFINED MEU_NO_SIGN) # Don't sign with rimage run_rimage COMMAND ${PROJECT_BINARY_DIR}/rimage_ep/build/rimage -o sof-${fw_name}.ri - -c "${PROJECT_SOURCE_DIR}/rimage/config/${fw_name}.toml" + -c "${RIMAGE_TOP}/config/${fw_name}.toml" -s ${MEU_OFFSET} -k ${RIMAGE_PRIVATE_KEY} -i ${RIMAGE_IMR_TYPE} @@ -427,7 +427,7 @@ else() # sign with rimage run_rimage COMMAND ${PROJECT_BINARY_DIR}/rimage_ep/build/rimage -o sof-${fw_name}.ri - -c "${PROJECT_SOURCE_DIR}/rimage/config/${fw_name}.toml" + -c "${RIMAGE_TOP}/config/${fw_name}.toml" -k ${RIMAGE_PRIVATE_KEY} -i ${RIMAGE_IMR_TYPE} -f ${SOF_MAJOR}.${SOF_MINOR}.${SOF_MICRO} diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index f35dd917eae0..7e58fd55d929 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -6,7 +6,7 @@ elseif(CONFIG_IPC_MAJOR_4) set(mixer_src mixin_mixout/mixin_mixout.c mixin_mixout/mixin_mixout_generic.c mixin_mixout/mixin_mixout_hifi3.c) endif() -if((NOT CONFIG_LIBRARY) OR CONFIG_LIBRARY_STATIC) +if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) add_local_sources(sof host-legacy.c component.c @@ -17,6 +17,7 @@ if((NOT CONFIG_LIBRARY) OR CONFIG_LIBRARY_STATIC) audio_stream.c channel_map.c ) + if(CONFIG_COMP_BLOB) add_local_sources(sof data_blob.c) endif() @@ -62,7 +63,7 @@ if((NOT CONFIG_LIBRARY) OR CONFIG_LIBRARY_STATIC) dai-legacy.c ) endif() - if(CONFIG_COMP_KPB) + if(CONFIG_COMP_KPB AND NOT CONFIG_LIBRARY_STATIC) add_local_sources(sof kpb.c ) @@ -89,7 +90,7 @@ if((NOT CONFIG_LIBRARY) OR CONFIG_LIBRARY_STATIC) if(CONFIG_COMP_RTNR) add_subdirectory(rtnr) endif() - if(CONFIG_COMP_BASEFW_IPC4) + if(CONFIG_COMP_BASEFW_IPC4 AND NOT CONFIG_LIBRARY) add_local_sources(sof base_fw.c ) @@ -125,6 +126,11 @@ add_local_sources(sof component.c data_blob.c buffer.c + source_api_helper.c + sink_api_helper.c + sink_source_utils.c + audio_stream.c + channel_map.c ) # Audio Modules with various optimizaitons @@ -168,11 +174,12 @@ set(sof_audio_modules mixer volume src asrc eq-fir eq-iir dcblock crossover tdfb # sources for each module if(CONFIG_IPC_MAJOR_3) set(volume_sources volume/volume.c volume/volume_generic.c volume/volume_ipc3.c) + set(src_sources src/src.c src/src_ipc3.c src/src_generic.c) elseif(CONFIG_IPC_MAJOR_4) set(volume_sources volume/volume.c volume/volume_generic.c volume/volume_ipc4.c) + set(src_sources src/src.c src/src_ipc4.c src/src_generic.c) endif() set(mixer_sources ${mixer_src}) -set(src_sources src/src.c src/src_generic.c) set(asrc_sources asrc/asrc.c asrc/asrc_farrow.c asrc/asrc_farrow_generic.c) set(eq-fir_sources eq_fir/eq_fir.c eq_fir/eq_fir_generic.c) set(eq-iir_sources eq_iir/eq_iir.c) diff --git a/src/audio/Kconfig b/src/audio/Kconfig index be2ff5f360b2..8c533713419a 100644 --- a/src/audio/Kconfig +++ b/src/audio/Kconfig @@ -2,6 +2,8 @@ menu "Audio components" +rsource "volume/Kconfig" + config COMP_BASEFW_IPC4 bool "BASEFW component" default y @@ -209,7 +211,8 @@ config COMP_TONE default n select CORDIC_FIXED help - Select for Tone component + Select for Tone component. + Warning: This component is deprecated and will be removed from SOF v2.8. config COMP_MIXER bool "Mixer component" @@ -702,4 +705,12 @@ config WRAP_ACTUAL_POSITION It is not necessary that on wrap, the buffer position would be zero.At wrap, in some cases based on the period size, the frame may not exactly be at the end of the buffer and roll over for some bytes from the beginning of the buffer. + +config COMP_MODULE_SHARED_LIBRARY_BUILD + bool "Build SOF modules as shared libraries" + default n + help + Select if you want to build modules as shared objects that can be used to run + pipelines on the host with the testbench or the ALSA plugin. + endmenu diff --git a/src/audio/aria/aria.c b/src/audio/aria/aria.c index 9d9c16c9c1d9..9ca1626e644d 100644 --- a/src/audio/aria/aria.c +++ b/src/audio/aria/aria.c @@ -72,8 +72,8 @@ static int aria_algo_init(struct aria_data *cd, void *buffer_desc, } static inline void aria_process_data(struct processing_module *mod, - struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + struct audio_stream *source, + struct audio_stream *sink, size_t frames) { struct aria_data *cd = module_get_private_data(mod); @@ -153,24 +153,19 @@ static int aria_free(struct processing_module *mod) static void aria_set_stream_params(struct comp_buffer *buffer, struct processing_module *mod) { - struct comp_buffer __sparse_cache *buffer_c; const struct ipc4_audio_format *audio_fmt = &mod->priv.cfg.base_cfg.audio_fmt; - buffer_c = buffer_acquire(buffer); - - ipc4_update_buffer_format(buffer_c, audio_fmt); + ipc4_update_buffer_format(buffer, audio_fmt); #ifdef ARIA_GENERIC - audio_stream_init_alignment_constants(1, 1, &buffer_c->stream); + audio_stream_init_alignment_constants(1, 1, &buffer->stream); #else - audio_stream_init_alignment_constants(8, 1, &buffer_c->stream); + audio_stream_init_alignment_constants(8, 1, &buffer->stream); #endif - - buffer_release(buffer_c); } static int aria_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { int ret; struct comp_buffer *source, *sink; @@ -254,8 +249,8 @@ static int aria_process(struct processing_module *mod, return 0; } -static struct module_interface aria_interface = { - .init = aria_init, +static const struct module_interface aria_interface = { + .init = aria_init, .prepare = aria_prepare, .process_audio_stream = aria_process, .reset = aria_reset, diff --git a/src/audio/aria/aria_generic.c b/src/audio/aria/aria_generic.c index cc0f90b2de2e..09daee86c5d9 100644 --- a/src/audio/aria/aria_generic.c +++ b/src/audio/aria/aria_generic.c @@ -20,7 +20,7 @@ const uint8_t INDEX_TAB[] = { }; inline void aria_algo_calc_gain(struct aria_data *cd, size_t gain_idx, - struct audio_stream __sparse_cache *source, int frames) + struct audio_stream *source, int frames) { int32_t max_data = 0; int32_t sample_abs; @@ -50,7 +50,7 @@ inline void aria_algo_calc_gain(struct aria_data *cd, size_t gain_idx, } void aria_algo_get_data(struct processing_module *mod, - struct audio_stream __sparse_cache *sink, int frames) + struct audio_stream *sink, int frames) { struct aria_data *cd = module_get_private_data(mod); int32_t step, in_sample; diff --git a/src/audio/aria/aria_hifi3.c b/src/audio/aria/aria_hifi3.c index 17e356b968bc..363ba583b0d3 100644 --- a/src/audio/aria/aria_hifi3.c +++ b/src/audio/aria/aria_hifi3.c @@ -21,7 +21,7 @@ const uint8_t INDEX_TAB[] = { }; inline void aria_algo_calc_gain(struct aria_data *cd, size_t gain_idx, - struct audio_stream __sparse_cache *source, int frames) + struct audio_stream *source, int frames) { /* detecting maximum value in data chunk */ ae_int32x2 in_sample; @@ -61,7 +61,7 @@ inline void aria_algo_calc_gain(struct aria_data *cd, size_t gain_idx, } void aria_algo_get_data_odd_channel(struct processing_module *mod, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, int frames) { struct aria_data *cd = module_get_private_data(mod); @@ -118,7 +118,7 @@ void aria_algo_get_data_odd_channel(struct processing_module *mod, } void aria_algo_get_data_even_channel(struct processing_module *mod, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, int frames) { struct aria_data *cd = module_get_private_data(mod); diff --git a/src/audio/asrc/asrc.c b/src/audio/asrc/asrc.c index 6f25e15129c5..fae2cc1f08b9 100644 --- a/src/audio/asrc/asrc.c +++ b/src/audio/asrc/asrc.c @@ -48,8 +48,8 @@ #define COEF_C2 Q_CONVERT_FLOAT(0.99, 30) typedef void (*asrc_proc_func)(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, int *consumed, int *produced); @@ -122,8 +122,8 @@ static inline void src_inc_wrap_s16(int16_t **ptr, int16_t *end, size_t size) /* A fast copy function for same in and out rate */ static void src_copy_s32(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, int *n_read, int *n_written) { struct comp_data *cd = comp_get_drvdata(dev); @@ -194,8 +194,8 @@ static void src_copy_s32(struct comp_dev *dev, } static void src_copy_s16(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, int *n_read, int *n_written) { struct comp_data *cd = comp_get_drvdata(dev); @@ -534,7 +534,6 @@ static int asrc_params(struct comp_dev *dev, { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; int err; comp_info(dev, "asrc_params()"); @@ -554,25 +553,19 @@ static int asrc_params(struct comp_dev *dev, sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - #if CONFIG_IPC_MAJOR_4 /* update the source/sink buffer formats. Sink rate will be modified below */ - ipc4_update_buffer_format(source_c, &cd->ipc_config.base.audio_fmt); - ipc4_update_buffer_format(sink_c, &cd->ipc_config.base.audio_fmt); + ipc4_update_buffer_format(sourceb, &cd->ipc_config.base.audio_fmt); + ipc4_update_buffer_format(sinkb, &cd->ipc_config.base.audio_fmt); #endif /* Don't change sink rate if value from IPC is 0 (auto detect) */ if (asrc_get_sink_rate(&cd->ipc_config)) - audio_stream_set_rate(&sink_c->stream, asrc_get_sink_rate(&cd->ipc_config)); + audio_stream_set_rate(&sinkb->stream, asrc_get_sink_rate(&cd->ipc_config)); /* set source/sink_frames/rate */ - cd->source_rate = audio_stream_get_rate(&source_c->stream); - cd->sink_rate = audio_stream_get_rate(&sink_c->stream); - - buffer_release(sink_c); - buffer_release(source_c); + cd->source_rate = audio_stream_get_rate(&sourceb->stream); + cd->sink_rate = audio_stream_get_rate(&sinkb->stream); if (!cd->sink_rate) { comp_err(dev, "asrc_params(), zero sink rate"); @@ -604,7 +597,6 @@ static int asrc_params(struct comp_dev *dev, static int asrc_dai_find(struct comp_dev *dev, struct comp_data *cd) { struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; int pid; /* Get current pipeline ID and walk to find the DAI */ @@ -615,9 +607,7 @@ static int asrc_dai_find(struct comp_dev *dev, struct comp_data *cd) do { sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sinkb); - dev = sink_c->sink; - buffer_release(sink_c); + dev = sinkb->sink; if (!dev) { comp_cl_err(&comp_asrc, "At end, no DAI found."); @@ -635,9 +625,7 @@ static int asrc_dai_find(struct comp_dev *dev, struct comp_data *cd) do { sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(sourceb); - dev = source_c->source; - buffer_release(source_c); + dev = sourceb->source; if (!dev) { comp_cl_err(&comp_asrc, "At beginning, no DAI found."); @@ -681,8 +669,11 @@ static int asrc_dai_stop_timestamp(struct comp_data *cd) return -EINVAL; } -static int asrc_dai_get_timestamp(struct comp_data *cd, - struct timestamp_data *tsd) +#if CONFIG_ZEPHYR_NATIVE_DRIVERS + static int asrc_dai_get_timestamp(struct comp_data *cd, struct dai_ts_data *tsd) +#else + static int asrc_dai_get_timestamp(struct comp_data *cd, struct timestamp_data *tsd) +#endif { if (!cd->dai_dev) return -EINVAL; @@ -722,7 +713,6 @@ static int asrc_prepare(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; uint32_t source_period_bytes; uint32_t sink_period_bytes; int sample_bytes; @@ -748,23 +738,20 @@ static int asrc_prepare(struct comp_dev *dev) sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - /* get source data format and period bytes */ - cd->source_format = audio_stream_get_frm_fmt(&source_c->stream); - source_period_bytes = audio_stream_period_bytes(&source_c->stream, + cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); + source_period_bytes = audio_stream_period_bytes(&sourceb->stream, cd->source_frames); /* get sink data format and period bytes */ - cd->sink_format = audio_stream_get_frm_fmt(&sink_c->stream); - sink_period_bytes = audio_stream_period_bytes(&sink_c->stream, + cd->sink_format = audio_stream_get_frm_fmt(&sinkb->stream); + sink_period_bytes = audio_stream_period_bytes(&sinkb->stream, cd->sink_frames); - if (audio_stream_get_size(&sink_c->stream) < + if (audio_stream_get_size(&sinkb->stream) < dev->ipc_config.periods_sink * sink_period_bytes) { comp_err(dev, "asrc_prepare(): sink buffer size %d is insufficient < %d * %d", - audio_stream_get_size(&sink_c->stream), dev->ipc_config.periods_sink, + audio_stream_get_size(&sinkb->stream), dev->ipc_config.periods_sink, sink_period_bytes); ret = -ENOMEM; goto err; @@ -783,7 +770,7 @@ static int asrc_prepare(struct comp_dev *dev) } /* ASRC supports S16_LE, S24_4LE and S32_LE formats */ - switch (audio_stream_get_frm_fmt(&source_c->stream)) { + switch (audio_stream_get_frm_fmt(&sourceb->stream)) { case SOF_IPC_FRAME_S16_LE: cd->asrc_func = src_copy_s16; break; @@ -801,7 +788,7 @@ static int asrc_prepare(struct comp_dev *dev) } /* Allocate input and output data buffer for ASRC processing */ - frame_bytes = audio_stream_frame_bytes(&source_c->stream); + frame_bytes = audio_stream_frame_bytes(&sourceb->stream); cd->buf_size = (cd->source_frames_max + cd->sink_frames_max) * frame_bytes; @@ -815,8 +802,8 @@ static int asrc_prepare(struct comp_dev *dev) goto err; } - sample_bytes = frame_bytes / audio_stream_get_channels(&source_c->stream); - for (i = 0; i < audio_stream_get_channels(&source_c->stream); i++) { + sample_bytes = frame_bytes / audio_stream_get_channels(&sourceb->stream); + for (i = 0; i < audio_stream_get_channels(&sourceb->stream); i++) { cd->ibuf[i] = cd->buf + i * sample_bytes; cd->obuf[i] = cd->ibuf[i] + cd->source_frames_max * frame_bytes; } @@ -824,7 +811,7 @@ static int asrc_prepare(struct comp_dev *dev) /* Get required size and allocate memory for ASRC */ sample_bits = sample_bytes * 8; ret = asrc_get_required_size(dev, &cd->asrc_size, - audio_stream_get_channels(&source_c->stream), + audio_stream_get_channels(&sourceb->stream), sample_bits); if (ret) { comp_err(dev, "asrc_prepare(), get_required_size_bytes failed"); @@ -850,7 +837,7 @@ static int asrc_prepare(struct comp_dev *dev) fs_sec = cd->source_rate; } - ret = asrc_initialise(dev, cd->asrc_obj, audio_stream_get_channels(&source_c->stream), + ret = asrc_initialise(dev, cd->asrc_obj, audio_stream_get_channels(&sourceb->stream), fs_prim, fs_sec, ASRC_IOF_INTERLEAVED, ASRC_IOF_INTERLEAVED, ASRC_BM_LINEAR, cd->frames, sample_bits, @@ -886,9 +873,6 @@ static int asrc_prepare(struct comp_dev *dev) goto err_free_asrc; } - buffer_release(sink_c); - buffer_release(source_c); - return 0; err_free_asrc: @@ -901,15 +885,17 @@ static int asrc_prepare(struct comp_dev *dev) cd->buf = NULL; err: - buffer_release(sink_c); - buffer_release(source_c); comp_set_state(dev, COMP_TRIGGER_RESET); return ret; } static int asrc_control_loop(struct comp_dev *dev, struct comp_data *cd) { +#if CONFIG_ZEPHYR_NATIVE_DRIVERS + struct dai_ts_data tsd; +#else struct timestamp_data tsd; +#endif int64_t tmp; int32_t delta_sample; int32_t delta_ts; @@ -978,8 +964,8 @@ static int asrc_control_loop(struct comp_dev *dev, struct comp_data *cd) return 0; } -static void asrc_process(struct comp_dev *dev, struct comp_buffer __sparse_cache *source, - struct comp_buffer __sparse_cache *sink) +static void asrc_process(struct comp_dev *dev, struct comp_buffer *source, + struct comp_buffer *sink) { struct comp_data *cd = comp_get_drvdata(dev); int consumed = 0; @@ -1005,7 +991,6 @@ static int asrc_copy(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *source, *sink; - struct comp_buffer __sparse_cache *source_c, *sink_c; int frames_src; int frames_snk; int ret; @@ -1022,11 +1007,8 @@ static int asrc_copy(struct comp_dev *dev) sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(source); - sink_c = buffer_acquire(sink); - - frames_src = audio_stream_get_avail_frames(&source_c->stream); - frames_snk = audio_stream_get_free_frames(&sink_c->stream); + frames_src = audio_stream_get_avail_frames(&source->stream); + frames_snk = audio_stream_get_free_frames(&sink->stream); if (cd->mode == ASRC_OM_PULL) { /* Let ASRC access max number of source frames in pull mode. @@ -1052,10 +1034,7 @@ static int asrc_copy(struct comp_dev *dev) } if (cd->source_frames && cd->sink_frames) - asrc_process(dev, source_c, sink_c); - - buffer_release(sink_c); - buffer_release(source_c); + asrc_process(dev, source, sink); return 0; } diff --git a/src/audio/audio_stream.c b/src/audio/audio_stream.c index 96f02cff8b90..0308e036755c 100644 --- a/src/audio/audio_stream.c +++ b/src/audio/audio_stream.c @@ -6,21 +6,17 @@ #include #include -static size_t audio_stream_get_free_size(struct sof_sink __sparse_cache *sink) +static size_t audio_stream_get_free_size(struct sof_sink *sink) { - struct audio_stream __sparse_cache *audio_stream = - attr_container_of(sink, struct audio_stream __sparse_cache, - sink_api, __sparse_cache); + struct audio_stream *audio_stream = container_of(sink, struct audio_stream, sink_api); return audio_stream_get_free_bytes(audio_stream); } -static int audio_stream_get_buffer(struct sof_sink __sparse_cache *sink, size_t req_size, +static int audio_stream_get_buffer(struct sof_sink *sink, size_t req_size, void **data_ptr, void **buffer_start, size_t *buffer_size) { - struct audio_stream __sparse_cache *audio_stream = - attr_container_of(sink, struct audio_stream __sparse_cache, - sink_api, __sparse_cache); + struct audio_stream *audio_stream = container_of(sink, struct audio_stream, sink_api); if (req_size > audio_stream_get_free_size(sink)) return -ENODATA; @@ -32,47 +28,37 @@ static int audio_stream_get_buffer(struct sof_sink __sparse_cache *sink, size_t return 0; } -static int audio_stream_commit_buffer(struct sof_sink __sparse_cache *sink, size_t commit_size) +static int audio_stream_commit_buffer(struct sof_sink *sink, size_t commit_size) { - struct audio_stream __sparse_cache *audio_stream = - attr_container_of(sink, struct audio_stream __sparse_cache, - sink_api, __sparse_cache); - struct comp_buffer __sparse_cache *buffer_c = - attr_container_of(audio_stream, struct comp_buffer __sparse_cache, - stream, __sparse_cache); + struct audio_stream *audio_stream = container_of(sink, struct audio_stream, sink_api); + struct comp_buffer *buffer = container_of(audio_stream, struct comp_buffer, stream); if (commit_size) { - buffer_stream_writeback(buffer_c, commit_size); + buffer_stream_writeback(buffer, commit_size); audio_stream_produce(audio_stream, commit_size); } return 0; } -static size_t audio_stream_get_data_available(struct sof_source __sparse_cache *source) +static size_t audio_stream_get_data_available(struct sof_source *source) { - struct audio_stream __sparse_cache *audio_stream = - attr_container_of(source, struct audio_stream __sparse_cache, - source_api, __sparse_cache); + struct audio_stream *audio_stream = container_of(source, struct audio_stream, source_api); return audio_stream_get_avail_bytes(audio_stream); } -static int audio_stream_get_data(struct sof_source __sparse_cache *source, size_t req_size, - void **data_ptr, void **buffer_start, size_t *buffer_size) +static int audio_stream_get_data(struct sof_source *source, size_t req_size, + void const **data_ptr, void const **buffer_start, + size_t *buffer_size) { - struct audio_stream __sparse_cache *audio_stream = - attr_container_of(source, struct audio_stream __sparse_cache, - source_api, __sparse_cache); - - struct comp_buffer __sparse_cache *buffer_c = - attr_container_of(audio_stream, struct comp_buffer __sparse_cache, - stream, __sparse_cache); + struct audio_stream *audio_stream = container_of(source, struct audio_stream, source_api); + struct comp_buffer *buffer = container_of(audio_stream, struct comp_buffer, stream); if (req_size > audio_stream_get_data_available(source)) return -ENODATA; - buffer_stream_invalidate(buffer_c, req_size); + buffer_stream_invalidate(buffer, req_size); /* get circular buffer parameters */ *data_ptr = audio_stream->r_ptr; @@ -81,11 +67,9 @@ static int audio_stream_get_data(struct sof_source __sparse_cache *source, size_ return 0; } -static int audio_stream_release_data(struct sof_source __sparse_cache *source, size_t free_size) +static int audio_stream_release_data(struct sof_source *source, size_t free_size) { - struct audio_stream __sparse_cache *audio_stream = - attr_container_of(source, struct audio_stream __sparse_cache, - source_api, __sparse_cache); + struct audio_stream *audio_stream = container_of(source, struct audio_stream, source_api); if (free_size) audio_stream_consume(audio_stream, free_size); @@ -93,54 +77,42 @@ static int audio_stream_release_data(struct sof_source __sparse_cache *source, s return 0; } -static int audio_stream_set_ipc_params_source(struct sof_source __sparse_cache *source, +static int audio_stream_set_ipc_params_source(struct sof_source *source, struct sof_ipc_stream_params *params, bool force_update) { - struct audio_stream __sparse_cache *audio_stream = - attr_container_of(source, struct audio_stream __sparse_cache, - source_api, __sparse_cache); - struct comp_buffer __sparse_cache *buffer = - attr_container_of(audio_stream, struct comp_buffer __sparse_cache, - stream, __sparse_cache); + struct audio_stream *audio_stream = container_of(source, struct audio_stream, source_api); + struct comp_buffer *buffer = container_of(audio_stream, struct comp_buffer, stream); return buffer_set_params(buffer, params, force_update); } -static int audio_stream_set_ipc_params_sink(struct sof_sink __sparse_cache *sink, +static int audio_stream_set_ipc_params_sink(struct sof_sink *sink, struct sof_ipc_stream_params *params, bool force_update) { - struct audio_stream __sparse_cache *audio_stream = - attr_container_of(sink, struct audio_stream __sparse_cache, - sink_api, __sparse_cache); - struct comp_buffer __sparse_cache *buffer = - attr_container_of(audio_stream, struct comp_buffer __sparse_cache, - stream, __sparse_cache); + struct audio_stream *audio_stream = container_of(sink, struct audio_stream, sink_api); + struct comp_buffer *buffer = container_of(audio_stream, struct comp_buffer, stream); return buffer_set_params(buffer, params, force_update); } -static int audio_stream_source_set_alignment_constants(struct sof_source __sparse_cache *source, +static int audio_stream_source_set_alignment_constants(struct sof_source *source, const uint32_t byte_align, const uint32_t frame_align_req) { - struct audio_stream __sparse_cache *audio_stream = - attr_container_of(source, struct audio_stream __sparse_cache, - source_api, __sparse_cache); + struct audio_stream *audio_stream = container_of(source, struct audio_stream, source_api); audio_stream_init_alignment_constants(byte_align, frame_align_req, audio_stream); return 0; } -static int audio_stream_sink_set_alignment_constants(struct sof_sink __sparse_cache *sink, +static int audio_stream_sink_set_alignment_constants(struct sof_sink *sink, const uint32_t byte_align, const uint32_t frame_align_req) { - struct audio_stream __sparse_cache *audio_stream = - attr_container_of(sink, struct audio_stream __sparse_cache, - sink_api, __sparse_cache); + struct audio_stream *audio_stream = container_of(sink, struct audio_stream, sink_api); audio_stream_init_alignment_constants(byte_align, frame_align_req, audio_stream); @@ -163,8 +135,7 @@ static const struct sink_ops audio_stream_sink_ops = { .set_alignment_constants = audio_stream_sink_set_alignment_constants }; -void audio_stream_init(struct audio_stream __sparse_cache *audio_stream, - void *buff_addr, uint32_t size) +void audio_stream_init(struct audio_stream *audio_stream, void *buff_addr, uint32_t size) { audio_stream->size = size; audio_stream->addr = buff_addr; @@ -177,10 +148,8 @@ void audio_stream_init(struct audio_stream __sparse_cache *audio_stream, audio_stream_init_alignment_constants(1, 1, audio_stream); source_init(audio_stream_get_source(audio_stream), &audio_stream_source_ops, - (__sparse_force struct sof_audio_stream_params *) &audio_stream->runtime_stream_params); sink_init(audio_stream_get_sink(audio_stream), &audio_stream_sink_ops, - (__sparse_force struct sof_audio_stream_params *) &audio_stream->runtime_stream_params); audio_stream_reset(audio_stream); } diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 05e99194e608..ce7b5ca7778e 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -51,7 +51,7 @@ static int basefw_config(uint32_t *data_offset, char *data) tuple = tlv_next(tuple); tlv_value_uint32_set(tuple, IPC4_SLOW_CLOCK_FREQ_HZ_FW_CFG, - clock_get_freq(CPU_LPRO_FREQ_IDX)); + clock_get_freq(CPU_LOWEST_FREQ_IDX)); tuple = tlv_next(tuple); tlv_value_uint32_set(tuple, IPC4_SLOW_CLOCK_FREQ_HZ_FW_CFG, IPC4_ALH_CAVS_1_8); diff --git a/src/audio/buffer.c b/src/audio/buffer.c index c9c86cf8dc61..02f6c9da0777 100644 --- a/src/audio/buffer.c +++ b/src/audio/buffer.c @@ -27,10 +27,10 @@ DECLARE_SOF_RT_UUID("buffer", buffer_uuid, 0x42544c92, 0x8e92, 0x4e41, 0xb6, 0x79, 0x34, 0x51, 0x9f, 0x1c, 0x1d, 0x28); DECLARE_TR_CTX(buffer_tr, SOF_UUID(buffer_uuid), LOG_LEVEL_INFO); -struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, uint32_t align) +struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, uint32_t align, + bool is_shared) { struct comp_buffer *buffer; - struct comp_buffer __sparse_cache *buffer_c; void *stream_addr; tr_dbg(&buffer_tr, "buffer_alloc()"); @@ -42,16 +42,19 @@ struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, u return NULL; } - /* - * allocate new buffer, align the allocation size to a cache line for - * the coherent API - */ - buffer = coherent_init_thread(struct comp_buffer, c); + /* allocate new buffer */ + enum mem_zone zone = is_shared ? SOF_MEM_ZONE_RUNTIME_SHARED : SOF_MEM_ZONE_RUNTIME; + + buffer = rzalloc(zone, 0, SOF_MEM_CAPS_RAM, sizeof(*buffer)); + if (!buffer) { tr_err(&buffer_tr, "buffer_alloc(): could not alloc structure"); return NULL; } + CORE_CHECK_STRUCT_INIT(buffer, is_shared); + + buffer->is_shared = is_shared; stream_addr = rballoc_align(0, caps, size, align); if (!stream_addr) { rfree(buffer); @@ -61,26 +64,11 @@ struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, u } /* From here no more uncached access to the buffer object, except its list headers */ - buffer_c = buffer_acquire(buffer); - audio_stream_set_addr(&buffer_c->stream, stream_addr); - buffer_init(buffer_c, size, caps); - - audio_stream_set_underrun(&buffer_c->stream, !!(flags & SOF_BUF_UNDERRUN_PERMITTED)); - audio_stream_set_overrun(&buffer_c->stream, !!(flags & SOF_BUF_OVERRUN_PERMITTED)); - - buffer_release(buffer_c); - - /* - * The buffer hasn't yet been marked as shared, hence buffer_release() - * hasn't written back and invalidated the cache. Therefore we have to - * do this manually now before adding to the lists. Buffer list - * structures are always accessed uncached and they're never modified at - * run-time, i.e. buffers are never relinked. So we have to make sure, - * that what we have written into buffer's cache is in RAM before - * modifying that RAM bypassing cache, and that after this cache is - * re-loaded again. - */ - dcache_writeback_invalidate_region(uncache_to_cache(buffer), sizeof(*buffer)); + audio_stream_set_addr(&buffer->stream, stream_addr); + buffer_init(buffer, size, caps); + + audio_stream_set_underrun(&buffer->stream, !!(flags & SOF_BUF_UNDERRUN_PERMITTED)); + audio_stream_set_overrun(&buffer->stream, !!(flags & SOF_BUF_OVERRUN_PERMITTED)); list_init(&buffer->source_list); list_init(&buffer->sink_list); @@ -88,9 +76,10 @@ struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, u return buffer; } -void buffer_zero(struct comp_buffer __sparse_cache *buffer) +void buffer_zero(struct comp_buffer *buffer) { buf_dbg(buffer, "stream_zero()"); + CORE_CHECK_STRUCT(buffer); bzero(audio_stream_get_addr(&buffer->stream), audio_stream_get_size(&buffer->stream)); if (buffer->caps & SOF_MEM_CAPS_DMA) @@ -99,10 +88,12 @@ void buffer_zero(struct comp_buffer __sparse_cache *buffer) audio_stream_get_size(&buffer->stream)); } -int buffer_set_size(struct comp_buffer __sparse_cache *buffer, uint32_t size, uint32_t alignment) +int buffer_set_size(struct comp_buffer *buffer, uint32_t size, uint32_t alignment) { void *new_ptr = NULL; + CORE_CHECK_STRUCT(buffer); + /* validate request */ if (size == 0) { buf_err(buffer, "resize size = %u is invalid", size); @@ -135,12 +126,14 @@ int buffer_set_size(struct comp_buffer __sparse_cache *buffer, uint32_t size, ui return 0; } -int buffer_set_params(struct comp_buffer __sparse_cache *buffer, +int buffer_set_params(struct comp_buffer *buffer, struct sof_ipc_stream_params *params, bool force_update) { int ret; int i; + CORE_CHECK_STRUCT(buffer); + if (!params) { buf_err(buffer, "buffer_set_params(): !params"); return -EINVAL; @@ -164,10 +157,11 @@ int buffer_set_params(struct comp_buffer __sparse_cache *buffer, return 0; } -bool buffer_params_match(struct comp_buffer __sparse_cache *buffer, +bool buffer_params_match(struct comp_buffer *buffer, struct sof_ipc_stream_params *params, uint32_t flag) { assert(params); + CORE_CHECK_STRUCT(buffer); if ((flag & BUFF_PARAMS_FRAME_FMT) && audio_stream_get_frm_fmt(&buffer->stream) != params->frame_fmt) @@ -191,6 +185,8 @@ void buffer_free(struct comp_buffer *buffer) .buffer = buffer, }; + CORE_CHECK_STRUCT(buffer); + if (!buffer) return; @@ -203,22 +199,10 @@ void buffer_free(struct comp_buffer *buffer) notifier_unregister_all(NULL, buffer); rfree(buffer->stream.addr); - coherent_free_thread(buffer, c); + rfree(buffer); } -/* - * comp_update_buffer_produce() and comp_update_buffer_consume() send - * NOTIFIER_ID_BUFFER_PRODUCE and NOTIFIER_ID_BUFFER_CONSUME notifier events - * respectively. The only recipient of those notifications is probes. The - * target for those notifications is always the current core, therefore notifier - * callbacks will be called synchronously from notifier_event() calls. Therefore - * we cannot pass unlocked buffer pointers to probes, because if they try to - * acquire the buffer, that can cause a deadlock. In general locked objects - * shouldn't be passed to potentially asynchronous contexts, but here we have no - * choice but to use our knowledge of the local notifier behaviour and pass - * locked buffers to notification recipients. - */ -void comp_update_buffer_produce(struct comp_buffer __sparse_cache *buffer, uint32_t bytes) +void comp_update_buffer_produce(struct comp_buffer *buffer, uint32_t bytes) { struct buffer_cb_transact cb_data = { .buffer = buffer, @@ -240,8 +224,7 @@ void comp_update_buffer_produce(struct comp_buffer __sparse_cache *buffer, uint3 audio_stream_produce(&buffer->stream, bytes); - /* Notifier looks for the pointer value to match it against registration */ - notifier_event(cache_to_uncache(buffer), NOTIFIER_ID_BUFFER_PRODUCE, + notifier_event(buffer, NOTIFIER_ID_BUFFER_PRODUCE, NOTIFIER_TARGET_CORE_LOCAL, &cb_data, sizeof(cb_data)); #if CONFIG_SOF_LOG_DBG_BUFFER @@ -257,7 +240,7 @@ void comp_update_buffer_produce(struct comp_buffer __sparse_cache *buffer, uint3 #endif } -void comp_update_buffer_consume(struct comp_buffer __sparse_cache *buffer, uint32_t bytes) +void comp_update_buffer_consume(struct comp_buffer *buffer, uint32_t bytes) { struct buffer_cb_transact cb_data = { .buffer = buffer, @@ -265,6 +248,8 @@ void comp_update_buffer_consume(struct comp_buffer __sparse_cache *buffer, uint3 .transaction_begin_address = audio_stream_get_rptr(&buffer->stream), }; + CORE_CHECK_STRUCT(buffer); + /* return if no bytes */ if (!bytes) { #if CONFIG_SOF_LOG_DBG_BUFFER @@ -279,7 +264,7 @@ void comp_update_buffer_consume(struct comp_buffer __sparse_cache *buffer, uint3 audio_stream_consume(&buffer->stream, bytes); - notifier_event(cache_to_uncache(buffer), NOTIFIER_ID_BUFFER_CONSUME, + notifier_event(buffer, NOTIFIER_ID_BUFFER_CONSUME, NOTIFIER_TARGET_CORE_LOCAL, &cb_data, sizeof(cb_data)); #if CONFIG_SOF_LOG_DBG_BUFFER @@ -303,30 +288,8 @@ void comp_update_buffer_consume(struct comp_buffer __sparse_cache *buffer, uint3 void buffer_attach(struct comp_buffer *buffer, struct list_item *head, int dir) { struct list_item *list = buffer_comp_list(buffer, dir); - struct list_item __sparse_cache *needs_sync; - bool further_buffers_exist; - - /* - * There can already be buffers on the target list. If we just link this - * buffer, we modify the first buffer's list header via uncached alias, - * so its cached copy can later be written back, overwriting the - * modified header. FIXME: this is still a problem with different cores. - */ - further_buffers_exist = !list_is_empty(head); - needs_sync = uncache_to_cache(head->next); - if (further_buffers_exist) - dcache_writeback_region(needs_sync, sizeof(struct list_item)); - /* The cache line can be prefetched here, invalidate it after prepending */ + CORE_CHECK_STRUCT(buffer); list_item_prepend(list, head); - if (further_buffers_exist) - dcache_invalidate_region(needs_sync, sizeof(struct list_item)); -#if CONFIG_INTEL - /* - * Until now the buffer object wasn't in cache, but uncached access to it could have - * triggered a cache prefetch. Drop that cache line to avoid using stale data in it. - */ - dcache_invalidate_region(uncache_to_cache(list), sizeof(*list)); -#endif } /* @@ -335,32 +298,7 @@ void buffer_attach(struct comp_buffer *buffer, struct list_item *head, int dir) */ void buffer_detach(struct comp_buffer *buffer, struct list_item *head, int dir) { - struct list_item __sparse_cache *needs_sync_prev, *needs_sync_next; - bool buffers_after_exist, buffers_before_exist; struct list_item *buf_list = buffer_comp_list(buffer, dir); - - /* - * There can be more buffers linked together with this one, that will - * still be staying on their respective pipelines and might get used via - * their cached aliases. If we just unlink this buffer, we modify their - * list header via uncached alias, so their cached copy can later be - * written back, overwriting the modified header. FIXME: this is still a - * problem with different cores. - */ - buffers_after_exist = head != buf_list->next; - buffers_before_exist = head != buf_list->prev; - needs_sync_prev = uncache_to_cache(buf_list->prev); - needs_sync_next = uncache_to_cache(buf_list->next); - if (buffers_after_exist) - dcache_writeback_region(needs_sync_next, sizeof(struct list_item)); - if (buffers_before_exist) - dcache_writeback_region(needs_sync_prev, sizeof(struct list_item)); - dcache_writeback_region(uncache_to_cache(buf_list), sizeof(*buf_list)); - /* buffers before or after can be prefetched here */ + CORE_CHECK_STRUCT(buffer); list_item_del(buf_list); - dcache_invalidate_region(uncache_to_cache(buf_list), sizeof(*buf_list)); - if (buffers_after_exist) - dcache_invalidate_region(needs_sync_next, sizeof(struct list_item)); - if (buffers_before_exist) - dcache_invalidate_region(needs_sync_prev, sizeof(struct list_item)); } diff --git a/src/audio/chain_dma.c b/src/audio/chain_dma.c index b8cf7ded072a..25cec633728a 100644 --- a/src/audio/chain_dma.c +++ b/src/audio/chain_dma.c @@ -238,12 +238,9 @@ static enum task_state chain_task_run(void *data) * mode task will update read position based on transferred data size to avoid * overwriting valid data and write position by half buffer size. */ - struct comp_buffer __sparse_cache *buffer_c = buffer_acquire(cd->dma_buffer); - const size_t buff_size = audio_stream_get_size(&buffer_c->stream); + const size_t buff_size = audio_stream_get_size(&cd->dma_buffer->stream); const size_t half_buff_size = buff_size / 2; - buffer_release(buffer_c); - if (!cd->first_data_received && host_avail_bytes > half_buff_size) { ret = dma_reload(cd->chan_link->dma->z_dev, cd->chan_link->index, 0, 0, @@ -510,7 +507,6 @@ static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uint8_t li uint32_t fifo_size) { struct chain_dma_data *cd = comp_get_drvdata(dev); - struct comp_buffer __sparse_cache *buffer_c; uint32_t addr_align; size_t buff_size; void *buff_addr; @@ -588,8 +584,8 @@ static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uint8_t li } fifo_size = ALIGN_UP_INTERNAL(fifo_size, addr_align); - - cd->dma_buffer = buffer_alloc(fifo_size, SOF_MEM_CAPS_DMA, 0, addr_align); + /* allocate not shared buffer */ + cd->dma_buffer = buffer_alloc(fifo_size, SOF_MEM_CAPS_DMA, 0, addr_align, false); if (!cd->dma_buffer) { comp_err(dev, "chain_task_init(): failed to alloc dma buffer"); @@ -598,11 +594,9 @@ static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uint8_t li } /* clear dma buffer */ - buffer_c = buffer_acquire(cd->dma_buffer); - buffer_zero(buffer_c); - buff_addr = audio_stream_get_addr(&buffer_c->stream); - buff_size = audio_stream_get_size(&buffer_c->stream); - buffer_release(buffer_c); + buffer_zero(cd->dma_buffer); + buff_addr = audio_stream_get_addr(&cd->dma_buffer->stream); + buff_size = audio_stream_get_size(&cd->dma_buffer->stream); ret = chain_init(dev, buff_addr, buff_size); if (ret < 0) { diff --git a/src/audio/component.c b/src/audio/component.c index 51e6b4250f9b..e51f8ec461b2 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -158,8 +158,8 @@ void sys_comp_init(struct sof *sof) k_spinlock_init(&sof->comp_drivers->lock); } -void comp_get_copy_limits(struct comp_buffer __sparse_cache *source, - struct comp_buffer __sparse_cache *sink, +void comp_get_copy_limits(struct comp_buffer *source, + struct comp_buffer *sink, struct comp_copy_limits *cl) { cl->frames = audio_stream_avail_frames(&source->stream, &sink->stream); @@ -169,8 +169,8 @@ void comp_get_copy_limits(struct comp_buffer __sparse_cache *source, cl->sink_bytes = cl->frames * cl->sink_frame_bytes; } -void comp_get_copy_limits_frame_aligned(const struct comp_buffer __sparse_cache *source, - const struct comp_buffer __sparse_cache *sink, +void comp_get_copy_limits_frame_aligned(const struct comp_buffer *source, + const struct comp_buffer *sink, struct comp_copy_limits *cl) { cl->frames = audio_stream_avail_frames_aligned(&source->stream, &sink->stream); @@ -182,8 +182,8 @@ void comp_get_copy_limits_frame_aligned(const struct comp_buffer __sparse_cache #ifdef STREAMCOPY_HIFI3 -int audio_stream_copy(const struct audio_stream __sparse_cache *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, uint32_t ooffset, uint32_t samples) +int audio_stream_copy(const struct audio_stream *source, uint32_t ioffset, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int ssize = audio_stream_sample_bytes(source); /* src fmt == sink fmt */ ae_int16x4 *src = (ae_int16x4 *)((int8_t *)audio_stream_get_rptr(source) + ioffset * ssize); @@ -227,8 +227,8 @@ int audio_stream_copy(const struct audio_stream __sparse_cache *source, uint32_t #else -int audio_stream_copy(const struct audio_stream __sparse_cache *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, uint32_t ooffset, uint32_t samples) +int audio_stream_copy(const struct audio_stream *source, uint32_t ioffset, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int ssize = audio_stream_sample_bytes(source); /* src fmt == sink fmt */ uint8_t *src = audio_stream_wrap(source, (uint8_t *)audio_stream_get_rptr(source) + @@ -279,7 +279,7 @@ void cir_buf_copy(void *src, void *src_addr, void *src_end, void *dst, } void audio_stream_copy_from_linear(const void *linear_source, int ioffset, - struct audio_stream __sparse_cache *sink, int ooffset, + struct audio_stream *sink, int ooffset, unsigned int samples) { int ssize = audio_stream_sample_bytes(sink); /* src fmt == sink fmt */ @@ -300,7 +300,7 @@ void audio_stream_copy_from_linear(const void *linear_source, int ioffset, } } -void audio_stream_copy_to_linear(const struct audio_stream __sparse_cache *source, int ioffset, +void audio_stream_copy_to_linear(const struct audio_stream *source, int ioffset, void *linear_sink, int ooffset, unsigned int samples) { int ssize = audio_stream_sample_bytes(source); /* src fmt == sink fmt */ @@ -328,9 +328,25 @@ int comp_copy(struct comp_dev *dev) assert(dev->drv->ops.copy); - /* copy only if we are the owner of the LL component */ - if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL && - cpu_is_me(dev->ipc_config.core)) { + /* copy only if we are the owner of component OR this is DP component + * + * DP components (modules) require two stage processing: + * + * LL_mod -> [comp_buffer -> dp_queue] -> dp_mod -> [dp_queue -> comp_buffer] -> LL_mod + * + * - in first step (it means - now) the pipeline must copy source data from comp_buffer + * to dp_queue and result data from dp_queue to comp_buffer + * + * - second step will be performed by a thread specific to the DP module - DP module + * will take data from input dpQueue (using source API) , process it + * and put in output DP queue (using sink API) + * + * this allows the current pipeline structure to see a DP module as a "normal" LL + * + * to be removed when pipeline 2.0 is ready + */ + if (cpu_is_me(dev->ipc_config.core) || + dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { #if CONFIG_PERFORMANCE_COUNTERS perf_cnt_init(&dev->pcd); #endif diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index ae03226be8c1..0bb2306d2a6e 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -178,8 +178,8 @@ static int copier_free(struct processing_module *mod) static int copier_params(struct processing_module *mod); static int copier_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct copier_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; @@ -266,7 +266,6 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) struct sof_ipc_stream_posn posn; struct comp_dev *dai_copier; struct comp_buffer *buffer; - struct comp_buffer __sparse_cache *buffer_c; uint32_t latency; int ret; @@ -358,10 +357,8 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) } buffer = list_first_item(&dai_copier->bsource_list, struct comp_buffer, sink_list); - buffer_c = buffer_acquire(buffer); pipe_reg.stream_start_offset = posn.dai_posn + - latency * audio_stream_get_size(&buffer_c->stream); - buffer_release(buffer_c); + latency * audio_stream_get_size(&buffer->stream); pipe_reg.stream_end_offset = 0; mailbox_sw_regs_write(cd->pipeline_reg_offset, &pipe_reg, sizeof(pipe_reg)); } else if (cmd == COMP_TRIGGER_PAUSE) { @@ -384,9 +381,7 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) } buffer = list_first_item(&dai_copier->bsource_list, struct comp_buffer, sink_list); - buffer_c = buffer_acquire(buffer); - pipe_reg.stream_start_offset += latency * audio_stream_get_size(&buffer_c->stream); - buffer_release(buffer_c); + pipe_reg.stream_start_offset += latency * audio_stream_get_size(&buffer->stream); mailbox_sw_regs_write(cd->pipeline_reg_offset, &pipe_reg.stream_start_offset, sizeof(pipe_reg.stream_start_offset)); } @@ -396,8 +391,8 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd) static int do_conversion_copy(struct comp_dev *dev, struct copier_data *cd, - struct comp_buffer __sparse_cache *src, - struct comp_buffer __sparse_cache *sink, + struct comp_buffer *src, + struct comp_buffer *sink, struct comp_copy_limits *processed_data) { int i; @@ -423,10 +418,9 @@ static int do_conversion_copy(struct comp_dev *dev, } static int copier_copy_to_sinks(struct copier_data *cd, struct comp_dev *dev, - struct comp_buffer __sparse_cache *src_c, + struct comp_buffer *src_c, struct comp_copy_limits *processed_data) { - struct comp_buffer __sparse_cache *sink_c; struct list_item *sink_list; struct comp_buffer *sink; int ret = 0; @@ -436,14 +430,12 @@ static int copier_copy_to_sinks(struct copier_data *cd, struct comp_dev *dev, struct comp_dev *sink_dev; sink = container_of(sink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - sink_dev = sink_c->sink; + sink_dev = sink->sink; processed_data->sink_bytes = 0; if (sink_dev->state == COMP_STATE_ACTIVE) { - ret = do_conversion_copy(dev, cd, src_c, sink_c, processed_data); + ret = do_conversion_copy(dev, cd, src_c, sink, processed_data); cd->output_total_data_processed += processed_data->sink_bytes; } - buffer_release(sink_c); if (ret < 0) { comp_err(dev, "failed to copy buffer for comp %x", dev->ipc_config.id); @@ -466,26 +458,23 @@ static int copier_module_copy(struct processing_module *mod, struct output_stream_buffer *output_buffers, int num_output_buffers) { struct copier_data *cd = module_get_private_data(mod); - struct comp_buffer __sparse_cache *src_c; + struct comp_buffer *src_c; struct comp_copy_limits processed_data; int i; if (!num_input_buffers || !num_output_buffers) return 0; - src_c = attr_container_of(input_buffers[0].data, struct comp_buffer __sparse_cache, - stream, __sparse_cache); + src_c = container_of(input_buffers[0].data, struct comp_buffer, stream); processed_data.source_bytes = 0; /* convert format and copy to each active sink */ for (i = 0; i < num_output_buffers; i++) { - struct comp_buffer __sparse_cache *sink_c; + struct comp_buffer *sink_c; struct comp_dev *sink_dev; - sink_c = attr_container_of(output_buffers[i].data, - struct comp_buffer __sparse_cache, - stream, __sparse_cache); + sink_c = container_of(output_buffers[i].data, struct comp_buffer, stream); sink_dev = sink_c->sink; processed_data.sink_bytes = 0; if (sink_dev->state == COMP_STATE_ACTIVE) { @@ -518,7 +507,6 @@ static int copier_module_copy(struct processing_module *mod, static int copier_multi_endpoint_dai_copy(struct copier_data *cd, struct comp_dev *dev) { - struct comp_buffer __sparse_cache *src_c, *sink_c; struct comp_copy_limits processed_data; struct comp_buffer *src; int ret; @@ -532,9 +520,7 @@ static int copier_multi_endpoint_dai_copy(struct copier_data *cd, struct comp_de if (ret < 0) return ret; - src_c = buffer_acquire(cd->multi_endpoint_buffer); - ret = copier_copy_to_sinks(cd, dev, src_c, &processed_data); - buffer_release(src_c); + ret = copier_copy_to_sinks(cd, dev, cd->multi_endpoint_buffer, &processed_data); return ret; } @@ -546,24 +532,18 @@ static int copier_multi_endpoint_dai_copy(struct copier_data *cd, struct comp_de } src = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - src_c = buffer_acquire(src); /* gateway(s) on output */ - sink_c = buffer_acquire(cd->multi_endpoint_buffer); - ret = do_conversion_copy(dev, cd, src_c, sink_c, &processed_data); - buffer_release(sink_c); - + ret = do_conversion_copy(dev, cd, src, cd->multi_endpoint_buffer, &processed_data); if (ret < 0) - goto err; + return ret; ret = dai_zephyr_multi_endpoint_copy(cd->dd, dev, cd->multi_endpoint_buffer, cd->endpoint_num); if (!ret) { - comp_update_buffer_consume(src_c, processed_data.source_bytes); + comp_update_buffer_consume(src, processed_data.source_bytes); cd->input_total_data_processed += processed_data.source_bytes; } -err: - buffer_release(src_c); return ret; } @@ -649,7 +629,6 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data, const struct ipc4_copier_config_set_sink_format *sink_fmt = data; struct processing_module *mod = comp_get_drvdata(dev); struct copier_data *cd = module_get_private_data(mod); - struct comp_buffer __sparse_cache *sink_c; struct list_item *sink_list; struct comp_buffer *sink; @@ -686,16 +665,12 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data, int sink_id; sink = container_of(sink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - sink_id = IPC4_SINK_QUEUE_ID(sink_c->id); + sink_id = IPC4_SINK_QUEUE_ID(sink->id); if (sink_id == sink_fmt->sink_id) { - ipc4_update_buffer_format(sink_c, &sink_fmt->sink_fmt); - buffer_release(sink_c); + ipc4_update_buffer_format(sink, &sink_fmt->sink_fmt); break; } - - buffer_release(sink_c); } return 0; @@ -943,7 +918,11 @@ static int copier_dai_ts_start_op(struct comp_dev *dev) return dai_common_ts_start(dd, dev); } +#if CONFIG_ZEPHYR_NATIVE_DRIVERS +static int copier_dai_ts_get_op(struct comp_dev *dev, struct dai_ts_data *tsd) +#else static int copier_dai_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd) +#endif { struct processing_module *mod = comp_get_drvdata(dev); struct copier_data *cd = module_get_private_data(mod); @@ -1003,8 +982,8 @@ static struct module_endpoint_ops copier_endpoint_ops = { .trigger = copier_comp_trigger }; -static struct module_interface copier_interface = { - .init = copier_init, +static const struct module_interface copier_interface = { + .init = copier_init, .prepare = copier_prepare, .process_audio_stream = copier_process, .reset = copier_reset, diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index 31b832b81d01..8704d3aacb59 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -310,9 +310,9 @@ int copier_dai_prepare(struct comp_dev *dev, struct copier_data *cd) return 0; } -static int copy_single_channel_c16(const struct audio_stream __sparse_cache *src, +static int copy_single_channel_c16(const struct audio_stream *src, unsigned int src_channel, - struct audio_stream __sparse_cache *dst, + struct audio_stream *dst, unsigned int dst_channel, unsigned int frame_count) { int16_t *r_ptr = (int16_t *)audio_stream_get_rptr(src) + src_channel; @@ -351,9 +351,9 @@ static int copy_single_channel_c16(const struct audio_stream __sparse_cache *src return 0; } -static int copy_single_channel_c32(const struct audio_stream __sparse_cache *src, +static int copy_single_channel_c32(const struct audio_stream *src, unsigned int src_channel, - struct audio_stream __sparse_cache *dst, + struct audio_stream *dst, unsigned int dst_channel, unsigned int frame_count) { int32_t *r_ptr = (int32_t *)audio_stream_get_rptr(src) + src_channel; @@ -395,7 +395,6 @@ static int copy_single_channel_c32(const struct audio_stream __sparse_cache *src int copier_dai_params(struct copier_data *cd, struct comp_dev *dev, struct sof_ipc_stream_params *params, int dai_index) { - struct comp_buffer __sparse_cache *buf_c; struct sof_ipc_stream_params demuxed_params = *params; const struct ipc4_audio_format *in_fmt = &cd->config.base.audio_fmt; const struct ipc4_audio_format *out_fmt = &cd->config.out_fmt; @@ -438,15 +437,11 @@ int copier_dai_params(struct copier_data *cd, struct comp_dev *dev, if (ret < 0) return ret; - buf_c = buffer_acquire(cd->dd[dai_index]->dma_buffer); for (j = 0; j < SOF_IPC_MAX_CHANNELS; j++) - buf_c->chmap[j] = (cd->chan_map[dai_index] >> j * 4) & 0xf; - buffer_release(buf_c); + cd->dd[dai_index]->dma_buffer->chmap[j] = (cd->chan_map[dai_index] >> j * 4) & 0xf; /* set channel copy func */ - buf_c = buffer_acquire(cd->multi_endpoint_buffer); - container_size = audio_stream_sample_bytes(&buf_c->stream); - buffer_release(buf_c); + container_size = audio_stream_sample_bytes(&cd->multi_endpoint_buffer->stream); switch (container_size) { case 2: diff --git a/src/audio/copier/copier_generic.c b/src/audio/copier/copier_generic.c index c610d05a049d..e8ac1e111510 100644 --- a/src/audio/copier/copier_generic.c +++ b/src/audio/copier/copier_generic.c @@ -22,7 +22,7 @@ LOG_MODULE_DECLARE(copier, CONFIG_SOF_LOG_LEVEL); #include int apply_attenuation(struct comp_dev *dev, struct copier_data *cd, - struct comp_buffer __sparse_cache *sink, int frame) + struct comp_buffer *sink, int frame) { int i; int n; @@ -62,7 +62,6 @@ void copier_update_params(struct copier_data *cd, struct comp_dev *dev, struct sof_ipc_stream_params *params) { struct comp_buffer *sink, *source; - struct comp_buffer __sparse_cache *sink_c, *source_c; struct list_item *sink_list; memset(params, 0, sizeof(*params)); @@ -85,13 +84,10 @@ void copier_update_params(struct copier_data *cd, struct comp_dev *dev, int j; sink = container_of(sink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - j = IPC4_SINK_QUEUE_ID(sink_c->id); + j = IPC4_SINK_QUEUE_ID(sink->id); - ipc4_update_buffer_format(sink_c, &cd->out_fmt[j]); - - buffer_release(sink_c); + ipc4_update_buffer_format(sink, &cd->out_fmt[j]); } /* @@ -102,12 +98,9 @@ void copier_update_params(struct copier_data *cd, struct comp_dev *dev, struct ipc4_audio_format *in_fmt; source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(source); in_fmt = &cd->config.base.audio_fmt; - ipc4_update_buffer_format(source_c, in_fmt); - - buffer_release(source_c); + ipc4_update_buffer_format(source, in_fmt); } /* update params for the DMA buffer */ @@ -140,7 +133,6 @@ int create_endpoint_buffer(struct comp_dev *dev, enum sof_ipc_frame valid_fmt; struct sof_ipc_buffer ipc_buf; struct comp_buffer *buffer; - struct comp_buffer __sparse_cache *buffer_c; uint32_t buf_size; uint32_t chan_map; int i; @@ -204,24 +196,22 @@ int create_endpoint_buffer(struct comp_dev *dev, ipc_buf.size = buf_size; ipc_buf.comp.pipeline_id = config->pipeline_id; ipc_buf.comp.core = config->core; - - buffer = buffer_new(&ipc_buf); + /* allocate not shared buffer */ + buffer = buffer_new(&ipc_buf, false); if (!buffer) return -ENOMEM; - buffer_c = buffer_acquire(buffer); - audio_stream_set_channels(&buffer_c->stream, copier_cfg->base.audio_fmt.channels_count); - audio_stream_set_rate(&buffer_c->stream, copier_cfg->base.audio_fmt.sampling_frequency); - audio_stream_set_frm_fmt(&buffer_c->stream, config->frame_fmt); - audio_stream_set_valid_fmt(&buffer_c->stream, valid_fmt); - audio_stream_set_buffer_fmt(&buffer_c->stream, + audio_stream_set_channels(&buffer->stream, copier_cfg->base.audio_fmt.channels_count); + audio_stream_set_rate(&buffer->stream, copier_cfg->base.audio_fmt.sampling_frequency); + audio_stream_set_frm_fmt(&buffer->stream, config->frame_fmt); + audio_stream_set_valid_fmt(&buffer->stream, valid_fmt); + audio_stream_set_buffer_fmt(&buffer->stream, copier_cfg->base.audio_fmt.interleaving_style); for (i = 0; i < SOF_IPC_MAX_CHANNELS; i++) - buffer_c->chmap[i] = (chan_map >> i * 4) & 0xf; + buffer->chmap[i] = (chan_map >> i * 4) & 0xf; - buffer_c->hw_params_configured = true; - buffer_release(buffer_c); + buffer->hw_params_configured = true; if (create_multi_endpoint_buffer) cd->multi_endpoint_buffer = buffer; diff --git a/src/audio/copier/copier_hifi.c b/src/audio/copier/copier_hifi.c index de6a8606aa7b..a419a4aee431 100644 --- a/src/audio/copier/copier_hifi.c +++ b/src/audio/copier/copier_hifi.c @@ -21,7 +21,7 @@ LOG_MODULE_REGISTER(copier_hifi, CONFIG_SOF_LOG_LEVEL); int apply_attenuation(struct comp_dev *dev, struct copier_data *cd, - struct comp_buffer __sparse_cache *sink, int frame) + struct comp_buffer *sink, int frame) { int i; int n; diff --git a/src/audio/copier/copier_host.c b/src/audio/copier/copier_host.c index 35456ed4dec1..30eda757bf80 100644 --- a/src/audio/copier/copier_host.c +++ b/src/audio/copier/copier_host.c @@ -246,7 +246,6 @@ void copier_host_dma_cb(struct comp_dev *dev, size_t bytes) { struct processing_module *mod = comp_get_drvdata(dev); struct copier_data *cd = module_get_private_data(mod); - struct comp_buffer __sparse_cache *sink, *source; int ret, frames; comp_dbg(dev, "copier_host_dma_cb() %p", dev); @@ -263,18 +262,13 @@ void copier_host_dma_cb(struct comp_dev *dev, size_t bytes) * playback scenario. */ if (cd->attenuation && dev->direction == SOF_IPC_STREAM_PLAYBACK) { - source = buffer_acquire(cd->hd->dma_buffer); - sink = buffer_acquire(cd->hd->local_buffer); - frames = bytes / audio_stream_frame_bytes(&source->stream); + frames = bytes / audio_stream_frame_bytes(&cd->hd->dma_buffer->stream); - ret = apply_attenuation(dev, cd, sink, frames); + ret = apply_attenuation(dev, cd, cd->hd->local_buffer, frames); if (ret < 0) comp_dbg(dev, "copier_host_dma_cb() apply attenuation failed! %d", ret); - buffer_stream_writeback(sink, bytes); - - buffer_release(source); - buffer_release(sink); + buffer_stream_writeback(cd->hd->local_buffer, bytes); } } diff --git a/src/audio/copier/copier_ipcgtw.c b/src/audio/copier/copier_ipcgtw.c index 967467f098ad..ed3350042ff7 100644 --- a/src/audio/copier/copier_ipcgtw.c +++ b/src/audio/copier/copier_ipcgtw.c @@ -37,7 +37,7 @@ static struct comp_dev *find_ipcgtw_by_node_id(union ipc4_connector_node_id node } static inline void audio_stream_copy_bytes_from_linear(const void *linear_source, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, unsigned int bytes) { const uint8_t *src = (const uint8_t *)linear_source; @@ -55,7 +55,7 @@ static inline void audio_stream_copy_bytes_from_linear(const void *linear_source } static inline -void audio_stream_copy_bytes_to_linear(const struct audio_stream __sparse_cache *source, +void audio_stream_copy_bytes_to_linear(const struct audio_stream *source, void *linear_sink, unsigned int bytes) { uint8_t *src = audio_stream_wrap(source, audio_stream_get_rptr(source)); @@ -93,7 +93,6 @@ int copier_ipcgtw_process(const struct ipc4_ipcgtw_cmd *cmd, const struct ipc4_ipc_gateway_cmd_data *in; struct comp_dev *dev; struct comp_buffer *buf; - struct comp_buffer __sparse_cache *buf_c; uint32_t data_size; struct ipc4_ipc_gateway_cmd_data_reply *out; @@ -110,15 +109,12 @@ int copier_ipcgtw_process(const struct ipc4_ipcgtw_cmd *cmd, buf = get_buffer(dev); - if (buf) { - buf_c = buffer_acquire(buf); - } else { + if (!buf) { /* NOTE: this func is called from IPC processing task and can be potentially * called before pipeline start even before buffer has been attached. In such * case do not report error but return 0 bytes available for GET_DATA and * 0 bytes free for SET_DATA. */ - buf_c = NULL; comp_warn(dev, "copier_ipcgtw_process(): no buffer found"); } @@ -126,13 +122,13 @@ int copier_ipcgtw_process(const struct ipc4_ipcgtw_cmd *cmd, switch (cmd->primary.r.cmd) { case IPC4_IPCGWCMD_GET_DATA: - if (buf_c) { + if (buf) { data_size = MIN(cmd->extension.r.data_size, SOF_IPC_MSG_MAX_SIZE - 4); - data_size = MIN(data_size, audio_stream_get_avail_bytes(&buf_c->stream)); - buffer_stream_invalidate(buf_c, data_size); - audio_stream_copy_bytes_to_linear(&buf_c->stream, out->payload, data_size); - comp_update_buffer_consume(buf_c, data_size); - out->u.size_avail = audio_stream_get_avail_bytes(&buf_c->stream); + data_size = MIN(data_size, audio_stream_get_avail_bytes(&buf->stream)); + buffer_stream_invalidate(buf, data_size); + audio_stream_copy_bytes_to_linear(&buf->stream, out->payload, data_size); + comp_update_buffer_consume(buf, data_size); + out->u.size_avail = audio_stream_get_avail_bytes(&buf->stream); *reply_payload_size = data_size + 4; } else { out->u.size_avail = 0; @@ -141,18 +137,18 @@ int copier_ipcgtw_process(const struct ipc4_ipcgtw_cmd *cmd, break; case IPC4_IPCGWCMD_SET_DATA: - if (buf_c) { + if (buf) { data_size = MIN(cmd->extension.r.data_size, - audio_stream_get_free_bytes(&buf_c->stream)); + audio_stream_get_free_bytes(&buf->stream)); dcache_invalidate_region((__sparse_force void __sparse_cache *) MAILBOX_HOSTBOX_BASE, data_size + offsetof(struct ipc4_ipc_gateway_cmd_data, payload)); - audio_stream_copy_bytes_from_linear(in->payload, &buf_c->stream, + audio_stream_copy_bytes_from_linear(in->payload, &buf->stream, data_size); - buffer_stream_writeback(buf_c, data_size); - comp_update_buffer_produce(buf_c, data_size); + buffer_stream_writeback(buf, data_size); + comp_update_buffer_produce(buf, data_size); out->u.size_consumed = data_size; *reply_payload_size = 4; } else { @@ -163,20 +159,16 @@ int copier_ipcgtw_process(const struct ipc4_ipcgtw_cmd *cmd, case IPC4_IPCGWCMD_FLUSH_DATA: *reply_payload_size = 0; - if (buf_c) - audio_stream_reset(&buf_c->stream); + if (buf) + audio_stream_reset(&buf->stream); break; default: comp_err(dev, "copier_ipcgtw_process(): unexpected cmd: %u", (unsigned int)cmd->primary.r.cmd); - if (buf_c) - buffer_release(buf_c); return -EINVAL; } - if (buf_c) - buffer_release(buf_c); return 0; } @@ -184,7 +176,6 @@ int copier_ipcgtw_params(struct ipcgtw_data *ipcgtw_data, struct comp_dev *dev, struct sof_ipc_stream_params *params) { struct comp_buffer *buf; - struct comp_buffer __sparse_cache *buf_c; int err; comp_dbg(dev, "ipcgtw_params()"); @@ -196,9 +187,7 @@ int copier_ipcgtw_params(struct ipcgtw_data *ipcgtw_data, struct comp_dev *dev, } /* resize buffer to size specified in IPC gateway config blob */ - buf_c = buffer_acquire(buf); - err = buffer_set_size(buf_c, ipcgtw_data->buf_size, 0); - buffer_release(buf_c); + err = buffer_set_size(buf, ipcgtw_data->buf_size, 0); if (err < 0) { comp_err(dev, "ipcgtw_params(): failed to resize buffer to %u bytes", @@ -214,10 +203,7 @@ void copier_ipcgtw_reset(struct comp_dev *dev) struct comp_buffer *buf = get_buffer(dev); if (buf) { - struct comp_buffer __sparse_cache *buf_c = buffer_acquire(buf); - - audio_stream_reset(&buf_c->stream); - buffer_release(buf_c); + audio_stream_reset(&buf->stream); } else { comp_warn(dev, "ipcgtw_reset(): no buffer found"); } diff --git a/src/audio/crossover/crossover.c b/src/audio/crossover/crossover.c index 029e2fcbf74c..4e89a9d05042 100644 --- a/src/audio/crossover/crossover.c +++ b/src/audio/crossover/crossover.c @@ -133,7 +133,6 @@ static int crossover_assign_sinks(struct processing_module *mod, struct sof_crossover_config *config = cd->config; struct comp_dev *dev = mod->dev; struct comp_buffer *sink; - struct comp_buffer __sparse_cache *sink_c; struct list_item *sink_list; int num_sinks = 0; int i; @@ -143,14 +142,12 @@ static int crossover_assign_sinks(struct processing_module *mod, unsigned int sink_id, state; sink = container_of(sink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); #if CONFIG_IPC_MAJOR_4 sink_id = cd->output_pin_index[j]; #else - sink_id = sink_c->pipeline_id; + sink_id = sink->pipeline_id; #endif - state = sink_c->sink->state; - buffer_release(sink_c); + state = sink->sink->state; if (state != dev->state) { j++; continue; @@ -486,7 +483,6 @@ static int crossover_check_sink_assign(struct processing_module *mod, { struct comp_dev *dev = mod->dev; struct comp_buffer *sink; - struct comp_buffer __sparse_cache *sink_c; struct list_item *sink_list; int num_assigned_sinks = 0; uint8_t assigned_sinks[SOF_CROSSOVER_MAX_STREAMS] = {0}; @@ -496,9 +492,7 @@ static int crossover_check_sink_assign(struct processing_module *mod, unsigned int pipeline_id; sink = container_of(sink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - pipeline_id = sink_c->pipeline_id; - buffer_release(sink_c); + pipeline_id = sink->pipeline_id; i = crossover_get_stream_index(mod, config, pipeline_id); if (i < 0) { @@ -623,7 +617,7 @@ static int crossover_process_audio_stream(struct processing_module *mod, bool enabled_buffers[PLATFORM_MAX_STREAMS] = { false }; struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct audio_stream __sparse_cache *source = input_buffers[0].data; + struct audio_stream *source = input_buffers[0].data; uint32_t num_sinks; uint32_t num_assigned_sinks = 0; /* The frames count to process from module adapter applies for source buffer and @@ -691,7 +685,6 @@ static int crossover_process_audio_stream(struct processing_module *mod, static void crossover_params(struct processing_module *mod) { struct sof_ipc_stream_params *params = mod->stream_params; - struct comp_buffer __sparse_cache *sink_c, *source_c; struct comp_buffer *sinkb, *sourceb; struct list_item *sink_list; struct comp_dev *dev = mod->dev; @@ -702,15 +695,11 @@ static void crossover_params(struct processing_module *mod) component_set_nearest_period_frames(dev, params->rate); sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(sourceb); - ipc4_update_buffer_format(source_c, &mod->priv.cfg.base_cfg.audio_fmt); - buffer_release(source_c); + ipc4_update_buffer_format(sourceb, &mod->priv.cfg.base_cfg.audio_fmt); list_for_item(sink_list, &dev->bsink_list) { sinkb = container_of(sink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sinkb); - ipc4_update_buffer_format(sink_c, &mod->priv.cfg.base_cfg.audio_fmt); - buffer_release(sink_c); + ipc4_update_buffer_format(sinkb, &mod->priv.cfg.base_cfg.audio_fmt); } } #endif @@ -721,13 +710,12 @@ static void crossover_params(struct processing_module *mod) * \return Error code. */ static int crossover_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; struct comp_buffer *source, *sink; - struct comp_buffer __sparse_cache *source_c, *sink_c; struct list_item *sink_list; int channels; int ret = 0; @@ -741,27 +729,23 @@ static int crossover_prepare(struct processing_module *mod, /* Crossover has a variable number of sinks */ mod->max_sinks = SOF_CROSSOVER_MAX_STREAMS; source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(source); /* Get source data format */ - cd->source_format = audio_stream_get_frm_fmt(&source_c->stream); - channels = audio_stream_get_channels(&source_c->stream); - audio_stream_init_alignment_constants(1, 1, &source_c->stream); - buffer_release(source_c); + cd->source_format = audio_stream_get_frm_fmt(&source->stream); + channels = audio_stream_get_channels(&source->stream); + audio_stream_init_alignment_constants(1, 1, &source->stream); /* Validate frame format and buffer size of sinks */ list_for_item(sink_list, &dev->bsink_list) { sink = container_of(sink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - if (cd->source_format == audio_stream_get_frm_fmt(&sink_c->stream)) { - audio_stream_init_alignment_constants(1, 1, &sink_c->stream); + if (cd->source_format == audio_stream_get_frm_fmt(&sink->stream)) { + audio_stream_init_alignment_constants(1, 1, &sink->stream); } else { comp_err(dev, "crossover_prepare(): Source fmt %d and sink fmt %d are different.", - cd->source_format, audio_stream_get_frm_fmt(&sink_c->stream)); + cd->source_format, audio_stream_get_frm_fmt(&sink->stream)); ret = -EINVAL; } - buffer_release(sink_c); if (ret < 0) return ret; } @@ -832,8 +816,8 @@ static int crossover_reset(struct processing_module *mod) } /** \brief Crossover Filter component definition. */ -static struct module_interface crossover_interface = { - .init = crossover_init, +static const struct module_interface crossover_interface = { + .init = crossover_init, .prepare = crossover_prepare, .process_audio_stream = crossover_process_audio_stream, .set_configuration = crossover_set_config, diff --git a/src/audio/crossover/crossover_generic.c b/src/audio/crossover/crossover_generic.c index ad8b6b930ea9..0823ce85920f 100644 --- a/src/audio/crossover/crossover_generic.c +++ b/src/audio/crossover/crossover_generic.c @@ -93,8 +93,8 @@ static void crossover_s16_default_pass(struct comp_data *cd, int32_t num_sinks, uint32_t frames) { - const struct audio_stream __sparse_cache *sink_stream; - const struct audio_stream __sparse_cache *source_stream = bsource->data; + const struct audio_stream *sink_stream; + const struct audio_stream *source_stream = bsource->data; int16_t *x; int32_t *y; int i, j; @@ -121,8 +121,8 @@ static void crossover_s32_default_pass(struct comp_data *cd, int32_t num_sinks, uint32_t frames) { - const struct audio_stream __sparse_cache *sink_stream; - const struct audio_stream __sparse_cache *source_stream = bsource->data; + const struct audio_stream *sink_stream; + const struct audio_stream *source_stream = bsource->data; int32_t *x, *y; int i, j; int n = audio_stream_get_channels(source_stream) * frames; @@ -149,8 +149,8 @@ static void crossover_s16_default(struct comp_data *cd, uint32_t frames) { struct crossover_state *state; - const struct audio_stream __sparse_cache *source_stream = bsource->data; - struct audio_stream __sparse_cache *sink_stream; + const struct audio_stream *source_stream = bsource->data; + struct audio_stream *sink_stream; int16_t *x, *y; int ch, i, j; int idx; @@ -187,8 +187,8 @@ static void crossover_s24_default(struct comp_data *cd, uint32_t frames) { struct crossover_state *state; - const struct audio_stream __sparse_cache *source_stream = bsource->data; - struct audio_stream __sparse_cache *sink_stream; + const struct audio_stream *source_stream = bsource->data; + struct audio_stream *sink_stream; int32_t *x, *y; int ch, i, j; int idx; @@ -225,8 +225,8 @@ static void crossover_s32_default(struct comp_data *cd, uint32_t frames) { struct crossover_state *state; - const struct audio_stream __sparse_cache *source_stream = bsource->data; - struct audio_stream __sparse_cache *sink_stream; + const struct audio_stream *source_stream = bsource->data; + struct audio_stream *sink_stream; int32_t *x, *y; int ch, i, j; int idx; diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 884f2b00f2fc..ccbe72f4062b 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -97,7 +97,6 @@ static void dai_dma_cb(void *arg, enum notify_id type, void *data) struct comp_dev *dev = arg; struct dai_data *dd = comp_get_drvdata(dev); uint32_t bytes = next->elem.size; - struct comp_buffer __sparse_cache *local_buf, *dma_buf; int ret; comp_dbg(dev, "dai_dma_cb()"); @@ -113,37 +112,32 @@ static void dai_dma_cb(void *arg, enum notify_id type, void *data) next->status = DMA_CB_STATUS_END; } - dma_buf = buffer_acquire(dd->dma_buffer); - /* is our pipeline handling an XRUN ? */ if (dd->xrun) { /* make sure we only playback silence during an XRUN */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) /* fill buffer with silence */ - buffer_zero(dma_buf); - buffer_release(dma_buf); + buffer_zero(dd->dma_buffer); return; } - local_buf = buffer_acquire(dd->local_buffer); - if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { - ret = dma_buffer_copy_to(local_buf, dma_buf, + ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer, dd->process, bytes); } else { - ret = dma_buffer_copy_from(dma_buf, local_buf, + ret = dma_buffer_copy_from(dd->dma_buffer, dd->local_buffer, dd->process, bytes); } /* assert dma_buffer_copy succeed */ if (ret < 0) { - struct comp_buffer __sparse_cache *source_c, *sink_c; + struct comp_buffer *source_c, *sink_c; source_c = dev->direction == SOF_IPC_STREAM_PLAYBACK ? - local_buf : dma_buf; + dd->local_buffer : dd->dma_buffer; sink_c = dev->direction == SOF_IPC_STREAM_PLAYBACK ? - dma_buf : local_buf; + dd->dma_buffer : dd->local_buffer; comp_err(dev, "dai_dma_cb() dma buffer copy failed, dir %d bytes %d avail %d free %d", dev->direction, bytes, audio_stream_get_avail_samples(&source_c->stream) * @@ -154,9 +148,6 @@ static void dai_dma_cb(void *arg, enum notify_id type, void *data) /* update host position (in bytes offset) for drivers */ dd->total_data_processed += bytes; } - - buffer_release(local_buf); - buffer_release(dma_buf); } int dai_common_new(struct dai_data *dd, struct comp_dev *dev, const struct ipc_config_dai *dai) @@ -357,23 +348,18 @@ static int dai_playback_params(struct comp_dev *dev, uint32_t period_bytes, { struct dai_data *dd = comp_get_drvdata(dev); struct dma_sg_config *config = &dd->config; - struct comp_buffer __sparse_cache *dma_buf = buffer_acquire(dd->dma_buffer), - *local_buf = buffer_acquire(dd->local_buffer); - uint32_t local_fmt = audio_stream_get_frm_fmt(&local_buf->stream); - uint32_t dma_fmt = audio_stream_get_frm_fmt(&dma_buf->stream); + uint32_t local_fmt = audio_stream_get_frm_fmt(&dd->local_buffer->stream); + uint32_t dma_fmt = audio_stream_get_frm_fmt(&dd->dma_buffer->stream); uint32_t fifo; int err = 0; /* set processing function */ dd->process = pcm_get_conversion_function(local_fmt, dma_fmt); - buffer_release(local_buf); - if (!dd->process) { comp_err(dev, "dai_playback_params(): converter function NULL: local fmt %d dma fmt %d\n", local_fmt, dma_fmt); - err = -EINVAL; - goto out; + return -EINVAL; } /* set up DMA configuration */ @@ -401,16 +387,13 @@ static int dai_playback_params(struct comp_dev *dev, uint32_t period_bytes, config->direction, period_count, period_bytes, - (uintptr_t)(audio_stream_get_addr(&dma_buf->stream)), + (uintptr_t)(audio_stream_get_addr(&dd->dma_buffer->stream)), fifo); if (err < 0) comp_err(dev, "dai_playback_params(): dma_sg_alloc() for period_count %d period_bytes %d failed with err = %d", period_count, period_bytes, err); } -out: - buffer_release(dma_buf); - return err; } @@ -419,23 +402,18 @@ static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, { struct dai_data *dd = comp_get_drvdata(dev); struct dma_sg_config *config = &dd->config; - struct comp_buffer __sparse_cache *dma_buf = buffer_acquire(dd->dma_buffer), - *local_buf = buffer_acquire(dd->local_buffer); - uint32_t local_fmt = audio_stream_get_frm_fmt(&local_buf->stream); - uint32_t dma_fmt = audio_stream_get_frm_fmt(&dma_buf->stream); + uint32_t local_fmt = audio_stream_get_frm_fmt(&dd->local_buffer->stream); + uint32_t dma_fmt = audio_stream_get_frm_fmt(&dd->dma_buffer->stream); uint32_t fifo; int err = 0; /* set processing function */ dd->process = pcm_get_conversion_function(dma_fmt, local_fmt); - buffer_release(local_buf); - if (!dd->process) { comp_err(dev, "dai_capture_params(): converter function NULL: local fmt %d dma fmt %d\n", local_fmt, dma_fmt); - err = -EINVAL; - goto out; + return -EINVAL; } /* set up DMA configuration */ @@ -474,16 +452,13 @@ static int dai_capture_params(struct comp_dev *dev, uint32_t period_bytes, config->direction, period_count, period_bytes, - (uintptr_t)(audio_stream_get_addr(&dma_buf->stream)), + (uintptr_t)(audio_stream_get_addr(&dd->dma_buffer->stream)), fifo); if (err < 0) comp_err(dev, "dai_capture_params(): dma_sg_alloc() for period_count %d period_bytes %d failed with err = %d", period_count, period_bytes, err); } -out: - buffer_release(dma_buf); - return err; } @@ -491,7 +466,6 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, struct sof_ipc_stream_params *params) { struct sof_ipc_stream_params hw_params = *params; - struct comp_buffer __sparse_cache *buffer_c; uint32_t frame_size; uint32_t period_count; uint32_t period_bytes; @@ -565,13 +539,9 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, return -EINVAL; } - buffer_c = buffer_acquire(dd->local_buffer); - /* calculate frame size */ frame_size = get_frame_bytes(dev->ipc_config.frame_fmt, - audio_stream_get_channels(&buffer_c->stream)); - - buffer_release(buffer_c); + audio_stream_get_channels(&dd->local_buffer->stream)); /* calculate period size */ period_bytes = dev->frames * frame_size; @@ -589,9 +559,7 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, /* alloc DMA buffer or change its size if exists */ if (dd->dma_buffer) { - buffer_c = buffer_acquire(dd->dma_buffer); - err = buffer_set_size(buffer_c, buffer_size, addr_align); - buffer_release(buffer_c); + err = buffer_set_size(dd->dma_buffer, buffer_size, addr_align); if (err < 0) { comp_err(dev, "dai_params(): buffer_set_size() failed, buffer_size = %u", @@ -600,7 +568,7 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, } } else { dd->dma_buffer = buffer_alloc(buffer_size, SOF_MEM_CAPS_DMA, 0, - addr_align); + addr_align, false); if (!dd->dma_buffer) { comp_err(dev, "dai_params(): failed to alloc dma buffer"); return -ENOMEM; @@ -613,10 +581,8 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, * frame_fmt's (using pcm converter). */ hw_params.frame_fmt = dev->ipc_config.frame_fmt; - buffer_c = buffer_acquire(dd->dma_buffer); - buffer_set_params(buffer_c, &hw_params, + buffer_set_params(dd->dma_buffer, &hw_params, BUFFER_UPDATE_FORCE); - buffer_release(buffer_c); } return dev->direction == SOF_IPC_STREAM_PLAYBACK ? @@ -685,7 +651,6 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev) int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev) { - struct comp_buffer __sparse_cache *buffer_c; int ret; dd->total_data_processed = 0; @@ -703,9 +668,7 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev) } /* clear dma buffer to avoid pop noise */ - buffer_c = buffer_acquire(dd->dma_buffer); - buffer_zero(buffer_c); - buffer_release(buffer_c); + buffer_zero(dd->dma_buffer); /* dma reconfig not required if XRUN handling */ if (dd->xrun) { @@ -815,11 +778,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, * this is only supported at capture mode. */ if (dev->direction == SOF_IPC_STREAM_CAPTURE) { - struct comp_buffer __sparse_cache *buffer_c = - buffer_acquire(dd->dma_buffer); - - buffer_zero(buffer_c); - buffer_release(buffer_c); + buffer_zero(dd->dma_buffer); } /* only start the DAI if we are not XRUN handling */ @@ -947,17 +906,14 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd) static void dai_report_xrun(struct comp_dev *dev, uint32_t bytes) { struct dai_data *dd = comp_get_drvdata(dev); - struct comp_buffer __sparse_cache *buf_c = buffer_acquire(dd->local_buffer); if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { comp_err(dev, "dai_report_xrun(): underrun due to no data available"); - comp_underrun(dev, buf_c, bytes); + comp_underrun(dev, dd->local_buffer, bytes); } else { comp_err(dev, "dai_report_xrun(): overrun due to no space available"); - comp_overrun(dev, buf_c, bytes); + comp_overrun(dev, dd->local_buffer, bytes); } - - buffer_release(buf_c); } /* copy and process stream data from source to sink buffers */ @@ -965,7 +921,6 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun { uint32_t dma_fmt; uint32_t sampling; - struct comp_buffer __sparse_cache *buf_c; uint32_t avail_bytes = 0; uint32_t free_bytes = 0; uint32_t copy_bytes = 0; @@ -981,23 +936,17 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun return ret; } - buf_c = buffer_acquire(dd->dma_buffer); - - dma_fmt = audio_stream_get_frm_fmt(&buf_c->stream); + dma_fmt = audio_stream_get_frm_fmt(&dd->dma_buffer->stream); sampling = get_sample_bytes(dma_fmt); - buffer_release(buf_c); - - buf_c = buffer_acquire(dd->local_buffer); - /* calculate minimum size to copy */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { - src_samples = audio_stream_get_avail_samples(&buf_c->stream); + src_samples = audio_stream_get_avail_samples(&dd->local_buffer->stream); sink_samples = free_bytes / sampling; samples = MIN(src_samples, sink_samples); } else { src_samples = avail_bytes / sampling; - sink_samples = audio_stream_get_free_samples(&buf_c->stream); + sink_samples = audio_stream_get_free_samples(&dd->local_buffer->stream); samples = MIN(src_samples, sink_samples); } @@ -1010,9 +959,7 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun comp_dbg(dev, "dai_common_copy(), dir: %d copy_bytes= 0x%x, frames= %d", dev->direction, copy_bytes, - samples / audio_stream_get_channels(&buf_c->stream)); - - buffer_release(buf_c); + samples / audio_stream_get_channels(&dd->local_buffer->stream)); /* Check possibility of glitch occurrence */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK && diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index bcbfd91dd2ad..6a0694519235 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -226,7 +226,6 @@ static enum dma_cb_status dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, pcm_converter_func *converter) { - struct comp_buffer __sparse_cache *local_buf, *dma_buf; enum dma_cb_status dma_status = DMA_CB_STATUS_RELOAD; int ret; @@ -241,33 +240,29 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, dma_status = DMA_CB_STATUS_END; } - dma_buf = buffer_acquire(dd->dma_buffer); - /* is our pipeline handling an XRUN ? */ if (dd->xrun) { /* make sure we only playback silence during an XRUN */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) /* fill buffer with silence */ - buffer_zero(dma_buf); - buffer_release(dma_buf); + buffer_zero(dd->dma_buffer); return dma_status; } - local_buf = buffer_acquire(dd->local_buffer); - if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { - ret = dma_buffer_copy_to(local_buf, dma_buf, + ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer, dd->process, bytes); } else { struct list_item *sink_list; - audio_stream_invalidate(&dma_buf->stream, bytes); + audio_stream_invalidate(&dd->dma_buffer->stream, bytes); /* * The PCM converter functions used during DMA buffer copy can never fail, * so no need to check the return value of dma_buffer_copy_from_no_consume(). */ - ret = dma_buffer_copy_from_no_consume(dma_buf, local_buf, dd->process, bytes); + ret = dma_buffer_copy_from_no_consume(dd->dma_buffer, dd->local_buffer, + dd->process, bytes); #if CONFIG_IPC_MAJOR_4 /* Skip in case of endpoint DAI devices created by the copier */ if (converter) { @@ -276,7 +271,6 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, * function */ list_for_item(sink_list, &dev->bsink_list) { - struct comp_buffer __sparse_cache *sink_c; struct comp_dev *sink_dev; struct comp_buffer *sink; int j; @@ -287,43 +281,41 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, if (sink == dd->local_buffer) continue; - sink_c = buffer_acquire(sink); - sink_dev = sink_c->sink; + sink_dev = sink->sink; - j = IPC4_SINK_QUEUE_ID(sink_c->id); + j = IPC4_SINK_QUEUE_ID(sink->id); if (j >= IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT) { comp_err(dev, "Sink queue ID: %d >= max output pin count: %d\n", j, IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT); ret = -EINVAL; - goto err; + continue; } if (!converter[j]) { comp_err(dev, "No PCM converter for sink queue %d\n", j); ret = -EINVAL; - goto err; + continue; } if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE) - ret = dma_buffer_copy_from_no_consume(dma_buf, sink_c, - converter[j], bytes); -err: - buffer_release(sink_c); + ret = dma_buffer_copy_from_no_consume(dd->dma_buffer, + sink, converter[j], + bytes); } } #endif - audio_stream_consume(&dma_buf->stream, bytes); + audio_stream_consume(&dd->dma_buffer->stream, bytes); } /* assert dma_buffer_copy succeed */ if (ret < 0) { - struct comp_buffer __sparse_cache *source_c, *sink_c; + struct comp_buffer *source_c, *sink_c; source_c = dev->direction == SOF_IPC_STREAM_PLAYBACK ? - local_buf : dma_buf; + dd->local_buffer : dd->dma_buffer; sink_c = dev->direction == SOF_IPC_STREAM_PLAYBACK ? - dma_buf : local_buf; + dd->dma_buffer : dd->local_buffer; comp_err(dev, "dai_dma_cb() dma buffer copy failed, dir %d bytes %d avail %d free %d", dev->direction, bytes, audio_stream_get_avail_samples(&source_c->stream) * @@ -335,9 +327,6 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, dd->total_data_processed += bytes; } - buffer_release(local_buf); - buffer_release(dma_buf); - return dma_status; } @@ -346,7 +335,6 @@ static enum dma_cb_status dai_dma_multi_endpoint_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t frames, struct comp_buffer *multi_endpoint_buffer) { - struct comp_buffer __sparse_cache *multi_buf_c, *dma_buf; enum dma_cb_status dma_status = DMA_CB_STATUS_RELOAD; uint32_t i, bytes; @@ -361,48 +349,41 @@ dai_dma_multi_endpoint_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t fr dma_status = DMA_CB_STATUS_END; } - dma_buf = buffer_acquire(dd->dma_buffer); - /* is our pipeline handling an XRUN ? */ if (dd->xrun) { /* make sure we only playback silence during an XRUN */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) /* fill buffer with silence */ - buffer_zero(dma_buf); - buffer_release(dma_buf); + buffer_zero(dd->dma_buffer); return dma_status; } - multi_buf_c = buffer_acquire(multi_endpoint_buffer); - - bytes = frames * audio_stream_frame_bytes(&dma_buf->stream); + bytes = frames * audio_stream_frame_bytes(&dd->dma_buffer->stream); if (dev->direction == SOF_IPC_STREAM_CAPTURE) - audio_stream_invalidate(&dma_buf->stream, bytes); + audio_stream_invalidate(&dd->dma_buffer->stream, bytes); /* copy all channels one by one */ - for (i = 0; i < audio_stream_get_channels(&dma_buf->stream); i++) { - uint32_t multi_buf_channel = dma_buf->chmap[i]; + for (i = 0; i < audio_stream_get_channels(&dd->dma_buffer->stream); i++) { + uint32_t multi_buf_channel = dd->dma_buffer->chmap[i]; if (dev->direction == SOF_IPC_STREAM_PLAYBACK) - dd->process(&multi_buf_c->stream, multi_buf_channel, - &dma_buf->stream, i, frames); + dd->process(&multi_endpoint_buffer->stream, multi_buf_channel, + &dd->dma_buffer->stream, i, frames); else - dd->process(&dma_buf->stream, i, &multi_buf_c->stream, + dd->process(&dd->dma_buffer->stream, i, &multi_endpoint_buffer->stream, multi_buf_channel, frames); } if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { - audio_stream_writeback(&dma_buf->stream, bytes); - audio_stream_produce(&dma_buf->stream, bytes); + audio_stream_writeback(&dd->dma_buffer->stream, bytes); + audio_stream_produce(&dd->dma_buffer->stream, bytes); } else { - audio_stream_consume(&dma_buf->stream, bytes); + audio_stream_consume(&dd->dma_buffer->stream, bytes); } /* update host position (in bytes offset) for drivers */ dd->total_data_processed += bytes; - buffer_release(multi_buf_c); - buffer_release(dma_buf); return dma_status; } @@ -592,23 +573,18 @@ static int dai_playback_params(struct dai_data *dd, struct comp_dev *dev, uint32 struct dma_config *dma_cfg; struct dma_block_config *dma_block_cfg; struct dma_block_config *prev = NULL; - struct comp_buffer __sparse_cache *dma_buf = buffer_acquire(dd->dma_buffer), - *local_buf = buffer_acquire(dd->local_buffer); - uint32_t local_fmt = audio_stream_get_frm_fmt(&local_buf->stream); - uint32_t dma_fmt = audio_stream_get_frm_fmt(&dma_buf->stream); + uint32_t local_fmt = audio_stream_get_frm_fmt(&dd->local_buffer->stream); + uint32_t dma_fmt = audio_stream_get_frm_fmt(&dd->dma_buffer->stream); uint32_t fifo, max_block_count, buf_size; int i, err = 0; - buffer_release(local_buf); - /* set processing function */ dd->process = pcm_get_conversion_function(local_fmt, dma_fmt); if (!dd->process) { comp_err(dev, "dai_playback_params(): converter function NULL: local fmt %d dma fmt %d\n", local_fmt, dma_fmt); - err = -EINVAL; - goto out; + return -EINVAL; } /* set up DMA configuration */ @@ -635,12 +611,12 @@ static int dai_playback_params(struct dai_data *dd, struct comp_dev *dev, uint32 &max_block_count); if (err < 0) { comp_err(dev, "dai_playback_params(): could not get dma attr max block count, err = %d", err); - goto out; + return err; } if (!max_block_count) { comp_err(dev, "dai_playback_params(): invalid max-block-count of zero"); - goto out; + return err; } if (max_block_count < period_count) { @@ -661,12 +637,12 @@ static int dai_playback_params(struct dai_data *dd, struct comp_dev *dev, uint32 config->direction, period_count, period_bytes, - (uintptr_t)audio_stream_get_addr(&dma_buf->stream), + (uintptr_t)audio_stream_get_addr(&dd->dma_buffer->stream), fifo); if (err < 0) { comp_err(dev, "dai_playback_params(): dma_sg_alloc() for period_count %d period_bytes %d failed with err = %d", period_count, period_bytes, err); - goto out; + return err; } } @@ -721,8 +697,6 @@ static int dai_playback_params(struct dai_data *dd, struct comp_dev *dev, uint32 free: if (err < 0) dma_sg_free(&config->elem_array); -out: - buffer_release(dma_buf); return err; } @@ -734,23 +708,18 @@ static int dai_capture_params(struct dai_data *dd, struct comp_dev *dev, uint32_ struct dma_config *dma_cfg; struct dma_block_config *dma_block_cfg; struct dma_block_config *prev = NULL; - struct comp_buffer __sparse_cache *dma_buf = buffer_acquire(dd->dma_buffer), - *local_buf = buffer_acquire(dd->local_buffer); - uint32_t local_fmt = audio_stream_get_frm_fmt(&local_buf->stream); - uint32_t dma_fmt = audio_stream_get_frm_fmt(&dma_buf->stream); + uint32_t local_fmt = audio_stream_get_frm_fmt(&dd->local_buffer->stream); + uint32_t dma_fmt = audio_stream_get_frm_fmt(&dd->dma_buffer->stream); uint32_t fifo, max_block_count, buf_size; int i, err = 0; - buffer_release(local_buf); - /* set processing function */ dd->process = pcm_get_conversion_function(dma_fmt, local_fmt); if (!dd->process) { comp_err(dev, "dai_capture_params(): converter function NULL: local fmt %d dma fmt %d\n", local_fmt, dma_fmt); - err = -EINVAL; - goto out; + return -EINVAL; } /* set up DMA configuration */ @@ -789,12 +758,12 @@ static int dai_capture_params(struct dai_data *dd, struct comp_dev *dev, uint32_ &max_block_count); if (err < 0) { comp_err(dev, "dai_capture_params(): could not get dma attr max block count, err = %d", err); - goto out; + return err; } if (!max_block_count) { comp_err(dev, "dai_capture_params(): invalid max-block-count of zero"); - goto out; + return err; } if (max_block_count < period_count) { @@ -815,12 +784,12 @@ static int dai_capture_params(struct dai_data *dd, struct comp_dev *dev, uint32_ config->direction, period_count, period_bytes, - (uintptr_t)audio_stream_get_addr(&dma_buf->stream), + (uintptr_t)audio_stream_get_addr(&dd->dma_buffer->stream), fifo); if (err < 0) { comp_err(dev, "dai_capture_params(): dma_sg_alloc() for period_count %d period_bytes %d failed with err = %d", period_count, period_bytes, err); - goto out; + return err; } } @@ -875,8 +844,6 @@ static int dai_capture_params(struct dai_data *dd, struct comp_dev *dev, uint32_ free: if (err < 0) dma_sg_free(&config->elem_array); -out: - buffer_release(dma_buf); return err; } @@ -885,7 +852,6 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, struct sof_ipc_stream_params *params) { struct sof_ipc_stream_params hw_params = *params; - struct comp_buffer __sparse_cache *buffer_c; uint32_t frame_size; uint32_t period_count; uint32_t period_bytes; @@ -967,9 +933,7 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, /* alloc DMA buffer or change its size if exists */ if (dd->dma_buffer) { - buffer_c = buffer_acquire(dd->dma_buffer); - err = buffer_set_size(buffer_c, buffer_size, addr_align); - buffer_release(buffer_c); + err = buffer_set_size(dd->dma_buffer, buffer_size, addr_align); if (err < 0) { comp_err(dev, "dai_common_params(): buffer_set_size() failed, buffer_size = %u", @@ -977,8 +941,9 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, return err; } } else { + /* allocate not shared buffer */ dd->dma_buffer = buffer_alloc(buffer_size, SOF_MEM_CAPS_DMA, 0, - addr_align); + addr_align, false); if (!dd->dma_buffer) { comp_err(dev, "dai_common_params(): failed to alloc dma buffer"); return -ENOMEM; @@ -991,11 +956,10 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, * frame_fmt's (using pcm converter). */ hw_params.frame_fmt = dev->ipc_config.frame_fmt; - buffer_c = buffer_acquire(dd->dma_buffer); - buffer_set_params(buffer_c, &hw_params, + buffer_set_params(dd->dma_buffer, &hw_params, BUFFER_UPDATE_FORCE); + dd->sampling = get_sample_bytes(hw_params.frame_fmt); - buffer_release(buffer_c); } dd->fast_mode = dd->ipc_config.feature_mask & BIT(IPC4_COPIER_FAST_MODE); @@ -1063,7 +1027,6 @@ int dai_common_config_prepare(struct dai_data *dd, struct comp_dev *dev) int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev) { - struct comp_buffer __sparse_cache *buffer_c; int ret; dd->total_data_processed = 0; @@ -1081,9 +1044,7 @@ int dai_common_prepare(struct dai_data *dd, struct comp_dev *dev) } /* clear dma buffer to avoid pop noise */ - buffer_c = buffer_acquire(dd->dma_buffer); - buffer_zero(buffer_c); - buffer_release(buffer_c); + buffer_zero(dd->dma_buffer); /* dma reconfig not required if XRUN handling */ if (dd->xrun) { @@ -1192,11 +1153,7 @@ static int dai_comp_trigger_internal(struct dai_data *dd, struct comp_dev *dev, * this is only supported at capture mode. */ if (dev->direction == SOF_IPC_STREAM_CAPTURE) { - struct comp_buffer __sparse_cache *buffer_c = - buffer_acquire(dd->dma_buffer); - - buffer_zero(buffer_c); - buffer_release(buffer_c); + buffer_zero(dd->dma_buffer); } /* only start the DAI if we are not XRUN handling */ @@ -1338,17 +1295,13 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd) /* report xrun occurrence */ static void dai_report_xrun(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes) { - struct comp_buffer __sparse_cache *buf_c = buffer_acquire(dd->local_buffer); - if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { comp_err(dev, "dai_report_xrun(): underrun due to no data available"); - comp_underrun(dev, buf_c, bytes); + comp_underrun(dev, dd->local_buffer, bytes); } else { comp_err(dev, "dai_report_xrun(): overrun due to no space available"); - comp_overrun(dev, buf_c, bytes); + comp_overrun(dev, dd->local_buffer, bytes); } - - buffer_release(buf_c); } /* process and copy stream data from multiple DMA source buffers to sink buffer */ @@ -1356,7 +1309,6 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, struct comp_buffer *multi_endpoint_buffer, int num_endpoints) { - struct comp_buffer __sparse_cache *buf_c; uint32_t avail_bytes = UINT32_MAX; uint32_t free_bytes = UINT32_MAX; uint32_t frames; @@ -1368,9 +1320,7 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, if (!num_endpoints || !dd || !multi_endpoint_buffer) return 0; - buf_c = buffer_acquire(dd[0]->dma_buffer); - frame_bytes = audio_stream_frame_bytes(&buf_c->stream); - buffer_release(buf_c); + frame_bytes = audio_stream_frame_bytes(&dd[0]->dma_buffer->stream); direction = dev->direction; @@ -1400,16 +1350,14 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, free_bytes = MIN(free_bytes, stat.free); } - buf_c = buffer_acquire(multi_endpoint_buffer); /* calculate minimum size to copy */ if (direction == SOF_IPC_STREAM_PLAYBACK) { - src_frames = audio_stream_get_avail_frames(&buf_c->stream); + src_frames = audio_stream_get_avail_frames(&multi_endpoint_buffer->stream); sink_frames = free_bytes / frame_bytes; } else { src_frames = avail_bytes / frame_bytes; - sink_frames = audio_stream_get_free_frames(&buf_c->stream); + sink_frames = audio_stream_get_free_frames(&multi_endpoint_buffer->stream); } - buffer_release(buf_c); frames = MIN(src_frames, sink_frames); @@ -1429,10 +1377,8 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, } if (direction == SOF_IPC_STREAM_PLAYBACK) { - buf_c = buffer_acquire(multi_endpoint_buffer); - frame_bytes = audio_stream_frame_bytes(&buf_c->stream); - buffer_stream_invalidate(buf_c, frames * frame_bytes); - buffer_release(buf_c); + frame_bytes = audio_stream_frame_bytes(&multi_endpoint_buffer->stream); + buffer_stream_invalidate(multi_endpoint_buffer, frames * frame_bytes); } for (i = 0; i < num_endpoints; i++) { @@ -1448,9 +1394,7 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, if (status == DMA_CB_STATUS_END) dma_stop(dd[i]->chan->dma->z_dev, dd[i]->chan->index); - buf_c = buffer_acquire(dd[i]->dma_buffer); - copy_bytes = frames * audio_stream_frame_bytes(&buf_c->stream); - buffer_release(buf_c); + copy_bytes = frames * audio_stream_frame_bytes(&dd[i]->dma_buffer->stream); ret = dma_reload(dd[i]->chan->dma->z_dev, dd[i]->chan->index, 0, 0, copy_bytes); if (ret < 0) { dai_report_xrun(dd[i], dev, copy_bytes); @@ -1460,28 +1404,22 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, dai_dma_position_update(dd[i], dev); } - buf_c = buffer_acquire(multi_endpoint_buffer); - frame_bytes = audio_stream_frame_bytes(&buf_c->stream); + frame_bytes = audio_stream_frame_bytes(&multi_endpoint_buffer->stream); if (direction == SOF_IPC_STREAM_PLAYBACK) { - comp_update_buffer_consume(buf_c, frames * frame_bytes); + comp_update_buffer_consume(multi_endpoint_buffer, frames * frame_bytes); } else { - buffer_stream_writeback(buf_c, frames * frame_bytes); - comp_update_buffer_produce(buf_c, frames * frame_bytes); + buffer_stream_writeback(multi_endpoint_buffer, frames * frame_bytes); + comp_update_buffer_produce(multi_endpoint_buffer, frames * frame_bytes); } - buffer_release(buf_c); return 0; } static void set_new_local_buffer(struct dai_data *dd, struct comp_dev *dev) { - struct comp_buffer __sparse_cache *dma_buf = buffer_acquire(dd->dma_buffer); - struct comp_buffer __sparse_cache *local_buf; - uint32_t dma_fmt = audio_stream_get_frm_fmt(&dma_buf->stream); + uint32_t dma_fmt = audio_stream_get_frm_fmt(&dd->dma_buffer->stream); uint32_t local_fmt; - buffer_release(dma_buf); - if (dev->direction == SOF_IPC_STREAM_PLAYBACK) dd->local_buffer = list_first_item(&dev->bsource_list, struct comp_buffer, @@ -1491,9 +1429,7 @@ static void set_new_local_buffer(struct dai_data *dd, struct comp_dev *dev) struct comp_buffer, source_list); - local_buf = buffer_acquire(dd->local_buffer); - local_fmt = audio_stream_get_frm_fmt(&local_buf->stream); - buffer_release(local_buf); + local_fmt = audio_stream_get_frm_fmt(&dd->local_buffer->stream); dd->process = pcm_get_conversion_function(local_fmt, dma_fmt); @@ -1508,7 +1444,6 @@ static void set_new_local_buffer(struct dai_data *dd, struct comp_dev *dev) int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_func *converter) { uint32_t sampling = dd->sampling; - struct comp_buffer __sparse_cache *buf_c; struct dma_status stat; uint32_t avail_bytes; uint32_t free_bytes; @@ -1551,11 +1486,9 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun /* calculate minimum size to copy */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { - buf_c = buffer_acquire(dd->local_buffer); - src_samples = audio_stream_get_avail_samples(&buf_c->stream); + src_samples = audio_stream_get_avail_samples(&dd->local_buffer->stream); sink_samples = free_bytes / sampling; samples = MIN(src_samples, sink_samples); - buffer_release(buf_c); } else { struct list_item *sink_list; @@ -1566,10 +1499,8 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun * a DAI copier and it is chosen as the dd->local buffer */ if (!converter) { - buf_c = buffer_acquire(dd->local_buffer); - sink_samples = audio_stream_get_free_samples(&buf_c->stream); + sink_samples = audio_stream_get_free_samples(&dd->local_buffer->stream); samples = MIN(samples, sink_samples); - buffer_release(buf_c); } else { /* * In the case of capture DAI's with multiple sink buffers, compute the @@ -1581,15 +1512,13 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun struct comp_buffer *sink; sink = container_of(sink_list, struct comp_buffer, source_list); - buf_c = buffer_acquire(sink); - sink_dev = buf_c->sink; + sink_dev = sink->sink; if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE) { sink_samples = - audio_stream_get_free_samples(&buf_c->stream); + audio_stream_get_free_samples(&sink->stream); samples = MIN(samples, sink_samples); } - buffer_release(buf_c); } } @@ -1668,7 +1597,7 @@ static int dai_copy(struct comp_dev *dev) int dai_common_ts_config_op(struct dai_data *dd, struct comp_dev *dev) { struct ipc_config_dai *dai = &dd->ipc_config; - struct dai_ts_cfg cfg; + struct dai_ts_cfg *cfg = &dd->ts_config; comp_dbg(dev, "dai_ts_config()"); if (!dd->chan) { @@ -1678,26 +1607,26 @@ int dai_common_ts_config_op(struct dai_data *dd, struct comp_dev *dev) switch (dai->type) { case SOF_DAI_INTEL_SSP: - cfg.type = DAI_INTEL_SSP; + cfg->type = DAI_INTEL_SSP; break; case SOF_DAI_INTEL_ALH: - cfg.type = DAI_INTEL_ALH; + cfg->type = DAI_INTEL_ALH; break; case SOF_DAI_INTEL_DMIC: - cfg.type = DAI_INTEL_DMIC; + cfg->type = DAI_INTEL_DMIC; break; default: comp_err(dev, "dai_ts_config(), not supported dai type"); return -EINVAL; } - cfg.direction = dai->direction; - cfg.index = dd->dai->index; - cfg.dma_id = dd->dma->plat_data.id; - cfg.dma_chan_index = dd->chan->index; - cfg.dma_chan_count = dd->dma->plat_data.channels; + cfg->direction = dai->direction; + cfg->index = dd->dai->index; + cfg->dma_id = dd->dma->plat_data.id; + cfg->dma_chan_index = dd->chan->index; + cfg->dma_chan_count = dd->dma->plat_data.channels; - return dai_ts_config(dd->dai->dev, &cfg); + return dai_ts_config(dd->dai->dev, cfg); } static int dai_ts_config_op(struct comp_dev *dev) @@ -1709,9 +1638,7 @@ static int dai_ts_config_op(struct comp_dev *dev) int dai_common_ts_start(struct dai_data *dd, struct comp_dev *dev) { - struct dai_ts_cfg cfg; - - return dai_ts_start(dd->dai->dev, &cfg); + return dai_ts_start(dd->dai->dev, (struct dai_ts_cfg *)&dd->ts_config); } static int dai_ts_start_op(struct comp_dev *dev) @@ -1722,16 +1649,14 @@ static int dai_ts_start_op(struct comp_dev *dev) return dai_common_ts_start(dd, dev); } -int dai_common_ts_get(struct dai_data *dd, struct comp_dev *dev, struct timestamp_data *tsd) +int dai_common_ts_get(struct dai_data *dd, struct comp_dev *dev, struct dai_ts_data *tsd) { - struct dai_ts_data tsdata; - struct dai_ts_cfg cfg; + struct dai_ts_cfg *cfg = (struct dai_ts_cfg *)&dd->ts_config; - /* TODO: convert to timestamp_data */ - return dai_ts_get(dd->dai->dev, &cfg, &tsdata); + return dai_ts_get(dd->dai->dev, cfg, tsd); } -static int dai_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd) +static int dai_ts_get_op(struct comp_dev *dev, struct dai_ts_data *tsd) { struct dai_data *dd = comp_get_drvdata(dev); @@ -1742,9 +1667,7 @@ static int dai_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd) int dai_common_ts_stop(struct dai_data *dd, struct comp_dev *dev) { - struct dai_ts_cfg cfg; - - return dai_ts_stop(dd->dai->dev, &cfg); + return dai_ts_stop(dd->dai->dev, (struct dai_ts_cfg *)&dd->ts_config); } static int dai_ts_stop_op(struct comp_dev *dev) @@ -1791,7 +1714,6 @@ static uint64_t dai_get_processed_data(struct comp_dev *dev, uint32_t stream_no, #ifdef CONFIG_IPC_MAJOR_4 int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, void *data) { - struct comp_buffer __sparse_cache *local_buf_c; struct ipc4_module_bind_unbind *bu; int buf_id; @@ -1799,12 +1721,10 @@ int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, void *data) buf_id = IPC4_COMP_ID(bu->extension.r.src_queue, bu->extension.r.dst_queue); if (dd && dd->local_buffer) { - local_buf_c = buffer_acquire(dd->local_buffer); - if (local_buf_c->id == buf_id) { + if (dd->local_buffer->id == buf_id) { comp_dbg(dev, "dai_zephyr_unbind: local_buffer %x unbound", buf_id); dd->local_buffer = NULL; } - buffer_release(local_buf_c); } return 0; diff --git a/src/audio/dcblock/dcblock.c b/src/audio/dcblock/dcblock.c index 956181149900..8e52820341ba 100644 --- a/src/audio/dcblock/dcblock.c +++ b/src/audio/dcblock/dcblock.c @@ -194,8 +194,8 @@ static int dcblock_process(struct processing_module *mod, int num_output_buffers) { struct comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = input_buffers[0].data; - struct audio_stream __sparse_cache *sink = output_buffers[0].data; + struct audio_stream *source = input_buffers[0].data; + struct audio_stream *sink = output_buffers[0].data; uint32_t frames = input_buffers[0].size; comp_dbg(mod->dev, "dcblock_process()"); @@ -207,8 +207,8 @@ static int dcblock_process(struct processing_module *mod, } /* init and calculate the aligned setting for available frames and free frames retrieve*/ -static inline void dcblock_set_frame_alignment(struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink) +static inline void dcblock_set_frame_alignment(struct audio_stream *source, + struct audio_stream *sink) { const uint32_t byte_align = 1; const uint32_t frame_align_req = 1; @@ -221,7 +221,6 @@ static inline void dcblock_set_frame_alignment(struct audio_stream __sparse_cach static void dcblock_params(struct processing_module *mod) { struct sof_ipc_stream_params *params = mod->stream_params; - struct comp_buffer __sparse_cache *sink_c, *source_c; struct comp_buffer *sinkb, *sourceb; struct comp_dev *dev = mod->dev; @@ -231,14 +230,10 @@ static void dcblock_params(struct processing_module *mod) component_set_nearest_period_frames(dev, params->rate); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sinkb); - ipc4_update_buffer_format(sink_c, &mod->priv.cfg.base_cfg.audio_fmt); - buffer_release(sink_c); + ipc4_update_buffer_format(sinkb, &mod->priv.cfg.base_cfg.audio_fmt); sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(sourceb); - ipc4_update_buffer_format(source_c, &mod->priv.cfg.base_cfg.audio_fmt); - buffer_release(source_c); + ipc4_update_buffer_format(sourceb, &mod->priv.cfg.base_cfg.audio_fmt); } #endif /* CONFIG_IPC_MAJOR_4 */ @@ -248,12 +243,11 @@ static void dcblock_params(struct processing_module *mod) * \return Error code. */ static int dcblock_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_data *cd = module_get_private_data(mod); struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; struct comp_dev *dev = mod->dev; comp_info(dev, "dcblock_prepare()"); @@ -266,18 +260,13 @@ static int dcblock_prepare(struct processing_module *mod, sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - /* get source data format */ - cd->source_format = audio_stream_get_frm_fmt(&source_c->stream); + cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); /* get sink data format and period bytes */ - cd->sink_format = audio_stream_get_frm_fmt(&sink_c->stream); + cd->sink_format = audio_stream_get_frm_fmt(&sinkb->stream); - dcblock_set_frame_alignment(&source_c->stream, &sink_c->stream); - buffer_release(sink_c); - buffer_release(source_c); + dcblock_set_frame_alignment(&sourceb->stream, &sinkb->stream); dcblock_init_state(cd); cd->dcblock_func = dcblock_find_func(cd->source_format); @@ -316,8 +305,8 @@ static int dcblock_reset(struct processing_module *mod) return 0; } -static struct module_interface dcblock_interface = { - .init = dcblock_init, +static const struct module_interface dcblock_interface = { + .init = dcblock_init, .prepare = dcblock_prepare, .process_audio_stream = dcblock_process, .set_configuration = dcblock_set_config, diff --git a/src/audio/dcblock/dcblock_generic.c b/src/audio/dcblock/dcblock_generic.c index 3fb6b476d5e6..459d51993f09 100644 --- a/src/audio/dcblock/dcblock_generic.c +++ b/src/audio/dcblock/dcblock_generic.c @@ -36,8 +36,8 @@ static int32_t dcblock_generic(struct dcblock_state *state, #if CONFIG_FORMAT_S16LE static void dcblock_s16_default(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames) { struct dcblock_state *state; @@ -76,8 +76,8 @@ static void dcblock_s16_default(struct comp_data *cd, #if CONFIG_FORMAT_S24LE static void dcblock_s24_default(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames) { struct dcblock_state *state; @@ -116,8 +116,8 @@ static void dcblock_s24_default(struct comp_data *cd, #if CONFIG_FORMAT_S32LE static void dcblock_s32_default(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames) { struct dcblock_state *state; diff --git a/src/audio/dcblock/dcblock_hifi3.c b/src/audio/dcblock/dcblock_hifi3.c index e8ef80032bb6..30d8aa4d32a8 100644 --- a/src/audio/dcblock/dcblock_hifi3.c +++ b/src/audio/dcblock/dcblock_hifi3.c @@ -29,7 +29,7 @@ static inline ae_int32x2 dcblock_cal(ae_int32x2 R, ae_int32x2 state_x, ae_int32 } /* Setup circular for component source */ -static inline void dcblock_set_circular(const struct audio_stream __sparse_cache *source) +static inline void dcblock_set_circular(const struct audio_stream *source) { /* Set source as circular buffer 0 */ AE_SETCBEGIN0(audio_stream_get_addr(source)); @@ -38,8 +38,8 @@ static inline void dcblock_set_circular(const struct audio_stream __sparse_cache #if CONFIG_FORMAT_S16LE static void dcblock_s16_default(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames) { ae_int16 *src = audio_stream_get_rptr(source); @@ -85,8 +85,8 @@ static void dcblock_s16_default(struct comp_data *cd, #if CONFIG_FORMAT_S24LE static void dcblock_s24_default(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames) { ae_int32 *src = audio_stream_get_rptr(source); @@ -132,8 +132,8 @@ static void dcblock_s24_default(struct comp_data *cd, #if CONFIG_FORMAT_S32LE static void dcblock_s32_default(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames) { ae_int32 *src = audio_stream_get_rptr(source); diff --git a/src/audio/dcblock/dcblock_hifi4.c b/src/audio/dcblock/dcblock_hifi4.c index b537b3dce7b0..98d8edf6345e 100644 --- a/src/audio/dcblock/dcblock_hifi4.c +++ b/src/audio/dcblock/dcblock_hifi4.c @@ -29,8 +29,8 @@ static inline ae_int32x2 dcblock_cal(ae_int32x2 R, ae_int32x2 state_x, ae_int32 } /* Setup circular for component sink and source */ -static inline void dcblock_set_circular(const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink) +static inline void dcblock_set_circular(const struct audio_stream *source, + const struct audio_stream *sink) { /* Set source as circular buffer 0 */ AE_SETCBEGIN0(audio_stream_get_addr(source)); @@ -43,8 +43,8 @@ static inline void dcblock_set_circular(const struct audio_stream __sparse_cache #if CONFIG_FORMAT_S16LE static void dcblock_s16_default(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames) { ae_int16 *in; @@ -80,8 +80,8 @@ static void dcblock_s16_default(struct comp_data *cd, #if CONFIG_FORMAT_S24LE static void dcblock_s24_default(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames) { ae_int32 *in; @@ -118,8 +118,8 @@ static void dcblock_s24_default(struct comp_data *cd, #if CONFIG_FORMAT_S32LE static void dcblock_s32_default(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames) { ae_int32 *in; diff --git a/src/audio/dp_queue.c b/src/audio/dp_queue.c new file mode 100644 index 000000000000..8001594a27bc --- /dev/null +++ b/src/audio/dp_queue.c @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. +// + +#include +#include +#include + +#include + +#include +#include + +LOG_MODULE_REGISTER(dp_queue, CONFIG_SOF_LOG_LEVEL); + +/* 393608d8-4188-11ee-be56-0242ac120002 */ +DECLARE_SOF_RT_UUID("dp_queue", dp_queue_uuid, 0x393608d8, 0x4188, 0x11ee, + 0xbe, 0x56, 0x02, 0x42, 0xac, 0x12, 0x20, 0x02); +DECLARE_TR_CTX(dp_queue_tr, SOF_UUID(dp_queue_uuid), LOG_LEVEL_INFO); + +static inline uint8_t __sparse_cache *dp_queue_buffer_end(struct dp_queue *dp_queue) +{ + return dp_queue->_data_buffer + dp_queue->data_buffer_size; +} + +static inline struct dp_queue *dp_queue_from_sink(struct sof_sink *sink) +{ + return container_of(sink, struct dp_queue, _sink_api); +} + +static inline struct dp_queue *dp_queue_from_source(struct sof_source *source) +{ + return container_of(source, struct dp_queue, _source_api); +} + +static inline void dp_queue_invalidate_shared(struct dp_queue *dp_queue, + void __sparse_cache *ptr, size_t size) +{ + /* no cache required in case of not shared queue */ + if (!dp_queue_is_shared(dp_queue)) + return; + + /* wrap-around? */ + if ((uintptr_t)ptr + size > (uintptr_t)dp_queue_buffer_end(dp_queue)) { + /* writeback till the end of circular buffer */ + dcache_invalidate_region + (ptr, (uintptr_t)dp_queue_buffer_end(dp_queue) - (uintptr_t)ptr); + size -= (uintptr_t)dp_queue_buffer_end(dp_queue) - (uintptr_t)ptr; + ptr = dp_queue->_data_buffer; + } + /* invalidate rest of data */ + dcache_invalidate_region(ptr, size); +} + +static inline void dp_queue_writeback_shared(struct dp_queue *dp_queue, + void __sparse_cache *ptr, size_t size) +{ + /* no cache required in case of not shared queue */ + if (!dp_queue_is_shared(dp_queue)) + return; + + /* wrap-around? */ + if ((uintptr_t)ptr + size > (uintptr_t)dp_queue_buffer_end(dp_queue)) { + /* writeback till the end of circular buffer */ + dcache_writeback_region + (ptr, (uintptr_t)dp_queue_buffer_end(dp_queue) - (uintptr_t)ptr); + size -= (uintptr_t)dp_queue_buffer_end(dp_queue) - (uintptr_t)ptr; + ptr = dp_queue->_data_buffer; + } + /* writeback rest of data */ + dcache_writeback_region(ptr, size); +} + +static inline +uint8_t __sparse_cache *dp_queue_get_pointer(struct dp_queue *dp_queue, size_t offset) +{ + /* check if offset is not in "double area" + * lines below do a quicker version of offset %= dp_queue->data_buffer_size; + */ + if (offset >= dp_queue->data_buffer_size) + offset -= dp_queue->data_buffer_size; + return dp_queue->_data_buffer + offset; +} + +static inline +size_t dp_queue_inc_offset(struct dp_queue *dp_queue, size_t offset, size_t inc) +{ + assert(inc <= dp_queue->data_buffer_size); + offset += inc; + /* wrap around ? 2*size because of "double area" */ + if (offset >= 2 * dp_queue->data_buffer_size) + offset -= 2 * dp_queue->data_buffer_size; + return offset; +} + +static inline +size_t _dp_queue_get_data_available(struct dp_queue *dp_queue) +{ + int32_t avail_data = dp_queue->_write_offset - dp_queue->_read_offset; + /* wrap around ? 2*size because of "double area" */ + if (avail_data < 0) + avail_data = 2 * dp_queue->data_buffer_size + avail_data; + + return avail_data; +} + +static size_t dp_queue_get_data_available(struct sof_source *source) +{ + struct dp_queue *dp_queue = dp_queue_from_source(source); + + CORE_CHECK_STRUCT(dp_queue); + return _dp_queue_get_data_available(dp_queue); +} + +static size_t dp_queue_get_free_size(struct sof_sink *sink) +{ + struct dp_queue *dp_queue = dp_queue_from_sink(sink); + + CORE_CHECK_STRUCT(dp_queue); + return dp_queue->data_buffer_size - _dp_queue_get_data_available(dp_queue); +} + +static int dp_queue_get_buffer(struct sof_sink *sink, size_t req_size, + void **data_ptr, void **buffer_start, size_t *buffer_size) +{ + struct dp_queue *dp_queue = dp_queue_from_sink(sink); + + CORE_CHECK_STRUCT(dp_queue); + if (req_size > dp_queue_get_free_size(sink)) + return -ENODATA; + + /* note, __sparse_force is to be removed once sink/src use __sparse_cache for data ptrs */ + *data_ptr = (__sparse_force void *)dp_queue_get_pointer(dp_queue, dp_queue->_write_offset); + *buffer_start = (__sparse_force void *)dp_queue->_data_buffer; + *buffer_size = dp_queue->data_buffer_size; + + /* no need to invalidate cache - buffer is to be written only */ + return 0; +} + +static int dp_queue_commit_buffer(struct sof_sink *sink, size_t commit_size) +{ + struct dp_queue *dp_queue = dp_queue_from_sink(sink); + + CORE_CHECK_STRUCT(dp_queue); + if (commit_size) { + dp_queue_writeback_shared(dp_queue, + dp_queue_get_pointer(dp_queue, dp_queue->_write_offset), + commit_size); + + /* move write pointer */ + dp_queue->_write_offset = + dp_queue_inc_offset(dp_queue, dp_queue->_write_offset, commit_size); + } + + return 0; +} + +static int dp_queue_get_data(struct sof_source *source, size_t req_size, + void const **data_ptr, void const **buffer_start, size_t *buffer_size) +{ + struct dp_queue *dp_queue = dp_queue_from_source(source); + __sparse_cache void *data_ptr_c; + + CORE_CHECK_STRUCT(dp_queue); + if (req_size > dp_queue_get_data_available(source)) + return -ENODATA; + + data_ptr_c = dp_queue_get_pointer(dp_queue, dp_queue->_read_offset); + + /* clean cache in provided data range */ + dp_queue_invalidate_shared(dp_queue, data_ptr_c, req_size); + + *buffer_start = (__sparse_force void *)dp_queue->_data_buffer; + *buffer_size = dp_queue->data_buffer_size; + *data_ptr = (__sparse_force void *)data_ptr_c; + + return 0; +} + +static int dp_queue_release_data(struct sof_source *source, size_t free_size) +{ + struct dp_queue *dp_queue = dp_queue_from_source(source); + + CORE_CHECK_STRUCT(dp_queue); + if (free_size) { + /* data consumed, free buffer space, no need for any special cache operations */ + dp_queue->_read_offset = + dp_queue_inc_offset(dp_queue, dp_queue->_read_offset, free_size); + } + + return 0; +} + +static int dp_queue_set_ipc_params(struct dp_queue *dp_queue, + struct sof_ipc_stream_params *params, + bool force_update) +{ + CORE_CHECK_STRUCT(dp_queue); + if (dp_queue->_hw_params_configured && !force_update) + return 0; + + dp_queue->audio_stream_params.frame_fmt = params->frame_fmt; + dp_queue->audio_stream_params.rate = params->rate; + dp_queue->audio_stream_params.channels = params->channels; + dp_queue->audio_stream_params.buffer_fmt = params->buffer_fmt; + + dp_queue->_hw_params_configured = true; + + return 0; +} + +static int dp_queue_set_ipc_params_source(struct sof_source *source, + struct sof_ipc_stream_params *params, + bool force_update) +{ + struct dp_queue *dp_queue = dp_queue_from_source(source); + + CORE_CHECK_STRUCT(dp_queue); + return dp_queue_set_ipc_params(dp_queue, params, force_update); +} + +static int dp_queue_set_ipc_params_sink(struct sof_sink *sink, + struct sof_ipc_stream_params *params, + bool force_update) +{ + struct dp_queue *dp_queue = dp_queue_from_sink(sink); + + CORE_CHECK_STRUCT(dp_queue); + return dp_queue_set_ipc_params(dp_queue, params, force_update); +} + +static const struct source_ops dp_queue_source_ops = { + .get_data_available = dp_queue_get_data_available, + .get_data = dp_queue_get_data, + .release_data = dp_queue_release_data, + .audio_set_ipc_params = dp_queue_set_ipc_params_source, +}; + +static const struct sink_ops dp_queue_sink_ops = { + .get_free_size = dp_queue_get_free_size, + .get_buffer = dp_queue_get_buffer, + .commit_buffer = dp_queue_commit_buffer, + .audio_set_ipc_params = dp_queue_set_ipc_params_sink, +}; + +struct dp_queue *dp_queue_create(size_t min_available, size_t min_free_space, uint32_t flags) +{ + struct dp_queue *dp_queue; + + /* allocate DP structure */ + if (flags & DP_QUEUE_MODE_SHARED) + dp_queue = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, + sizeof(*dp_queue)); + else + dp_queue = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*dp_queue)); + if (!dp_queue) + return NULL; + + dp_queue->_flags = flags; + + CORE_CHECK_STRUCT_INIT(dp_queue, flags & DP_QUEUE_MODE_SHARED); + + /* initiate structures */ + source_init(dp_queue_get_source(dp_queue), &dp_queue_source_ops, + &dp_queue->audio_stream_params); + sink_init(dp_queue_get_sink(dp_queue), &dp_queue_sink_ops, + &dp_queue->audio_stream_params); + + list_init(&dp_queue->list); + + /* set obs/ibs in sink/source interfaces */ + sink_set_min_free_space(&dp_queue->_sink_api, min_free_space); + source_set_min_available(&dp_queue->_source_api, min_available); + + uint32_t max_ibs_obs = MAX(min_available, min_free_space); + + /* calculate required buffer size */ + dp_queue->data_buffer_size = 2 * max_ibs_obs; + + /* allocate data buffer - always in cached memory alias */ + dp_queue->data_buffer_size = ALIGN_UP(dp_queue->data_buffer_size, PLATFORM_DCACHE_ALIGN); + dp_queue->_data_buffer = (__sparse_force __sparse_cache void *) + rballoc_align(0, 0, dp_queue->data_buffer_size, PLATFORM_DCACHE_ALIGN); + if (!dp_queue->_data_buffer) + goto err; + + tr_info(&dp_queue_tr, "DpQueue created, shared: %u min_available: %u min_free_space %u, size %u", + dp_queue_is_shared(dp_queue), min_available, min_free_space, + dp_queue->data_buffer_size); + + /* return a pointer to allocated structure */ + return dp_queue; +err: + tr_err(&dp_queue_tr, "DpQueue creation failure"); + rfree(dp_queue); + return NULL; +} diff --git a/src/audio/drc/drc.c b/src/audio/drc/drc.c index a435e347a608..c69b3a742ea6 100644 --- a/src/audio/drc/drc.c +++ b/src/audio/drc/drc.c @@ -227,8 +227,8 @@ static int drc_get_config(struct processing_module *mod, return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); } -static void drc_set_alignment(struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink) +static void drc_set_alignment(struct audio_stream *source, + struct audio_stream *sink) { /* Currently no optimizations those would use wider loads and stores */ audio_stream_init_alignment_constants(1, 1, source); @@ -243,8 +243,8 @@ static int drc_process(struct processing_module *mod, { struct drc_comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct audio_stream __sparse_cache *source = input_buffers[0].data; - struct audio_stream __sparse_cache *sink = output_buffers[0].data; + struct audio_stream *source = input_buffers[0].data; + struct audio_stream *sink = output_buffers[0].data; int frames = input_buffers[0].size; int ret; @@ -272,7 +272,6 @@ static int drc_process(struct processing_module *mod, static void drc_params(struct processing_module *mod) { struct sof_ipc_stream_params *params = mod->stream_params; - struct comp_buffer __sparse_cache *sink_c, *source_c; struct comp_buffer *sinkb, *sourceb; struct comp_dev *dev = mod->dev; @@ -282,24 +281,19 @@ static void drc_params(struct processing_module *mod) component_set_nearest_period_frames(dev, params->rate); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sinkb); - ipc4_update_buffer_format(sink_c, &mod->priv.cfg.base_cfg.audio_fmt); - buffer_release(sink_c); + ipc4_update_buffer_format(sinkb, &mod->priv.cfg.base_cfg.audio_fmt); sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(sourceb); - ipc4_update_buffer_format(source_c, &mod->priv.cfg.base_cfg.audio_fmt); - buffer_release(source_c); + ipc4_update_buffer_format(sourceb, &mod->priv.cfg.base_cfg.audio_fmt); } #endif /* CONFIG_IPC_MAJOR_4 */ static int drc_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct drc_comp_data *cd = module_get_private_data(mod); struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; struct comp_dev *dev = mod->dev; int channels; int rate; @@ -314,16 +308,12 @@ static int drc_prepare(struct processing_module *mod, /* DRC component will only ever have 1 source and 1 sink buffer */ sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - drc_set_alignment(&source_c->stream, &sink_c->stream); + drc_set_alignment(&sourceb->stream, &sinkb->stream); /* get source data format */ - cd->source_format = audio_stream_get_frm_fmt(&source_c->stream); - channels = audio_stream_get_channels(&sink_c->stream); - rate = audio_stream_get_rate(&sink_c->stream); - buffer_release(sink_c); - buffer_release(source_c); + cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); + channels = audio_stream_get_channels(&sinkb->stream); + rate = audio_stream_get_rate(&sinkb->stream); /* Initialize DRC */ comp_info(dev, "drc_prepare(), source_format=%d", cd->source_format); @@ -360,8 +350,8 @@ static int drc_reset(struct processing_module *mod) return 0; } -static struct module_interface drc_interface = { - .init = drc_init, +static const struct module_interface drc_interface = { + .init = drc_init, .prepare = drc_prepare, .process_audio_stream = drc_process, .set_configuration = drc_set_config, diff --git a/src/audio/drc/drc_generic.c b/src/audio/drc/drc_generic.c index fb7978c54cdc..472431a0e408 100644 --- a/src/audio/drc/drc_generic.c +++ b/src/audio/drc/drc_generic.c @@ -466,8 +466,8 @@ static void drc_process_one_division(struct drc_state *state, } void drc_default_pass(struct processing_module *mod, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, uint32_t frames) + const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames) { audio_stream_copy(source, 0, sink, 0, frames * audio_stream_get_channels(source)); } @@ -479,8 +479,8 @@ static inline void drc_pre_delay_index_inc(int *idx, int increment) #if CONFIG_FORMAT_S16LE static void drc_delay_input_sample_s16(struct drc_state *state, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, int16_t **x, int16_t **y, int samples) { int16_t *x1; @@ -528,8 +528,8 @@ static void drc_delay_input_sample_s16(struct drc_state *state, } static void drc_s16_default(struct processing_module *mod, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames) { int16_t *x = audio_stream_get_rptr(source); @@ -574,8 +574,8 @@ static void drc_s16_default(struct processing_module *mod, #if CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE static void drc_delay_input_sample_s32(struct drc_state *state, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, int32_t **x, int32_t **y, int samples) { int32_t *x1; @@ -625,8 +625,8 @@ static void drc_delay_input_sample_s32(struct drc_state *state, #if CONFIG_FORMAT_S24LE static void drc_delay_input_sample_s24(struct drc_state *state, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, int32_t **x, int32_t **y, int samples) { int32_t *x1; @@ -674,8 +674,8 @@ static void drc_delay_input_sample_s24(struct drc_state *state, } static void drc_s24_default(struct processing_module *mod, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames) { int32_t *x = audio_stream_get_rptr(source); @@ -722,8 +722,8 @@ static void drc_s24_default(struct processing_module *mod, #if CONFIG_FORMAT_S32LE static void drc_s32_default(struct processing_module *mod, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames) { int32_t *x = audio_stream_get_rptr(source); diff --git a/src/audio/eq_fir/eq_fir.c b/src/audio/eq_fir/eq_fir.c index 5fad4db4babf..baca41e054a4 100644 --- a/src/audio/eq_fir/eq_fir.c +++ b/src/audio/eq_fir/eq_fir.c @@ -174,7 +174,6 @@ static int eq_fir_params(struct processing_module *mod) struct sof_ipc_stream_params comp_params; struct comp_dev *dev = mod->dev; struct comp_buffer *sinkb; - struct comp_buffer __sparse_cache *sink_c; enum sof_ipc_frame valid_fmt, frame_fmt; int i, ret; @@ -197,9 +196,7 @@ static int eq_fir_params(struct processing_module *mod) component_set_nearest_period_frames(dev, comp_params.rate); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sinkb); - ret = buffer_set_params(sink_c, &comp_params, true); - buffer_release(sink_c); + ret = buffer_set_params(sinkb, &comp_params, true); return ret; } #endif /* CONFIG_IPC_MAJOR_4 */ @@ -213,8 +210,8 @@ static void eq_fir_passthrough(struct fir_state_32x16 fir[], struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; audio_stream_copy(source, 0, sink, 0, frames * audio_stream_get_channels(source)); } @@ -512,7 +509,7 @@ static int eq_fir_process(struct processing_module *mod, int num_output_buffers) { struct comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = input_buffers[0].data; + struct audio_stream *source = input_buffers[0].data; uint32_t frame_count = input_buffers[0].size; int ret; @@ -554,8 +551,8 @@ static int eq_fir_process(struct processing_module *mod, return 0; } -static void eq_fir_set_alignment(struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink) +static void eq_fir_set_alignment(struct audio_stream *source, + struct audio_stream *sink) { const uint32_t byte_align = 1; const uint32_t frame_align_req = 2; /* Process multiples of 2 frames */ @@ -565,12 +562,11 @@ static void eq_fir_set_alignment(struct audio_stream __sparse_cache *source, } static int eq_fir_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_data *cd = module_get_private_data(mod); struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; struct comp_dev *dev = mod->dev; int channels; enum sof_ipc_frame frame_fmt; @@ -589,13 +585,9 @@ static int eq_fir_prepare(struct processing_module *mod, /* EQ component will only ever have 1 source and 1 sink buffer. */ sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - eq_fir_set_alignment(&source_c->stream, &sink_c->stream); - channels = audio_stream_get_channels(&sink_c->stream); - frame_fmt = audio_stream_get_frm_fmt(&source_c->stream); - buffer_release(sink_c); - buffer_release(source_c); + eq_fir_set_alignment(&sourceb->stream, &sinkb->stream); + channels = audio_stream_get_channels(&sinkb->stream); + frame_fmt = audio_stream_get_frm_fmt(&sourceb->stream); cd->eq_fir_func = eq_fir_passthrough; cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); @@ -636,7 +628,7 @@ static int eq_fir_reset(struct processing_module *mod) return 0; } -static struct module_interface eq_fir_interface = { +static const struct module_interface eq_fir_interface = { .init = eq_fir_init, .free = eq_fir_free, .set_configuration = eq_fir_set_config, diff --git a/src/audio/eq_fir/eq_fir_generic.c b/src/audio/eq_fir/eq_fir_generic.c index ff763d325864..7edea7b21057 100644 --- a/src/audio/eq_fir/eq_fir_generic.c +++ b/src/audio/eq_fir/eq_fir_generic.c @@ -23,8 +23,8 @@ LOG_MODULE_DECLARE(eq_fir, CONFIG_SOF_LOG_LEVEL); void eq_fir_s16(struct fir_state_32x16 fir[], struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct fir_state_32x16 *filter; int32_t z; int16_t *x0, *y0; @@ -61,8 +61,8 @@ void eq_fir_s16(struct fir_state_32x16 fir[], struct input_stream_buffer *bsourc void eq_fir_s24(struct fir_state_32x16 fir[], struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct fir_state_32x16 *filter; int32_t z; int32_t *x0, *y0; @@ -99,8 +99,8 @@ void eq_fir_s24(struct fir_state_32x16 fir[], struct input_stream_buffer *bsourc void eq_fir_s32(struct fir_state_32x16 fir[], struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct fir_state_32x16 *filter; int32_t *x0, *y0; int32_t *x = audio_stream_get_rptr(source); diff --git a/src/audio/eq_fir/eq_fir_hifi2ep.c b/src/audio/eq_fir/eq_fir_hifi2ep.c index 29d12587ab1f..fc5ce500b9de 100644 --- a/src/audio/eq_fir/eq_fir_hifi2ep.c +++ b/src/audio/eq_fir/eq_fir_hifi2ep.c @@ -28,8 +28,8 @@ LOG_MODULE_DECLARE(eq_fir, CONFIG_SOF_LOG_LEVEL); void eq_fir_2x_s32(struct fir_state_32x16 fir[], struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct fir_state_32x16 *f; int32_t *src = audio_stream_get_rptr(source); int32_t *snk = audio_stream_get_wptr(sink); @@ -72,8 +72,8 @@ void eq_fir_2x_s32(struct fir_state_32x16 fir[], struct input_stream_buffer *bso void eq_fir_2x_s24(struct fir_state_32x16 fir[], struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct fir_state_32x16 *f; int32_t *src = audio_stream_get_rptr(source); int32_t *snk = audio_stream_get_wptr(sink); @@ -120,8 +120,8 @@ void eq_fir_2x_s24(struct fir_state_32x16 fir[], struct input_stream_buffer *bso void eq_fir_2x_s16(struct fir_state_32x16 fir[], struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct fir_state_32x16 *f; int16_t *src = audio_stream_get_rptr(source); int16_t *snk = audio_stream_get_wptr(sink); diff --git a/src/audio/eq_fir/eq_fir_hifi3.c b/src/audio/eq_fir/eq_fir_hifi3.c index b9b5f3b1ec63..00ce836741f5 100644 --- a/src/audio/eq_fir/eq_fir_hifi3.c +++ b/src/audio/eq_fir/eq_fir_hifi3.c @@ -27,8 +27,8 @@ LOG_MODULE_DECLARE(eq_fir, CONFIG_SOF_LOG_LEVEL); void eq_fir_2x_s32(struct fir_state_32x16 fir[], struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct fir_state_32x16 *f; ae_int32x2 d0 = 0; ae_int32x2 d1 = 0; @@ -84,8 +84,8 @@ void eq_fir_2x_s32(struct fir_state_32x16 fir[], struct input_stream_buffer *bso void eq_fir_2x_s24(struct fir_state_32x16 fir[], struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct fir_state_32x16 *f; ae_int32x2 d0 = 0; ae_int32x2 d1 = 0; @@ -156,8 +156,8 @@ void eq_fir_2x_s24(struct fir_state_32x16 fir[], struct input_stream_buffer *bso void eq_fir_2x_s16(struct fir_state_32x16 fir[], struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct fir_state_32x16 *f; ae_int16x4 d0 = AE_ZERO16(); ae_int16x4 d1 = AE_ZERO16(); diff --git a/src/audio/eq_iir/eq_iir.c b/src/audio/eq_iir/eq_iir.c index 1ff8ed6879e6..76f187ce04f0 100644 --- a/src/audio/eq_iir/eq_iir.c +++ b/src/audio/eq_iir/eq_iir.c @@ -64,8 +64,8 @@ static void eq_iir_s16_default(struct processing_module *mod, struct input_strea struct output_stream_buffer *bsink, uint32_t frames) { struct comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct iir_state_df1 *filter; int16_t *x0; int16_t *y0; @@ -112,8 +112,8 @@ static void eq_iir_s24_default(struct processing_module *mod, struct input_strea struct output_stream_buffer *bsink, uint32_t frames) { struct comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct iir_state_df1 *filter; int32_t *x0; int32_t *y0; @@ -160,8 +160,8 @@ static void eq_iir_s32_default(struct processing_module *mod, struct input_strea struct output_stream_buffer *bsink, uint32_t frames) { struct comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct iir_state_df1 *filter; int32_t *x0; int32_t *y0; @@ -209,8 +209,8 @@ static void eq_iir_s32_16_default(struct processing_module *mod, struct output_stream_buffer *bsink, uint32_t frames) { struct comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct iir_state_df1 *filter; int32_t *x0; int16_t *y0; @@ -257,8 +257,8 @@ static void eq_iir_s32_24_default(struct processing_module *mod, struct output_stream_buffer *bsink, uint32_t frames) { struct comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct iir_state_df1 *filter; int32_t *x0; int32_t *y0; @@ -303,8 +303,8 @@ static void eq_iir_s32_24_default(struct processing_module *mod, static void eq_iir_pass(struct processing_module *mod, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, uint32_t frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; audio_stream_copy(source, 0, sink, 0, frames * audio_stream_get_channels(source)); } @@ -314,8 +314,8 @@ static void eq_iir_pass(struct processing_module *mod, struct input_stream_buffe static void eq_iir_s32_s16_pass(struct processing_module *mod, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, uint32_t frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *x = audio_stream_get_rptr(source); int16_t *y = audio_stream_get_wptr(sink); int nmax; @@ -344,8 +344,8 @@ static void eq_iir_s32_s16_pass(struct processing_module *mod, struct input_stre static void eq_iir_s32_s24_pass(struct processing_module *mod, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, uint32_t frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *x = audio_stream_get_rptr(source); int32_t *y = audio_stream_get_wptr(sink); int nmax; @@ -694,7 +694,6 @@ static int eq_iir_verify_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) { struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; uint32_t buffer_flag; int ret; @@ -705,8 +704,6 @@ static int eq_iir_verify_params(struct comp_dev *dev, sink_list); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); /* we check whether we can support frame_fmt conversion (whether we have * such conversion function) due to source and sink buffer frame_fmt's. @@ -714,14 +711,11 @@ static int eq_iir_verify_params(struct comp_dev *dev, * pcm frame_fmt and will not make any conversion (sink and source * frame_fmt will be equal). */ - buffer_flag = eq_iir_find_func(audio_stream_get_frm_fmt(&source_c->stream), - audio_stream_get_frm_fmt(&sink_c->stream), fm_configured, + buffer_flag = eq_iir_find_func(audio_stream_get_frm_fmt(&sourceb->stream), + audio_stream_get_frm_fmt(&sinkb->stream), fm_configured, ARRAY_SIZE(fm_configured)) ? BUFF_PARAMS_FRAME_FMT : 0; - buffer_release(sink_c); - buffer_release(source_c); - ret = comp_verify_params(dev, buffer_flag, params); if (ret < 0) { comp_err(dev, "eq_iir_verify_params(): comp_verify_params() failed."); @@ -794,8 +788,8 @@ static int eq_iir_process(struct processing_module *mod, struct output_stream_buffer *output_buffers, int num_output_buffers) { struct comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = input_buffers[0].data; - struct audio_stream __sparse_cache *sink = output_buffers[0].data; + struct audio_stream *source = input_buffers[0].data; + struct audio_stream *sink = output_buffers[0].data; uint32_t frame_count = input_buffers[0].size; int ret; @@ -821,8 +815,8 @@ static int eq_iir_process(struct processing_module *mod, * \param[in,out] source Structure pointer of source. * \param[in,out] sink Structure pointer of sink. */ -static void eq_iir_set_alignment(struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink) +static void eq_iir_set_alignment(struct audio_stream *source, + struct audio_stream *sink) { const uint32_t byte_align = 8; const uint32_t frame_align_req = 2; @@ -838,7 +832,6 @@ static int eq_iir_params(struct processing_module *mod) struct sof_ipc_stream_params comp_params; struct comp_dev *dev = mod->dev; struct comp_buffer *sinkb; - struct comp_buffer __sparse_cache *sink_c; enum sof_ipc_frame valid_fmt, frame_fmt; int i, ret; @@ -860,9 +853,7 @@ static int eq_iir_params(struct processing_module *mod) component_set_nearest_period_frames(dev, comp_params.rate); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sinkb); - ret = buffer_set_params(sink_c, &comp_params, true); - buffer_release(sink_c); + ret = buffer_set_params(sinkb, &comp_params, true); return ret; } #endif @@ -880,12 +871,11 @@ static void eq_iir_set_passthrough_func(struct comp_data *cd, } static int eq_iir_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_data *cd = module_get_private_data(mod); struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; struct comp_dev *dev = mod->dev; enum sof_ipc_frame source_format; enum sof_ipc_frame sink_format; @@ -910,16 +900,12 @@ static int eq_iir_prepare(struct processing_module *mod, /* EQ component will only ever have 1 source and 1 sink buffer */ sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - eq_iir_set_alignment(&source_c->stream, &sink_c->stream); + eq_iir_set_alignment(&sourceb->stream, &sinkb->stream); /* get source and sink data format */ - channels = audio_stream_get_channels(&sink_c->stream); - source_format = audio_stream_get_frm_fmt(&source_c->stream); - sink_format = audio_stream_get_frm_fmt(&sink_c->stream); - buffer_release(sink_c); - buffer_release(source_c); + channels = audio_stream_get_channels(&sinkb->stream); + source_format = audio_stream_get_frm_fmt(&sourceb->stream); + sink_format = audio_stream_get_frm_fmt(&sinkb->stream); cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); @@ -960,8 +946,8 @@ static int eq_iir_reset(struct processing_module *mod) return 0; } -static struct module_interface eq_iir_interface = { - .init = eq_iir_init, +static const struct module_interface eq_iir_interface = { + .init = eq_iir_init, .prepare = eq_iir_prepare, .process_audio_stream = eq_iir_process, .set_configuration = eq_iir_set_config, diff --git a/src/audio/google/google_hotword_detect.c b/src/audio/google/google_hotword_detect.c index b948420ec36b..cf2c4ea3f00c 100644 --- a/src/audio/google/google_hotword_detect.c +++ b/src/audio/google/google_hotword_detect.c @@ -159,7 +159,6 @@ static int ghd_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) { struct comp_buffer *sourceb; - struct comp_buffer __sparse_cache *source_c; int ret; /* Detector is used only in KPB topology. It always requires channels @@ -176,21 +175,18 @@ static int ghd_params(struct comp_dev *dev, /* This detector component will only ever have 1 source */ sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(sourceb); - if (audio_stream_get_channels(source_c->stream) != 1) { + if (audio_stream_get_channels(sourceb->stream) != 1) { comp_err(dev, "ghd_params(): Only single-channel supported"); ret = -EINVAL; - } else if (audio_stream_get_frm_fmt(&source_c->stream) != SOF_IPC_FRAME_S16_LE) { + } else if (audio_stream_get_frm_fmt(&sourceb->stream) != SOF_IPC_FRAME_S16_LE) { comp_err(dev, "ghd_params(): Only S16_LE supported"); ret = -EINVAL; - } else if (source_c->stream.rate != KPB_SAMPLNG_FREQUENCY) { + } else if (sourceb->stream.rate != KPB_SAMPLNG_FREQUENCY) { comp_err(dev, "ghd_params(): Only 16KHz supported"); ret = -EINVAL; } - buffer_release(source_c); - return ret; } @@ -383,8 +379,7 @@ static int ghd_copy(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *source; - struct comp_buffer __sparse_cache *source_c; - struct audio_stream __sparse_cache *stream; + struct audio_stream *stream; uint32_t bytes, tail_bytes, head_bytes = 0; int ret; @@ -399,8 +394,7 @@ static int ghd_copy(struct comp_dev *dev) /* keyword components will only ever have 1 source */ source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(sourceb); - stream = &source_c->stream; + stream = &sourceb->stream; bytes = audio_stream_get_avail_bytes(stream); @@ -411,7 +405,7 @@ static int ghd_copy(struct comp_dev *dev) (uint32_t)audio_stream_get_end_addr(stream)); /* copy and perform detection */ - buffer_stream_invalidate(source_c, bytes); + buffer_stream_invalidate(sourceb, bytes); tail_bytes = (char *)audio_stream_get_end_addr(stream) - (char *)audio_stream_get_rptr(stream); @@ -426,9 +420,7 @@ static int ghd_copy(struct comp_dev *dev) ghd_detect(dev, stream, audio_stream_get_addr(stream), head_bytes); /* calc new available */ - comp_update_buffer_consume(source_c, bytes); - - buffer_release(source_c); + comp_update_buffer_consume(sourceb, bytes); return 0; } diff --git a/src/audio/google/google_rtc_audio_processing.c b/src/audio/google/google_rtc_audio_processing.c index 29493cf9da0b..87d270e71e11 100644 --- a/src/audio/google/google_rtc_audio_processing.c +++ b/src/audio/google/google_rtc_audio_processing.c @@ -89,7 +89,6 @@ static int google_rtc_audio_processing_params( int ret; #if CONFIG_IPC_MAJOR_4 struct google_rtc_audio_processing_comp_data *cd = comp_get_drvdata(dev); - struct comp_buffer __sparse_cache *sink_c; struct comp_buffer *sink; /* update sink buffer format */ @@ -108,9 +107,7 @@ static int google_rtc_audio_processing_params( enum sof_ipc_frame valid_fmt, frame_fmt; sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - ipc4_update_buffer_format(sink_c, out_fmt); - buffer_release(sink_c); + ipc4_update_buffer_format(sink, out_fmt); } #endif @@ -502,7 +499,6 @@ static int google_rtc_audio_processing_prepare(struct comp_dev *dev) { struct google_rtc_audio_processing_comp_data *cd = comp_get_drvdata(dev); struct list_item *source_buffer_list_item; - struct comp_buffer __sparse_cache *output_c; unsigned int aec_channels = 0, frame_fmt, rate; int ret; @@ -512,19 +508,17 @@ static int google_rtc_audio_processing_prepare(struct comp_dev *dev) list_for_item(source_buffer_list_item, &dev->bsource_list) { struct comp_buffer *source = container_of(source_buffer_list_item, struct comp_buffer, sink_list); - struct comp_buffer __sparse_cache *source_c = buffer_acquire(source); #if CONFIG_IPC_MAJOR_4 - if (IPC4_SINK_QUEUE_ID(source_c->id) == SOF_AEC_FEEDBACK_QUEUE_ID) { + if (IPC4_SINK_QUEUE_ID(source->id) == SOF_AEC_FEEDBACK_QUEUE_ID) { #else - if (source_c->source->pipeline->pipeline_id != dev->pipeline->pipeline_id) { + if (source->source->pipeline->pipeline_id != dev->pipeline->pipeline_id) { #endif cd->aec_reference = source; - aec_channels = audio_stream_get_channels(&source_c->stream); + aec_channels = audio_stream_get_channels(&source->stream); } else { cd->raw_microphone = source; } - buffer_release(source_c); } cd->output = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); @@ -539,11 +533,8 @@ static int google_rtc_audio_processing_prepare(struct comp_dev *dev) return -EINVAL; } - output_c = buffer_acquire(cd->output); - frame_fmt = audio_stream_get_frm_fmt(&output_c->stream); - rate = audio_stream_get_rate(&output_c->stream); - buffer_release(output_c); - + frame_fmt = audio_stream_get_frm_fmt(&cd->output->stream); + rate = audio_stream_get_rate(&cd->output->stream); if (cd->num_capture_channels > audio_stream_get_channels(&cd->raw_microphone->stream)) { comp_err(dev, "unsupported number of microphone channels: %d", @@ -592,8 +583,8 @@ static int google_rtc_audio_processing_reset(struct comp_dev *dev) static int google_rtc_audio_processing_copy(struct comp_dev *dev) { struct google_rtc_audio_processing_comp_data *cd = comp_get_drvdata(dev); - struct comp_buffer __sparse_cache *buffer_c, *mic_buf, *output_buf; struct comp_copy_limits cl; + struct comp_buffer *buffer; int16_t *src, *dst, *ref; uint32_t num_aec_reference_frames; uint32_t num_aec_reference_bytes; @@ -609,27 +600,26 @@ static int google_rtc_audio_processing_copy(struct comp_dev *dev) if (ret) return ret; } + buffer = cd->aec_reference; - buffer_c = buffer_acquire(cd->aec_reference); - - ref = audio_stream_get_rptr(&buffer_c->stream); + ref = audio_stream_get_rptr(&buffer->stream); - num_aec_reference_frames = audio_stream_get_avail_frames(&buffer_c->stream); - num_aec_reference_bytes = audio_stream_get_avail_bytes(&buffer_c->stream); + num_aec_reference_frames = audio_stream_get_avail_frames(&buffer->stream); + num_aec_reference_bytes = audio_stream_get_avail_bytes(&buffer->stream); - buffer_stream_invalidate(buffer_c, num_aec_reference_bytes); + buffer_stream_invalidate(buffer, num_aec_reference_bytes); num_samples_remaining = num_aec_reference_frames * - audio_stream_get_channels(&buffer_c->stream); + audio_stream_get_channels(&buffer->stream); while (num_samples_remaining) { - nmax = audio_stream_samples_without_wrap_s16(&buffer_c->stream, ref); + nmax = audio_stream_samples_without_wrap_s16(&buffer->stream, ref); n = MIN(num_samples_remaining, nmax); for (i = 0; i < n; i += cd->num_aec_reference_channels) { j = cd->num_aec_reference_channels * cd->aec_reference_frame_index; for (channel = 0; channel < cd->num_aec_reference_channels; ++channel) cd->aec_reference_buffer[j++] = ref[channel]; - ref += audio_stream_get_channels(&buffer_c->stream); + ref += audio_stream_get_channels(&buffer->stream); ++cd->aec_reference_frame_index; if (cd->aec_reference_frame_index == cd->num_frames) { @@ -639,26 +629,21 @@ static int google_rtc_audio_processing_copy(struct comp_dev *dev) } } num_samples_remaining -= n; - ref = audio_stream_wrap(&buffer_c->stream, ref); + ref = audio_stream_wrap(&buffer->stream, ref); } - comp_update_buffer_consume(buffer_c, num_aec_reference_bytes); - - buffer_release(buffer_c); + comp_update_buffer_consume(buffer, num_aec_reference_bytes); - mic_buf = buffer_acquire(cd->raw_microphone); - output_buf = buffer_acquire(cd->output); + src = audio_stream_get_rptr(&cd->raw_microphone->stream); + dst = audio_stream_get_wptr(&cd->output->stream); - src = audio_stream_get_rptr(&mic_buf->stream); - dst = audio_stream_get_wptr(&output_buf->stream); - - comp_get_copy_limits(mic_buf, output_buf, &cl); - buffer_stream_invalidate(mic_buf, cl.source_bytes); + comp_get_copy_limits(cd->raw_microphone, cd->output, &cl); + buffer_stream_invalidate(cd->raw_microphone, cl.source_bytes); num_frames_remaining = cl.frames; while (num_frames_remaining) { - nmax = audio_stream_frames_without_wrap(&mic_buf->stream, src); + nmax = audio_stream_frames_without_wrap(&cd->raw_microphone->stream, src); n = MIN(num_frames_remaining, nmax); - nmax = audio_stream_frames_without_wrap(&output_buf->stream, dst); + nmax = audio_stream_frames_without_wrap(&cd->output->stream, dst); n = MIN(n, nmax); for (i = 0; i < n; i++) { memcpy_s(&(cd->raw_mic_buffer[cd->raw_mic_buffer_frame_index * @@ -684,21 +669,18 @@ static int google_rtc_audio_processing_copy(struct comp_dev *dev) cd->raw_mic_buffer_frame_index = 0; } - src += audio_stream_get_channels(&mic_buf->stream); - dst += audio_stream_get_channels(&output_buf->stream); + src += audio_stream_get_channels(&cd->raw_microphone->stream); + dst += audio_stream_get_channels(&cd->output->stream); } num_frames_remaining -= n; - src = audio_stream_wrap(&mic_buf->stream, src); - dst = audio_stream_wrap(&output_buf->stream, dst); + src = audio_stream_wrap(&cd->raw_microphone->stream, src); + dst = audio_stream_wrap(&cd->output->stream, dst); } - buffer_stream_writeback(output_buf, cl.sink_bytes); - - comp_update_buffer_produce(output_buf, cl.sink_bytes); - comp_update_buffer_consume(mic_buf, cl.source_bytes); + buffer_stream_writeback(cd->output, cl.sink_bytes); - buffer_release(output_buf); - buffer_release(mic_buf); + comp_update_buffer_produce(cd->output, cl.sink_bytes); + comp_update_buffer_consume(cd->raw_microphone, cl.source_bytes); return 0; } diff --git a/src/audio/host-legacy.c b/src/audio/host-legacy.c index b9a112583586..83cf3c8cd3c4 100644 --- a/src/audio/host-legacy.c +++ b/src/audio/host-legacy.c @@ -105,16 +105,13 @@ static int host_dma_set_config_and_copy(struct host_data *hd, struct comp_dev *d */ static uint32_t host_get_copy_bytes_one_shot(struct host_data *hd, struct comp_dev *dev) { - struct comp_buffer __sparse_cache *buffer_c = buffer_acquire(hd->local_buffer); uint32_t copy_bytes; /* calculate minimum size to copy */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) - copy_bytes = audio_stream_get_free_bytes(&buffer_c->stream); + copy_bytes = audio_stream_get_free_bytes(&hd->local_buffer->stream); else - copy_bytes = audio_stream_get_avail_bytes(&buffer_c->stream); - - buffer_release(buffer_c); + copy_bytes = audio_stream_get_avail_bytes(&hd->local_buffer->stream); /* copy_bytes should be aligned to minimum possible chunk of * data to be copied by dma. @@ -168,17 +165,14 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c static uint32_t host_get_copy_bytes_one_shot(struct host_data *hd, struct comp_dev *dev) { struct dma_sg_elem *local_elem = hd->config.elem_array.elems; - struct comp_buffer __sparse_cache *buffer_c = buffer_acquire(hd->local_buffer); uint32_t copy_bytes; uint32_t split_value; /* calculate minimum size to copy */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) - copy_bytes = audio_stream_get_free_bytes(&buffer_c->stream); + copy_bytes = audio_stream_get_free_bytes(&hd->local_buffer->stream); else - copy_bytes = audio_stream_get_avail_bytes(&buffer_c->stream); - - buffer_release(buffer_c); + copy_bytes = audio_stream_get_avail_bytes(&hd->local_buffer->stream); /* copy_bytes should be aligned to minimum possible chunk of * data to be copied by dma. @@ -232,19 +226,19 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t bytes) { - struct comp_buffer __sparse_cache *source; - struct comp_buffer __sparse_cache *sink; + struct comp_buffer *source; + struct comp_buffer *sink; int ret; bool update_mailbox = false; bool send_ipc = false; if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { - source = buffer_acquire(hd->dma_buffer); - sink = buffer_acquire(hd->local_buffer); + source = hd->dma_buffer; + sink = hd->local_buffer; ret = dma_buffer_copy_from(source, sink, hd->process, bytes); } else { - source = buffer_acquire(hd->local_buffer); - sink = buffer_acquire(hd->dma_buffer); + source = hd->local_buffer; + sink = hd->dma_buffer; ret = dma_buffer_copy_to(source, sink, hd->process, bytes); } @@ -257,9 +251,6 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt audio_stream_get_free_samples(&sink->stream) * audio_stream_frame_bytes(&sink->stream)); - buffer_release(sink); - buffer_release(source); - if (ret < 0) return; @@ -372,7 +363,6 @@ static void host_dma_cb(void *arg, enum notify_id type, void *data) */ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev *dev) { - struct comp_buffer __sparse_cache *buffer_c; uint32_t avail_bytes = 0; uint32_t free_bytes = 0; uint32_t copy_bytes = 0; @@ -387,28 +377,24 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev return 0; } - buffer_c = buffer_acquire(hd->local_buffer); - /* calculate minimum size to copy */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { /* limit bytes per copy to one period for the whole pipeline * in order to avoid high load spike */ - free_bytes = audio_stream_get_free_bytes(&buffer_c->stream); + free_bytes = audio_stream_get_free_bytes(&hd->local_buffer->stream); copy_bytes = MIN(hd->period_bytes, MIN(avail_bytes, free_bytes)); if (!copy_bytes) comp_info(dev, "no bytes to copy, %d free in buffer, %d available in DMA", free_bytes, avail_bytes); } else { - avail_bytes = audio_stream_get_avail_bytes(&buffer_c->stream); + avail_bytes = audio_stream_get_avail_bytes(&hd->local_buffer->stream); copy_bytes = MIN(avail_bytes, free_bytes); if (!copy_bytes) comp_info(dev, "no bytes to copy, %d avail in buffer, %d free in DMA", avail_bytes, free_bytes); } - buffer_release(buffer_c); - /* copy_bytes should be aligned to minimum possible chunk of * data to be copied by dma. */ @@ -446,7 +432,6 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal static int create_local_elems(struct host_data *hd, struct comp_dev *dev, uint32_t buffer_count, uint32_t buffer_bytes) { - struct comp_buffer __sparse_cache *dma_buf_c; struct dma_sg_elem_array *elem_array; uint32_t dir; int err; @@ -469,11 +454,9 @@ static int create_local_elems(struct host_data *hd, struct comp_dev *dev, uint32 elem_array = &hd->config.elem_array; } - dma_buf_c = buffer_acquire(hd->dma_buffer); err = dma_sg_alloc(elem_array, SOF_MEM_ZONE_RUNTIME, dir, buffer_count, buffer_bytes, - (uintptr_t)(audio_stream_get_addr(&dma_buf_c->stream)), 0); - buffer_release(dma_buf_c); + (uintptr_t)(audio_stream_get_addr(&hd->dma_buffer->stream)), 0); if (err < 0) { comp_err(dev, "create_local_elems(): dma_sg_alloc() failed"); return err; @@ -690,8 +673,6 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, struct sof_ipc_stream_params *params, notifier_callback_t cb) { struct dma_sg_config *config = &hd->config; - struct comp_buffer __sparse_cache *host_buf_c; - struct comp_buffer __sparse_cache *dma_buf_c; uint32_t period_count; uint32_t period_bytes; uint32_t buffer_size; @@ -740,10 +721,9 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, hd->local_buffer = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - host_buf_c = buffer_acquire(hd->local_buffer); period_bytes = dev->frames * - audio_stream_frame_bytes(&host_buf_c->stream); + audio_stream_frame_bytes(&hd->local_buffer->stream); if (!period_bytes) { comp_err(dev, "host_params(): invalid period_bytes"); @@ -778,9 +758,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, * but we have to write back caches after we finish anyway */ if (hd->dma_buffer) { - dma_buf_c = buffer_acquire(hd->dma_buffer); - err = buffer_set_size(dma_buf_c, buffer_size, addr_align); - buffer_release(dma_buf_c); + err = buffer_set_size(hd->dma_buffer, buffer_size, addr_align); if (err < 0) { comp_err(dev, "host_params(): buffer_set_size() failed, buffer_size = %u", buffer_size); @@ -788,16 +766,14 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, } } else { hd->dma_buffer = buffer_alloc(buffer_size, SOF_MEM_CAPS_DMA, 0, - addr_align); + addr_align, false); if (!hd->dma_buffer) { comp_err(dev, "host_params(): failed to alloc dma buffer"); err = -ENOMEM; goto out; } - dma_buf_c = buffer_acquire(hd->dma_buffer); - buffer_set_params(dma_buf_c, params, BUFFER_UPDATE_FORCE); - buffer_release(dma_buf_c); + buffer_set_params(hd->dma_buffer, params, BUFFER_UPDATE_FORCE); } /* create SG DMA elems for local DMA buffer */ @@ -806,8 +782,8 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, goto out; /* set up DMA configuration - copy in sample bytes. */ - config->src_width = audio_stream_sample_bytes(&host_buf_c->stream); - config->dest_width = audio_stream_sample_bytes(&host_buf_c->stream); + config->src_width = audio_stream_sample_bytes(&hd->local_buffer->stream); + config->dest_width = audio_stream_sample_bytes(&hd->local_buffer->stream); config->cyclic = 0; config->irq_disabled = pipeline_is_timer_driven(dev->pipeline); config->is_scheduling_source = comp_is_scheduling_source(dev); @@ -851,11 +827,11 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, host_copy_normal; /* set processing function */ - hd->process = pcm_get_conversion_function(audio_stream_get_frm_fmt(&host_buf_c->stream), - audio_stream_get_frm_fmt(&host_buf_c->stream)); + hd->process = + pcm_get_conversion_function(audio_stream_get_frm_fmt(&hd->local_buffer->stream), + audio_stream_get_frm_fmt(&hd->local_buffer->stream)); out: - buffer_release(host_buf_c); hd->cb_dev = dev; @@ -886,11 +862,7 @@ static int host_params(struct comp_dev *dev, int host_common_prepare(struct host_data *hd) { - struct comp_buffer __sparse_cache *buf_c = buffer_acquire(hd->dma_buffer); - - buffer_zero(buf_c); - buffer_release(buf_c); - + buffer_zero(hd->dma_buffer); return 0; } diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index d62ad4b424fc..4016a8be82a4 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -109,18 +109,13 @@ static int host_dma_set_config_and_copy(struct host_data *hd, struct comp_dev *d static uint32_t host_get_copy_bytes_one_shot(struct host_data *hd) { struct comp_buffer *buffer = hd->local_buffer; - struct comp_buffer __sparse_cache *buffer_c; uint32_t copy_bytes; - buffer_c = buffer_acquire(buffer); - /* calculate minimum size to copy */ if (hd->ipc_host.direction == SOF_IPC_STREAM_PLAYBACK) - copy_bytes = audio_stream_get_free_bytes(&buffer_c->stream); + copy_bytes = audio_stream_get_free_bytes(&buffer->stream); else - copy_bytes = audio_stream_get_avail_bytes(&buffer_c->stream); - - buffer_release(buffer_c); + copy_bytes = audio_stream_get_avail_bytes(&buffer->stream); /* copy_bytes should be aligned to minimum possible chunk of * data to be copied by dma. @@ -175,19 +170,14 @@ static uint32_t host_get_copy_bytes_one_shot(struct host_data *hd) { struct dma_sg_elem *local_elem = hd->config.elem_array.elems; struct comp_buffer *buffer = hd->local_buffer; - struct comp_buffer __sparse_cache *buffer_c; uint32_t copy_bytes; uint32_t split_value; - buffer_c = buffer_acquire(buffer); - /* calculate minimum size to copy */ if (hd->ipc_host.direction == SOF_IPC_STREAM_PLAYBACK) - copy_bytes = audio_stream_get_free_bytes(&buffer_c->stream); + copy_bytes = audio_stream_get_free_bytes(&buffer->stream); else - copy_bytes = audio_stream_get_avail_bytes(&buffer_c->stream); - - buffer_release(buffer_c); + copy_bytes = audio_stream_get_avail_bytes(&buffer->stream); /* copy_bytes should be aligned to minimum possible chunk of * data to be copied by dma. @@ -241,36 +231,27 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t bytes) { - struct comp_buffer __sparse_cache *source; - struct comp_buffer __sparse_cache *sink; + struct comp_buffer *source; + struct comp_buffer *sink; int ret; bool update_mailbox = false; bool send_ipc = false; - if (hd->ipc_host.direction == SOF_IPC_STREAM_PLAYBACK) { - source = buffer_acquire(hd->dma_buffer); - sink = buffer_acquire(hd->local_buffer); + if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { + source = hd->dma_buffer; + sink = hd->local_buffer; ret = dma_buffer_copy_from(source, sink, hd->process, bytes); } else { - source = buffer_acquire(hd->local_buffer); - sink = buffer_acquire(hd->dma_buffer); + source = hd->local_buffer; + sink = hd->dma_buffer; ret = dma_buffer_copy_to(source, sink, hd->process, bytes); } - /* assert dma_buffer_copy succeed */ - if (ret < 0) - comp_err(dev, "host_common_update() dma buffer copy failed, dir %d bytes %d avail %d free %d", - hd->ipc_host.direction, bytes, - audio_stream_get_avail_samples(&source->stream) * - audio_stream_frame_bytes(&source->stream), - audio_stream_get_free_samples(&sink->stream) * - audio_stream_frame_bytes(&sink->stream)); - - buffer_release(sink); - buffer_release(source); - - if (ret < 0) + if (ret < 0) { + comp_err(dev, "host_common_update() copy failed, dir %d bytes %d return: %d", + dev->direction, bytes, ret); return; + } hd->total_data_processed += bytes; @@ -379,8 +360,6 @@ static void host_dma_cb(struct comp_dev *dev, size_t bytes) static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev *dev) { struct comp_buffer *buffer = hd->local_buffer; - struct comp_buffer __sparse_cache *buffer_c; - struct comp_buffer __sparse_cache *dma_buf_c; struct dma_status dma_stat; uint32_t avail_samples; uint32_t free_samples; @@ -397,18 +376,14 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev return 0; } - dma_buf_c = buffer_acquire(hd->dma_buffer); - dma_sample_bytes = get_sample_bytes(audio_stream_get_frm_fmt(&dma_buf_c->stream)); - buffer_release(dma_buf_c); - - buffer_c = buffer_acquire(buffer); + dma_sample_bytes = hd->config.src_width; /* calculate minimum size to copy */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { avail_samples = (dma_stat.pending_length - hd->partial_size) / dma_sample_bytes; - free_samples = audio_stream_get_free_samples(&buffer_c->stream); + free_samples = audio_stream_get_free_samples(&buffer->stream); } else { - avail_samples = audio_stream_get_avail_samples(&buffer_c->stream); + avail_samples = audio_stream_get_avail_samples(&buffer->stream); free_samples = (dma_stat.free - hd->partial_size) / dma_sample_bytes; } @@ -425,8 +400,6 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev comp_info(dev, "no bytes to copy, available samples: %d, free_samples: %d", avail_samples, free_samples); - buffer_release(buffer_c); - /* dma_copy_bytes should be aligned to minimum possible chunk of * data to be copied by dma. */ @@ -464,7 +437,6 @@ static inline bool stream_sync(struct host_data *hd, struct comp_dev *dev) */ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb) { - struct comp_buffer __sparse_cache *buffer_c; uint32_t copy_bytes; const unsigned int threshold = #if CONFIG_HOST_DMA_RELOAD_DELAY_ENABLE @@ -482,7 +454,6 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal cb(dev, copy_bytes); hd->partial_size += copy_bytes; - buffer_c = buffer_acquire(hd->dma_buffer); /* * On large buffers we don't need to reload DMA on every period. When @@ -491,8 +462,8 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal * also adding a 2ms safety margin. */ if (!IS_ENABLED(CONFIG_HOST_DMA_RELOAD_DELAY_ENABLE) || - audio_stream_get_size(&buffer_c->stream) < hd->period_bytes << 3 || - audio_stream_get_size(&buffer_c->stream) - hd->partial_size <= + hd->dma_buffer_size < hd->period_bytes << 3 || + hd->dma_buffer_size - hd->partial_size <= (2 + threshold) * hd->period_bytes) { if (stream_sync(hd, dev)) { ret = dma_reload(hd->chan->dma->z_dev, hd->chan->index, 0, 0, @@ -503,16 +474,12 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal hd->partial_size = 0; } } - - buffer_release(buffer_c); - return ret; } static int create_local_elems(struct host_data *hd, struct comp_dev *dev, uint32_t buffer_count, uint32_t buffer_bytes, uint32_t direction) { - struct comp_buffer __sparse_cache *dma_buf_c; struct dma_sg_elem_array *elem_array; uint32_t dir; int err; @@ -535,11 +502,9 @@ static int create_local_elems(struct host_data *hd, struct comp_dev *dev, uint32 elem_array = &hd->config.elem_array; } - dma_buf_c = buffer_acquire(hd->dma_buffer); err = dma_sg_alloc(elem_array, SOF_MEM_ZONE_RUNTIME, dir, buffer_count, buffer_bytes, - (uintptr_t)audio_stream_get_addr(&dma_buf_c->stream), 0); - buffer_release(dma_buf_c); + (uintptr_t)audio_stream_get_addr(&hd->dma_buffer->stream), 0); if (err < 0) { comp_err(dev, "create_local_elems(): dma_sg_alloc() failed"); return err; @@ -759,8 +724,6 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, struct dma_sg_elem *sg_elem; struct dma_config *dma_cfg = &hd->z_config; struct dma_block_config dma_block_cfg; - struct comp_buffer __sparse_cache *host_buf_c; - struct comp_buffer __sparse_cache *dma_buf_c; uint32_t period_count; uint32_t period_bytes; uint32_t buffer_size; @@ -809,14 +772,12 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, hd->local_buffer = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - host_buf_c = buffer_acquire(hd->local_buffer); period_bytes = dev->frames * get_frame_bytes(params->frame_fmt, params->channels); if (!period_bytes) { comp_err(dev, "host_params(): invalid period_bytes"); - err = -EINVAL; - goto out; + return -EINVAL; } /* determine source and sink buffer elements */ @@ -848,46 +809,43 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, * but we have to write back caches after we finish anywae */ if (hd->dma_buffer) { - dma_buf_c = buffer_acquire(hd->dma_buffer); - err = buffer_set_size(dma_buf_c, buffer_size, addr_align); - buffer_release(dma_buf_c); + err = buffer_set_size(hd->dma_buffer, buffer_size, addr_align); if (err < 0) { comp_err(dev, "host_params(): buffer_set_size() failed, buffer_size = %u", buffer_size); - goto out; + return err; } } else { + /* allocate not shared buffer */ hd->dma_buffer = buffer_alloc(buffer_size, SOF_MEM_CAPS_DMA, 0, - addr_align); + addr_align, false); if (!hd->dma_buffer) { comp_err(dev, "host_params(): failed to alloc dma buffer"); - err = -ENOMEM; - goto out; + return -ENOMEM; } - dma_buf_c = buffer_acquire(hd->dma_buffer); - buffer_set_params(dma_buf_c, params, BUFFER_UPDATE_FORCE); + buffer_set_params(hd->dma_buffer, params, BUFFER_UPDATE_FORCE); /* set processing function */ if (params->direction == SOF_IPC_STREAM_CAPTURE) hd->process = pcm_get_conversion_function( - audio_stream_get_frm_fmt(&host_buf_c->stream), - audio_stream_get_frm_fmt(&dma_buf_c->stream)); + audio_stream_get_frm_fmt(&hd->local_buffer->stream), + audio_stream_get_frm_fmt(&hd->dma_buffer->stream)); else hd->process = pcm_get_conversion_function( - audio_stream_get_frm_fmt(&dma_buf_c->stream), - audio_stream_get_frm_fmt(&host_buf_c->stream)); + audio_stream_get_frm_fmt(&hd->dma_buffer->stream), + audio_stream_get_frm_fmt(&hd->local_buffer->stream)); - config->src_width = audio_stream_sample_bytes(&dma_buf_c->stream); + config->src_width = audio_stream_sample_bytes(&hd->dma_buffer->stream); config->dest_width = config->src_width; - buffer_release(dma_buf_c); + hd->dma_buffer_size = audio_stream_get_size(&hd->dma_buffer->stream); } /* create SG DMA elems for local DMA buffer */ err = create_local_elems(hd, dev, period_count, buffer_size / period_count, params->direction); if (err < 0) - goto out; + return err; /* set up DMA configuration - copy in sample bytes. */ config->cyclic = 0; @@ -905,8 +863,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, channel = dma_request_channel(hd->dma->z_dev, &hda_chan); if (channel < 0) { comp_err(dev, "host_params(): requested channel %d is busy", hda_chan); - err = -ENODEV; - goto out; + return -ENODEV; } hd->chan = &hd->dma->chan[channel]; @@ -960,7 +917,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, comp_err(dev, "host_params(): dma_config() failed"); dma_release_channel(hd->dma->z_dev, hd->chan->index); hd->chan = NULL; - goto out; + return err; } err = dma_get_attribute(hd->dma->z_dev, DMA_ATTR_COPY_ALIGNMENT, @@ -968,8 +925,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, if (err < 0) { comp_err(dev, "host_params(): dma_get_attribute()"); - - goto out; + return err; } /* minimal copied data shouldn't be less than alignment */ @@ -982,9 +938,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, hd->copy = hd->copy_type == COMP_COPY_ONE_SHOT ? host_copy_one_shot : host_copy_normal; -out: - buffer_release(host_buf_c); - return err; + return 0; } static int host_params(struct comp_dev *dev, @@ -1006,11 +960,7 @@ static int host_params(struct comp_dev *dev, int host_common_prepare(struct host_data *hd) { - struct comp_buffer __sparse_cache *buf_c = buffer_acquire(hd->dma_buffer); - - buffer_zero(buf_c); - buffer_release(buf_c); - + buffer_zero(hd->dma_buffer); return 0; } diff --git a/src/audio/igo_nr/igo_nr.c b/src/audio/igo_nr/igo_nr.c index 7ee3884bd023..19d0cc01db46 100644 --- a/src/audio/igo_nr/igo_nr.c +++ b/src/audio/igo_nr/igo_nr.c @@ -66,8 +66,8 @@ static void igo_nr_lib_process(struct comp_data *cd) #if CONFIG_FORMAT_S16LE static void igo_nr_capture_s16(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, int32_t frames) { int32_t nch = audio_stream_get_channels(source); @@ -125,8 +125,8 @@ static void igo_nr_capture_s16(struct comp_data *cd, #if CONFIG_FORMAT_S24LE static void igo_nr_capture_s24(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, int32_t frames) { int32_t nch = audio_stream_get_channels(source); @@ -184,8 +184,8 @@ static void igo_nr_capture_s24(struct comp_data *cd, #if CONFIG_FORMAT_S32LE static void igo_nr_capture_s32(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, int32_t frames) { int32_t nch = audio_stream_get_channels(source); @@ -379,7 +379,6 @@ static int32_t igo_nr_params(struct comp_dev *dev, { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sinkb, *sourceb; - struct comp_buffer __sparse_cache *sink_c, *source_c; int32_t err; comp_info(dev, "igo_nr_params()"); @@ -395,22 +394,16 @@ static int32_t igo_nr_params(struct comp_dev *dev, sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - /* set source/sink_frames/rate */ - cd->source_rate = audio_stream_get_rate(&source_c->stream); - cd->sink_rate = audio_stream_get_rate(&sink_c->stream); + cd->source_rate = audio_stream_get_rate(&sourceb->stream); + cd->sink_rate = audio_stream_get_rate(&sinkb->stream); - if (audio_stream_get_channels(&source_c->stream) != - audio_stream_get_channels(&sink_c->stream)) { + if (audio_stream_get_channels(&sourceb->stream) != + audio_stream_get_channels(&sinkb->stream)) { comp_err(dev, "igo_nr_params(), mismatch source/sink stream channels"); cd->invalid_param = true; } - buffer_release(sink_c); - buffer_release(source_c); - if (!cd->sink_rate) { comp_err(dev, "igo_nr_params(), zero sink rate"); return -EINVAL; @@ -619,8 +612,8 @@ static int32_t igo_nr_cmd(struct comp_dev *dev, } static void igo_nr_process(struct comp_dev *dev, - struct comp_buffer __sparse_cache *source, - struct comp_buffer __sparse_cache *sink, + struct comp_buffer *source, + struct comp_buffer *sink, struct comp_copy_limits *cl, int32_t frames) @@ -701,7 +694,6 @@ static int32_t igo_nr_copy(struct comp_dev *dev) { struct comp_copy_limits cl; struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; struct comp_data *cd = comp_get_drvdata(dev); int32_t src_frames; int32_t sink_frames; @@ -713,27 +705,21 @@ static int32_t igo_nr_copy(struct comp_dev *dev) sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - /* Check for changed configuration */ if (comp_is_new_data_blob_available(cd->model_handler)) igo_nr_set_igo_params(dev); /* Get source, sink, number of frames etc. to process. */ - comp_get_copy_limits(source_c, sink_c, &cl); + comp_get_copy_limits(sourceb, sinkb, &cl); - src_frames = audio_stream_get_avail_frames(&source_c->stream); - sink_frames = audio_stream_get_free_frames(&sink_c->stream); + src_frames = audio_stream_get_avail_frames(&sourceb->stream); + sink_frames = audio_stream_get_free_frames(&sinkb->stream); comp_dbg(dev, "src_frames = %d, sink_frames = %d.", src_frames, sink_frames); /* Process only when frames count is enough. */ if (src_frames >= IGO_FRAME_SIZE && sink_frames >= IGO_FRAME_SIZE) - igo_nr_process(dev, source_c, sink_c, &cl, IGO_FRAME_SIZE); - - buffer_release(sink_c); - buffer_release(source_c); + igo_nr_process(dev, sourceb, sinkb, &cl, IGO_FRAME_SIZE); return 0; } diff --git a/src/audio/kpb.c b/src/audio/kpb.c index dee693d6fd9d..48bc6bd3eeec 100644 --- a/src/audio/kpb.c +++ b/src/audio/kpb.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -106,6 +107,8 @@ struct comp_data { uint32_t num_of_in_channels; uint32_t offsets[KPB_MAX_MICSEL_CHANNELS]; struct kpb_micselector_config mic_sel; + struct kpb_fmt_dev_list fmt_device_list; + struct fast_mode_task fmt; #if CONFIG_AMS uint32_t kpd_uuid_id; @@ -120,18 +123,18 @@ static int kpb_register_client(struct comp_data *kpb, struct kpb_client *cli); static void kpb_init_draining(struct comp_dev *dev, struct kpb_client *cli); static enum task_state kpb_draining_task(void *arg); static int kpb_buffer_data(struct comp_dev *dev, - const struct comp_buffer __sparse_cache *source, size_t size); + const struct comp_buffer *source, size_t size); static size_t kpb_allocate_history_buffer(struct comp_data *kpb, size_t hb_size_req); static void kpb_clear_history_buffer(struct history_buffer *buff); static void kpb_free_history_buffer(struct history_buffer *buff); static inline bool kpb_is_sample_width_supported(uint32_t sampling_width); -static void kpb_copy_samples(struct comp_buffer __sparse_cache *sink, - struct comp_buffer __sparse_cache *source, size_t size, +static void kpb_copy_samples(struct comp_buffer *sink, + struct comp_buffer *source, size_t size, size_t sample_width, uint32_t channels); -static void kpb_drain_samples(void *source, struct audio_stream __sparse_cache *sink, +static void kpb_drain_samples(void *source, struct audio_stream *sink, size_t size, size_t sample_width); -static void kpb_buffer_samples(const struct audio_stream __sparse_cache *source, +static void kpb_buffer_samples(const struct audio_stream *source, int offset, void *sink, size_t size, size_t sample_width); static void kpb_reset_history_buffer(struct history_buffer *buff); @@ -141,6 +144,23 @@ static inline bool validate_host_params(struct comp_dev *dev, size_t hb_size_req); static inline void kpb_change_state(struct comp_data *kpb, enum kpb_state state); +#ifdef CONFIG_IPC_MAJOR_4 +/* KpbFastModeTaskModulesList Namespace */ +static inline int alloc_fmt_module_list_item(struct kpb_fmt_dev_list *fmt_device_list, + struct comp_dev *mi_ptr, struct comp_dev ***item); +static int clear_fmt_modules_list(struct kpb_fmt_dev_list *fmt_device_list, + uint32_t outpin_idx); +static int prepare_fmt_modules_list(struct comp_dev *kpb_dev, uint32_t outpin_idx, + const struct kpb_task_params *modules_to_prepare); +/* FMT Namespace */ +static int register_modules_list(struct fast_mode_task *fmt, + struct device_list *new_list, size_t list_idx); +static int unregister_modules_list(struct fast_mode_task *fmt, + struct device_list *list_to_remove, size_t list_idx); +/* Devicelist */ +static int devicelist_push(struct device_list *devlist, struct comp_dev **dev); +static void devicelist_reset(struct device_list *devlist, bool remove_items); +#endif static uint64_t kpb_task_deadline(void *data) { @@ -330,17 +350,14 @@ static int kpb_bind(struct comp_dev *dev, void *data) list_for_item(blist, &dev->bsink_list) { struct comp_buffer *sink = container_of(blist, struct comp_buffer, source_list); - struct comp_buffer __sparse_cache *sink_c = buffer_acquire(sink); int sink_buf_id; - if (!sink_c->sink) { + if (!sink->sink) { ret = -EINVAL; - buffer_release(sink_c); break; } - sink_buf_id = sink_c->id; - buffer_release(sink_c); + sink_buf_id = sink->id; if (sink_buf_id == buf_id) { if (sink_buf_id == 0) @@ -376,7 +393,8 @@ static int kpb_unbind(struct comp_dev *dev, void *data) else kpb->host_sink = NULL; - return 0; + /* Clear fmt config */ + return clear_fmt_modules_list(&kpb->fmt_device_list, bu->extension.r.src_queue); } #else /* CONFIG_IPC_MAJOR_4 */ @@ -848,17 +866,13 @@ static int kpb_prepare(struct comp_dev *dev) list_for_item(blist, &dev->bsink_list) { struct comp_buffer *sink = container_of(blist, struct comp_buffer, source_list); - struct comp_buffer __sparse_cache *sink_c = buffer_acquire(sink); enum sof_comp_type type; - if (!sink_c->sink) { + if (!sink->sink) { ret = -EINVAL; - buffer_release(sink_c); break; } - - type = dev_comp_type(sink_c->sink); - buffer_release(sink_c); + type = dev_comp_type(sink->sink); switch (type) { case SOF_COMP_SELECTOR: @@ -886,18 +900,15 @@ static int kpb_prepare(struct comp_dev *dev) list_for_item(sink_list, &dev->bsink_list) { struct comp_buffer *sink = container_of(sink_list, struct comp_buffer, source_list); - struct comp_buffer __sparse_cache *sink_c = buffer_acquire(sink); audio_stream_init_alignment_constants(byte_align, frame_align_req, - &sink_c->stream); - sink_id = sink_c->id; + &sink->stream); + sink_id = sink->id; if (sink_id == 0) - audio_stream_set_channels(&sink_c->stream, kpb->num_of_sel_mic); + audio_stream_set_channels(&sink->stream, kpb->num_of_sel_mic); else - audio_stream_set_channels(&sink_c->stream, kpb->config.channels); - - buffer_release(sink_c); + audio_stream_set_channels(&sink->stream, kpb->config.channels); } } #endif /* CONFIG_IPC_MAJOR_4 */ @@ -991,12 +1002,12 @@ static int kpb_reset(struct comp_dev *dev) #ifdef KPB_HIFI3 #if CONFIG_FORMAT_S16LE -static void kpb_micselect_copy16(struct comp_buffer __sparse_cache *sink, - struct comp_buffer __sparse_cache *source, size_t size, +static void kpb_micselect_copy16(struct comp_buffer *sink, + struct comp_buffer *source, size_t size, uint32_t in_channels, uint32_t micsel_channels, uint32_t *offsets) { - struct audio_stream __sparse_cache *istream = &source->stream; - struct audio_stream __sparse_cache *ostream = &sink->stream; + struct audio_stream *istream = &source->stream; + struct audio_stream *ostream = &sink->stream; uint16_t ch; size_t i; @@ -1024,12 +1035,12 @@ static void kpb_micselect_copy16(struct comp_buffer __sparse_cache *sink, } #endif #if CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE -static void kpb_micselect_copy32(struct comp_buffer __sparse_cache *sink, - struct comp_buffer __sparse_cache *source, size_t size, +static void kpb_micselect_copy32(struct comp_buffer *sink, + struct comp_buffer *source, size_t size, uint32_t in_channels, uint32_t micsel_channels, uint32_t *offsets) { - struct audio_stream __sparse_cache *istream = &source->stream; - struct audio_stream __sparse_cache *ostream = &sink->stream; + struct audio_stream *istream = &source->stream; + struct audio_stream *ostream = &sink->stream; uint16_t ch; size_t i; @@ -1058,12 +1069,12 @@ static void kpb_micselect_copy32(struct comp_buffer __sparse_cache *sink, } #endif #else -static void kpb_micselect_copy16(struct comp_buffer __sparse_cache *sink, - struct comp_buffer __sparse_cache *source, size_t size, +static void kpb_micselect_copy16(struct comp_buffer *sink, + struct comp_buffer *source, size_t size, uint32_t in_channels, uint32_t micsel_channels, uint32_t *offsets) { - struct audio_stream __sparse_cache *istream = &source->stream; - struct audio_stream __sparse_cache *ostream = &sink->stream; + struct audio_stream *istream = &source->stream; + struct audio_stream *ostream = &sink->stream; buffer_stream_invalidate(source, size); size_t out_samples; @@ -1090,12 +1101,12 @@ static void kpb_micselect_copy16(struct comp_buffer __sparse_cache *sink, } } -static void kpb_micselect_copy32(struct comp_buffer __sparse_cache *sink, - struct comp_buffer __sparse_cache *source, size_t size, +static void kpb_micselect_copy32(struct comp_buffer *sink, + struct comp_buffer *source, size_t size, uint32_t in_channels, uint32_t micsel_channels, uint32_t *offsets) { - struct audio_stream __sparse_cache *istream = &source->stream; - struct audio_stream __sparse_cache *ostream = &sink->stream; + struct audio_stream *istream = &source->stream; + struct audio_stream *ostream = &sink->stream; buffer_stream_invalidate(source, size); size_t out_samples; @@ -1121,8 +1132,8 @@ static void kpb_micselect_copy32(struct comp_buffer __sparse_cache *sink, } } #endif -static void kpb_micselect_copy(struct comp_dev *dev, struct comp_buffer __sparse_cache *sink_c, - struct comp_buffer __sparse_cache *source_c, size_t copy_bytes, +static void kpb_micselect_copy(struct comp_dev *dev, struct comp_buffer *sink_c, + struct comp_buffer *source_c, size_t copy_bytes, uint32_t channels) { struct comp_data *kpb = comp_get_drvdata(dev); @@ -1167,7 +1178,6 @@ static int kpb_copy(struct comp_dev *dev) int ret = 0; struct comp_data *kpb = comp_get_drvdata(dev); struct comp_buffer *source, *sink; - struct comp_buffer __sparse_cache *source_c, *sink_c = NULL; size_t copy_bytes = 0, produced_bytes = 0; size_t sample_width = kpb->config.sampling_width; struct draining_data *dd = &kpb->draining_task_data; @@ -1185,13 +1195,11 @@ static int kpb_copy(struct comp_dev *dev) source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(source); - /* Validate source */ - if (!audio_stream_get_rptr(&source_c->stream)) { + if (!audio_stream_get_rptr(&source->stream)) { comp_err(dev, "kpb_copy(): invalid source pointers."); ret = -EINVAL; - goto out; + return ret; } switch (kpb->state) { @@ -1206,29 +1214,27 @@ static int kpb_copy(struct comp_dev *dev) break; } - sink_c = buffer_acquire(sink); - /* Validate sink */ - if (!audio_stream_get_wptr(&sink_c->stream)) { + if (!audio_stream_get_wptr(&sink->stream)) { comp_err(dev, "kpb_copy(): invalid selector sink pointers."); ret = -EINVAL; break; } - copy_bytes = audio_stream_get_copy_bytes(&source_c->stream, &sink_c->stream); + copy_bytes = audio_stream_get_copy_bytes(&source->stream, &sink->stream); if (!copy_bytes) { comp_err(dev, "kpb_copy(): nothing to copy sink->free %d source->avail %d", - audio_stream_get_free_bytes(&sink_c->stream), - audio_stream_get_avail_bytes(&source_c->stream)); + audio_stream_get_free_bytes(&sink->stream), + audio_stream_get_avail_bytes(&source->stream)); ret = PPL_STATUS_PATH_STOP; break; } if (kpb->num_of_sel_mic == 0) { - kpb_copy_samples(sink_c, source_c, copy_bytes, sample_width, channels); + kpb_copy_samples(sink, source, copy_bytes, sample_width, channels); } else { - uint32_t avail = audio_stream_get_avail_bytes(&source_c->stream); - uint32_t free = audio_stream_get_free_bytes(&sink_c->stream); + uint32_t avail = audio_stream_get_avail_bytes(&source->stream); + uint32_t free = audio_stream_get_free_bytes(&sink->stream); copy_bytes = MIN(avail, free * channels / kpb->num_of_sel_mic); copy_bytes = ROUND_DOWN(copy_bytes, (sample_width >> 3) * channels); @@ -1244,13 +1250,13 @@ static int kpb_copy(struct comp_dev *dev) ret = PPL_STATUS_PATH_STOP; break; } - kpb_micselect_copy(dev, sink_c, source_c, produced_bytes, channels); + kpb_micselect_copy(dev, sink, source, produced_bytes, channels); } /* Buffer source data internally in history buffer for future * use by clients. */ if (copy_bytes <= kpb->hd.buffer_size) { - ret = kpb_buffer_data(dev, source_c, copy_bytes); + ret = kpb_buffer_data(dev, source, copy_bytes); if (ret) { comp_err(dev, "kpb_copy(): internal buffering failed."); @@ -1269,11 +1275,11 @@ static int kpb_copy(struct comp_dev *dev) } if (kpb->num_of_sel_mic == 0) - comp_update_buffer_produce(sink_c, copy_bytes); + comp_update_buffer_produce(sink, copy_bytes); else - comp_update_buffer_produce(sink_c, produced_bytes); + comp_update_buffer_produce(sink, produced_bytes); - comp_update_buffer_consume(source_c, copy_bytes); + comp_update_buffer_consume(source, copy_bytes); break; case KPB_STATE_HOST_COPY: @@ -1286,20 +1292,18 @@ static int kpb_copy(struct comp_dev *dev) break; } - sink_c = buffer_acquire(sink); - /* Validate sink */ - if (!audio_stream_get_wptr(&sink_c->stream)) { + if (!audio_stream_get_wptr(&sink->stream)) { comp_err(dev, "kpb_copy(): invalid host sink pointers."); ret = -EINVAL; break; } - copy_bytes = audio_stream_get_copy_bytes(&source_c->stream, &sink_c->stream); + copy_bytes = audio_stream_get_copy_bytes(&source->stream, &sink->stream); if (!copy_bytes) { comp_err(dev, "kpb_copy(): nothing to copy sink->free %d source->avail %d", - audio_stream_get_free_bytes(&sink_c->stream), - audio_stream_get_avail_bytes(&source_c->stream)); + audio_stream_get_free_bytes(&sink->stream), + audio_stream_get_avail_bytes(&source->stream)); /* NOTE! We should stop further pipeline copy due to * no data availability however due to HW bug * (no HOST DMA IRQs) we need to call host copy @@ -1308,10 +1312,10 @@ static int kpb_copy(struct comp_dev *dev) break; } - kpb_copy_samples(sink_c, source_c, copy_bytes, sample_width, channels); + kpb_copy_samples(sink, source, copy_bytes, sample_width, channels); - comp_update_buffer_produce(sink_c, copy_bytes); - comp_update_buffer_consume(source_c, copy_bytes); + comp_update_buffer_produce(sink, copy_bytes); + comp_update_buffer_consume(source, copy_bytes); break; case KPB_STATE_INIT_DRAINING: @@ -1319,12 +1323,12 @@ static int kpb_copy(struct comp_dev *dev) /* In draining and init draining we only buffer data in * the internal history buffer. */ - avail_bytes = audio_stream_get_avail_bytes(&source_c->stream); + avail_bytes = audio_stream_get_avail_bytes(&source->stream); copy_bytes = MIN(avail_bytes, kpb->hd.free); ret = PPL_STATUS_PATH_STOP; if (copy_bytes) { - buffer_stream_invalidate(source_c, copy_bytes); - ret = kpb_buffer_data(dev, source_c, copy_bytes); + buffer_stream_invalidate(source, copy_bytes); + ret = kpb_buffer_data(dev, source, copy_bytes); dd->buffered_while_draining += copy_bytes; kpb->hd.free -= copy_bytes; @@ -1333,10 +1337,10 @@ static int kpb_copy(struct comp_dev *dev) break; } - comp_update_buffer_consume(source_c, copy_bytes); + comp_update_buffer_consume(source, copy_bytes); } else { comp_warn(dev, "kpb_copy(): buffering skipped (no data to copy, avail %d, free %d", - audio_stream_get_avail_bytes(&source_c->stream), + audio_stream_get_avail_bytes(&source->stream), kpb->hd.free); } @@ -1348,11 +1352,6 @@ static int kpb_copy(struct comp_dev *dev) break; } -out: - if (sink_c) - buffer_release(sink_c); - buffer_release(source_c); - return ret; } @@ -1365,7 +1364,7 @@ static int kpb_copy(struct comp_dev *dev) * */ static int kpb_buffer_data(struct comp_dev *dev, - const struct comp_buffer __sparse_cache *source, size_t size) + const struct comp_buffer *source, size_t size) { int ret = 0; size_t size_to_copy = size; @@ -1729,7 +1728,7 @@ static void kpb_init_draining(struct comp_dev *dev, struct kpb_client *cli) static enum task_state kpb_draining_task(void *arg) { struct draining_data *draining_data = (struct draining_data *)arg; - struct comp_buffer __sparse_cache *sink = buffer_acquire(draining_data->sink); + struct comp_buffer *sink = draining_data->sink; struct history_buffer *buff = draining_data->hb; size_t drain_req = draining_data->drain_req; size_t sample_width = draining_data->sample_width; @@ -1859,13 +1858,9 @@ static enum task_state kpb_draining_task(void *arg) out: draining_time_end = sof_cycle_get_64(); - buffer_release(sink); - /* Reset host-sink copy mode back to its pre-draining value */ - sink = buffer_acquire(kpb->host_sink); - comp_set_attribute(sink->sink, COMP_ATTR_COPY_TYPE, + comp_set_attribute(kpb->host_sink->sink, COMP_ATTR_COPY_TYPE, &kpb->draining_task_data.copy_type); - buffer_release(sink); draining_time_ms = k_cyc_to_ms_near64(draining_time_end - draining_time_start); if (draining_time_ms <= UINT_MAX) @@ -1880,7 +1875,7 @@ static enum task_state kpb_draining_task(void *arg) #ifdef KPB_HIFI3 static void kpb_convert_24b_to_32b(const void *linear_source, int ioffset, - struct audio_stream __sparse_cache *sink, int ooffset, + struct audio_stream *sink, int ooffset, unsigned int n_samples) { int ssize = audio_stream_sample_bytes(sink); @@ -1928,7 +1923,7 @@ static void kpb_convert_24b_to_32b(const void *linear_source, int ioffset, } #else static void kpb_convert_24b_to_32b(const void *source, int ioffset, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, int ooffset, unsigned int samples) { int ssize = audio_stream_sample_bytes(sink); @@ -1960,7 +1955,7 @@ static void kpb_convert_24b_to_32b(const void *source, int ioffset, * * \return none. */ -static void kpb_drain_samples(void *source, struct audio_stream __sparse_cache *sink, +static void kpb_drain_samples(void *source, struct audio_stream *sink, size_t size, size_t sample_width) { unsigned int samples; @@ -1989,7 +1984,7 @@ static void kpb_drain_samples(void *source, struct audio_stream __sparse_cache * } #ifdef KPB_HIFI3 -static void kpb_convert_32b_to_24b(const struct audio_stream __sparse_cache *source, int ioffset, +static void kpb_convert_32b_to_24b(const struct audio_stream *source, int ioffset, void *linear_sink, int ooffset, unsigned int n_samples) { int ssize = audio_stream_sample_bytes(source); @@ -2027,7 +2022,7 @@ static void kpb_convert_32b_to_24b(const struct audio_stream __sparse_cache *sou } } #else -static void kpb_convert_32b_to_24b(const struct audio_stream __sparse_cache *source, int ioffset, +static void kpb_convert_32b_to_24b(const struct audio_stream *source, int ioffset, void *sink, int ooffset, unsigned int samples) { int ssize = audio_stream_sample_bytes(source); @@ -2060,7 +2055,7 @@ static void kpb_convert_32b_to_24b(const struct audio_stream __sparse_cache *sou * \param[in] size Requested copy size in bytes. * \param[in] sample_width Sample size. */ -static void kpb_buffer_samples(const struct audio_stream __sparse_cache *source, +static void kpb_buffer_samples(const struct audio_stream *source, int offset, void *sink, size_t size, size_t sample_width) { @@ -2147,8 +2142,8 @@ static inline bool kpb_is_sample_width_supported(uint32_t sampling_width) } #ifdef KPB_HIFI3 -static void kpb_copy_24b_in_32b(const struct audio_stream __sparse_cache *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, uint32_t ooffset, +static void kpb_copy_24b_in_32b(const struct audio_stream *source, uint32_t ioffset, + struct audio_stream *sink, uint32_t ooffset, uint32_t n_samples) { int ssize = audio_stream_sample_bytes(source); /* src fmt == sink fmt */ @@ -2181,8 +2176,8 @@ static void kpb_copy_24b_in_32b(const struct audio_stream __sparse_cache *source } } #else -static void kpb_copy_24b_in_32b(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static void kpb_copy_24b_in_32b(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -2217,12 +2212,12 @@ static void kpb_copy_24b_in_32b(const struct audio_stream __sparse_cache *source * * \return none. */ -static void kpb_copy_samples(struct comp_buffer __sparse_cache *sink, - struct comp_buffer __sparse_cache *source, size_t size, +static void kpb_copy_samples(struct comp_buffer *sink, + struct comp_buffer *source, size_t size, size_t sample_width, uint32_t channels) { - struct audio_stream __sparse_cache *istream = &source->stream; - struct audio_stream __sparse_cache *ostream = &sink->stream; + struct audio_stream *istream = &source->stream; + struct audio_stream *ostream = &sink->stream; unsigned int samples; buffer_stream_invalidate(source, size); @@ -2378,15 +2373,196 @@ static int kpb_set_micselect(struct comp_dev *dev, const void *data, return 0; } +#ifdef CONFIG_IPC_MAJOR_4 + +static int devicelist_push(struct device_list *devlist, struct comp_dev **dev) +{ + if (devlist->count != DEVICE_LIST_SIZE) { + devlist->devs[devlist->count] = dev; + devlist->count++; + return 0; + } + return -EINVAL; +} + +static void devicelist_reset(struct device_list *devlist, bool remove_items) +{ + /* clear items */ + if (remove_items) { + for (int i = 0; i < DEVICE_LIST_SIZE; i++) + *devlist->devs[i] = NULL; + } + /* zero the pointers */ + for (int i = 0; i < DEVICE_LIST_SIZE; i++) + devlist->devs[i] = NULL; + + devlist->count = 0; +} + +static inline int alloc_fmt_module_list_item(struct kpb_fmt_dev_list *fmt_device_list, + struct comp_dev *mi_ptr, struct comp_dev ***item) +{ + /* -1 means we did not find the slot yet */ + int first_empty_slot_idx = -1; + + for (size_t module_slot_idx = 0; module_slot_idx < FAST_MODE_TASK_MAX_MODULES_COUNT; + ++module_slot_idx){ + /* check if module already added */ + if (fmt_device_list->modules_list_item[module_slot_idx] == mi_ptr) + return -EINVAL; + /* finding first available empty slot */ + if (first_empty_slot_idx < 0 && + !fmt_device_list->modules_list_item[module_slot_idx]) + first_empty_slot_idx = module_slot_idx; + } + /* add item to first available empty slot */ + if (first_empty_slot_idx >= 0) { + fmt_device_list->modules_list_item[first_empty_slot_idx] = mi_ptr; + *item = &fmt_device_list->modules_list_item[first_empty_slot_idx]; + return 0; + } + return -ENOMEM; +} + +static int prepare_fmt_modules_list(struct comp_dev *kpb_dev, + uint32_t outpin_idx, + const struct kpb_task_params *modules_to_prepare) +{ + int ret; + struct comp_dev *dev; + struct kpb_fmt_dev_list *fmt_device_list = + &((struct comp_data *)comp_get_drvdata(kpb_dev))->fmt_device_list; + + fmt_device_list->kpb_list_item[outpin_idx] = kpb_dev; + ret = devicelist_push(&fmt_device_list->device_list[outpin_idx], + &fmt_device_list->kpb_list_item[outpin_idx]); + if (ret < 0) + return ret; + + for (size_t mod_idx = 0; mod_idx < modules_to_prepare->number_of_modules; ++mod_idx) { + uint32_t comp_id = IPC4_COMP_ID(modules_to_prepare->dev_ids[mod_idx].module_id, + modules_to_prepare->dev_ids[mod_idx].instance_id); + + dev = ipc4_get_comp_dev(comp_id); + if (!dev) + return -EINVAL; + + struct comp_dev **new_list_item_ptr; + + ret = alloc_fmt_module_list_item(fmt_device_list, dev, &new_list_item_ptr); + if (ret < 0) + return ret; + *new_list_item_ptr = dev; + ret = devicelist_push(&fmt_device_list->device_list[outpin_idx], + new_list_item_ptr); + if (ret < 0) + return ret; + } + return 0; +} + +static int clear_fmt_modules_list(struct kpb_fmt_dev_list *fmt_device_list, + uint32_t outpin_idx) +{ + if (outpin_idx >= KPB_MAX_SINK_CNT) + return -EINVAL; + + devicelist_reset(&fmt_device_list->device_list[outpin_idx], true); + return 0; +} + +static int unregister_modules_list(struct fast_mode_task *fmt, + struct device_list *list_to_remove, size_t list_idx) +{ + if (list_to_remove == fmt->device_list[list_idx]) { + fmt->device_list[list_idx] = NULL; + return 0; + } + if (!fmt->device_list[list_idx]) { + /* Nothing to do here */ + return 0; + } + return -EINVAL; +} + +/* Comment from Old FW, may be outdated: + * Important: function below should be called only from within critical section + * (Goto KPB for more details) + */ +static int register_modules_list(struct fast_mode_task *fmt, + struct device_list *new_list, size_t list_idx) +{ + if (list_idx >= ARRAY_SIZE(fmt->device_list)) + return -EINVAL; + + /* Check if slot is free */ + if (!fmt->device_list[list_idx]) { + fmt->device_list[list_idx] = new_list; + return 0; + } + if (new_list == fmt->device_list[list_idx]) { + /* Already registered. */ + return 0; + } + /* was ADSP_ALREADY_IN_USE */ + return -EINVAL; +} + +static int configure_fast_mode_task(struct comp_dev *kpb_dev, const struct kpb_task_params *cfg, + size_t pin) +{ + if (pin >= KPB_MAX_SINK_CNT || pin == REALTIME_PIN_ID || !cfg) + return -EINVAL; + + struct comp_data *priv_data = (struct comp_data *)comp_get_drvdata(kpb_dev); + int ret = unregister_modules_list(&priv_data->fmt, + &priv_data->fmt_device_list.device_list[pin], + pin); + if (ret) + return -EINVAL; + + ret = clear_fmt_modules_list(&priv_data->fmt_device_list, pin); + if (ret) + return -EINVAL; + + /* When modules count IS 0 we only need to remove modules from Fast Mode. */ + if (cfg->number_of_modules > 0) { + ret = prepare_fmt_modules_list(kpb_dev, pin, cfg); + if (!ret) + ret = register_modules_list(&priv_data->fmt, + &priv_data->fmt_device_list.device_list[pin], + pin); + } + return ret; +} +#endif + static int kpb_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, bool last_block, uint32_t data_offset, const char *data) { + /* We can use extended param id for both extended and standard param id */ + union ipc4_extended_param_id extended_param_id; + comp_info(dev, "kpb_set_large_config()"); - switch (param_id) { + extended_param_id.full = param_id; + + switch (extended_param_id.part.parameter_type) { +#ifdef CONFIG_IPC_MAJOR_4 + case KP_BUF_CFG_FM_MODULE: { + /* Modules count equals 0 is a special case in which we want to clear list for + * given pin. Reference FW also allowed for cfg/data to be NULL, but this is no + * longer the case. + */ + const struct kpb_task_params *cfg = (struct kpb_task_params *)data; + uint32_t outpin_id = extended_param_id.part.parameter_instance; + + return configure_fast_mode_task(dev, cfg, outpin_id); + } +#endif case KP_BUF_CLIENT_MIC_SELECT: return kpb_set_micselect(dev, data, data_offset); default: diff --git a/src/audio/mfcc/mfcc.c b/src/audio/mfcc/mfcc.c index b93e49dab743..109c3636a4a1 100644 --- a/src/audio/mfcc/mfcc.c +++ b/src/audio/mfcc/mfcc.c @@ -161,8 +161,8 @@ static int mfcc_process(struct processing_module *mod, struct output_stream_buffer *output_buffers, int num_output_buffers) { struct mfcc_comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = input_buffers->data; - struct audio_stream __sparse_cache *sink = output_buffers->data; + struct audio_stream *source = input_buffers->data; + struct audio_stream *sink = output_buffers->data; int frames = input_buffers->size; comp_dbg(mod->dev, "mfcc_process(), start"); @@ -187,14 +187,12 @@ static void mfcc_set_alignment(struct audio_stream *source, struct audio_stream } static int mfcc_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct mfcc_comp_data *cd = module_get_private_data(mod); struct comp_buffer *sourceb; struct comp_buffer *sinkb; - struct comp_buffer __sparse_cache *source_c; - struct comp_buffer __sparse_cache *sink_c; struct comp_dev *dev = mod->dev; enum sof_ipc_frame source_format; enum sof_ipc_frame sink_format; @@ -206,23 +204,21 @@ static int mfcc_prepare(struct processing_module *mod, /* MFCC component will only ever have 1 source and 1 sink buffer */ sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); /* get source data format */ - source_format = audio_stream_get_frm_fmt(&source_c->stream); + source_format = audio_stream_get_frm_fmt(&sourceb->stream); /* set align requirements */ - mfcc_set_alignment(&source_c->stream, &sink_c->stream); + mfcc_set_alignment(&sourceb->stream, &sinkb->stream); /* get sink data format and period bytes */ - sink_format = audio_stream_get_frm_fmt(&sink_c->stream); - sink_period_bytes = audio_stream_period_bytes(&sink_c->stream, dev->frames); + sink_format = audio_stream_get_frm_fmt(&sinkb->stream); + sink_period_bytes = audio_stream_period_bytes(&sinkb->stream, dev->frames); comp_info(dev, "mfcc_prepare(), source_format = %d, sink_format = %d", source_format, sink_format); - if (audio_stream_get_size(&sink_c->stream) < sink_period_bytes) { + if (audio_stream_get_size(&sinkb->stream) < sink_period_bytes) { comp_err(dev, "mfcc_prepare(): sink buffer size %d is insufficient < %d", - audio_stream_get_size(&sink_c->stream), sink_period_bytes); + audio_stream_get_size(&sinkb->stream), sink_period_bytes); ret = -ENOMEM; goto err; } @@ -231,8 +227,8 @@ static int mfcc_prepare(struct processing_module *mod, /* Initialize MFCC, max_frames is set to dev->frames + 4 */ if (cd->config) { - ret = mfcc_setup(mod, dev->frames + 4, audio_stream_get_rate(&source_c->stream), - audio_stream_get_channels(&source_c->stream)); + ret = mfcc_setup(mod, dev->frames + 4, audio_stream_get_rate(&sourceb->stream), + audio_stream_get_channels(&sourceb->stream)); if (ret < 0) { comp_err(dev, "mfcc_prepare(), setup failed."); goto err; @@ -246,13 +242,9 @@ static int mfcc_prepare(struct processing_module *mod, goto err; } - buffer_release(sink_c); - buffer_release(source_c); return 0; err: - buffer_release(sink_c); - buffer_release(source_c); comp_set_state(dev, COMP_TRIGGER_RESET); return ret; } @@ -268,14 +260,14 @@ static int mfcc_reset(struct processing_module *mod) return 0; } -static struct module_interface mfcc_interface = { - .init = mfcc_init, - .free = mfcc_free, - .set_configuration = mfcc_set_config, - .get_configuration = mfcc_get_config, - .process_audio_stream = mfcc_process, - .prepare = mfcc_prepare, - .reset = mfcc_reset, +static const struct module_interface mfcc_interface = { + .init = mfcc_init, + .free = mfcc_free, + .set_configuration = mfcc_set_config, + .get_configuration = mfcc_get_config, + .process_audio_stream = mfcc_process, + .prepare = mfcc_prepare, + .reset = mfcc_reset, }; DECLARE_MODULE_ADAPTER(mfcc_interface, mfcc_uuid, mfcc_tr); diff --git a/src/audio/mfcc/mfcc_common.c b/src/audio/mfcc/mfcc_common.c index 8ea1d7db4184..63ab84943669 100644 --- a/src/audio/mfcc/mfcc_common.c +++ b/src/audio/mfcc/mfcc_common.c @@ -143,7 +143,7 @@ static int mfcc_stft_process(const struct comp_dev *dev, struct mfcc_state *stat void mfcc_s16_default(struct processing_module *mod, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *sink = bsink->data; struct mfcc_comp_data *cd = module_get_private_data(mod); struct mfcc_state *state = &cd->state; struct mfcc_buffer *buf = &cd->state.buf; diff --git a/src/audio/mfcc/mfcc_generic.c b/src/audio/mfcc/mfcc_generic.c index 447b1382ce11..9384b16e0cee 100644 --- a/src/audio/mfcc/mfcc_generic.c +++ b/src/audio/mfcc/mfcc_generic.c @@ -27,7 +27,7 @@ void mfcc_source_copy_s16(struct input_stream_buffer *bsource, struct mfcc_buffer *buf, struct mfcc_pre_emph *emph, int frames, int source_channel) { - struct audio_stream __sparse_cache *source = bsource->data; + struct audio_stream *source = bsource->data; int32_t s; int16_t *x0; int16_t *x = audio_stream_get_rptr(source); diff --git a/src/audio/mfcc/mfcc_hifi3.c b/src/audio/mfcc/mfcc_hifi3.c index 6b274a58ae84..76f0a79da668 100644 --- a/src/audio/mfcc/mfcc_hifi3.c +++ b/src/audio/mfcc/mfcc_hifi3.c @@ -36,7 +36,7 @@ static inline void set_circular_buf0(const void *start, const void *end) void mfcc_source_copy_s16(struct input_stream_buffer *bsource, struct mfcc_buffer *buf, struct mfcc_pre_emph *emph, int frames, int source_channel) { - struct audio_stream __sparse_cache *source = bsource->data; + struct audio_stream *source = bsource->data; int copied; int nmax; int n; @@ -88,7 +88,7 @@ void mfcc_source_copy_s16(struct input_stream_buffer *bsource, struct mfcc_buffe } buf->s_avail += copied; buf->s_free -= copied; - buf->w_ptr = out; + buf->w_ptr = (int16_t *)out; } void mfcc_fill_prev_samples(struct mfcc_buffer *buf, int16_t *prev_data, @@ -121,7 +121,7 @@ void mfcc_fill_prev_samples(struct mfcc_buffer *buf, int16_t *prev_data, buf->s_avail -= prev_data_length; buf->s_free += prev_data_length; - buf->r_ptr = in; + buf->r_ptr = (void *)in; /* int16_t pointer but direct cast is not possible */ } void mfcc_fill_fft_buffer(struct mfcc_state *state) @@ -156,7 +156,7 @@ void mfcc_fill_fft_buffer(struct mfcc_state *state) buf->s_avail -= fft->fft_hop_size; buf->s_free += fft->fft_hop_size; - buf->r_ptr = in; + buf->r_ptr = (int16_t *)in; /* Copy for next time data back to overlap buffer */ idx = fft->fft_fill_start_idx + fft->fft_hop_size; diff --git a/src/audio/mfcc/mfcc_hifi4.c b/src/audio/mfcc/mfcc_hifi4.c index 4e8853a4903b..25df53b4ca06 100644 --- a/src/audio/mfcc/mfcc_hifi4.c +++ b/src/audio/mfcc/mfcc_hifi4.c @@ -42,7 +42,7 @@ static inline void set_circular_buf1(const void *start, const void *end) void mfcc_source_copy_s16(struct input_stream_buffer *bsource, struct mfcc_buffer *buf, struct mfcc_pre_emph *emph, int frames, int source_channel) { - struct audio_stream __sparse_cache *source = bsource->data; + struct audio_stream *source = bsource->data; int num_channels = audio_stream_get_channels(source); ae_int16 *in = (ae_int16 *)source->r_ptr + source_channel; ae_int16 *out = (ae_int16 *)buf->w_ptr; diff --git a/src/audio/mixer/mixer.c b/src/audio/mixer/mixer.c index 3dc6ee1407dc..fce964f4da1b 100644 --- a/src/audio/mixer/mixer.c +++ b/src/audio/mixer/mixer.c @@ -82,7 +82,7 @@ static int mixer_process(struct processing_module *mod, { struct mixer_data *md = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - const struct audio_stream __sparse_cache *sources_stream[PLATFORM_MAX_STREAMS]; + const struct audio_stream *sources_stream[PLATFORM_MAX_STREAMS]; int sources_indices[PLATFORM_MAX_STREAMS]; int32_t i = 0, j = 0; uint32_t frames = INT32_MAX; @@ -174,13 +174,11 @@ static int mixer_reset(struct processing_module *mod) /* FIXME: this is racy and implicitly protected by serialised IPCs */ struct comp_buffer *source = container_of(blist, struct comp_buffer, sink_list); - struct comp_buffer __sparse_cache *source_c = buffer_acquire(source); bool stop = false; - if (source_c->source && source_c->source->state > COMP_STATE_READY) + if (source->source && source->source->state > COMP_STATE_READY) stop = true; - buffer_release(source_c); /* only mix the sources with the same state with mixer */ if (stop) /* should not reset the downstream components */ @@ -194,7 +192,7 @@ static int mixer_reset(struct processing_module *mod) } /* init and calculate the aligned setting for available frames and free frames retrieve*/ -static inline void mixer_set_frame_alignment(struct audio_stream __sparse_cache *source) +static inline void mixer_set_frame_alignment(struct audio_stream *source) { #if XCHAL_HAVE_HIFI3 || XCHAL_HAVE_HIFI4 @@ -220,26 +218,22 @@ static inline void mixer_set_frame_alignment(struct audio_stream __sparse_cache } static int mixer_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct mixer_data *md = module_get_private_data(mod); - struct comp_buffer __sparse_cache *sink_c; struct comp_dev *dev = mod->dev; struct comp_buffer *sink; struct list_item *blist; sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - md->mix_func = mixer_get_processing_function(dev, sink_c); - mixer_set_frame_alignment(&sink_c->stream); - buffer_release(sink_c); + md->mix_func = mixer_get_processing_function(dev, sink); + mixer_set_frame_alignment(&sink->stream); /* check each mixer source state */ list_for_item(blist, &dev->bsource_list) { struct comp_buffer *source; - struct comp_buffer __sparse_cache *source_c; bool stop; /* @@ -251,11 +245,9 @@ static int mixer_prepare(struct processing_module *mod, * done. */ source = container_of(blist, struct comp_buffer, sink_list); - source_c = buffer_acquire(source); - mixer_set_frame_alignment(&source_c->stream); - stop = source_c->source && (source_c->source->state == COMP_STATE_PAUSED || - source_c->source->state == COMP_STATE_ACTIVE); - buffer_release(source_c); + mixer_set_frame_alignment(&source->stream); + stop = source->source && (source->source->state == COMP_STATE_PAUSED || + source->source->state == COMP_STATE_ACTIVE); /* only prepare downstream if we have no active sources */ if (stop) @@ -266,8 +258,8 @@ static int mixer_prepare(struct processing_module *mod, return 0; } -static struct module_interface mixer_interface = { - .init = mixer_init, +static const struct module_interface mixer_interface = { + .init = mixer_init, .prepare = mixer_prepare, .process_audio_stream = mixer_process, .reset = mixer_reset, diff --git a/src/audio/mixer/mixer_generic.c b/src/audio/mixer/mixer_generic.c index b8be3ecf63a1..0deabe2093a7 100644 --- a/src/audio/mixer/mixer_generic.c +++ b/src/audio/mixer/mixer_generic.c @@ -11,8 +11,8 @@ #if CONFIG_FORMAT_S16LE /* Mix n 16 bit PCM source streams to one sink stream */ -static void mix_n_s16(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, uint32_t num_sources, +static void mix_n_s16(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream **sources, uint32_t num_sources, uint32_t frames) { int16_t *src[PLATFORM_MAX_CHANNELS]; @@ -57,8 +57,8 @@ static void mix_n_s16(struct comp_dev *dev, struct audio_stream __sparse_cache * #if CONFIG_FORMAT_S24LE /* Mix n 24 bit PCM source streams to one sink stream */ -static void mix_n_s24(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, uint32_t num_sources, +static void mix_n_s24(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream **sources, uint32_t num_sources, uint32_t frames) { int32_t *src[PLATFORM_MAX_CHANNELS]; @@ -105,8 +105,8 @@ static void mix_n_s24(struct comp_dev *dev, struct audio_stream __sparse_cache * #if CONFIG_FORMAT_S32LE /* Mix n 32 bit PCM source streams to one sink stream */ -static void mix_n_s32(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, uint32_t num_sources, +static void mix_n_s32(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream **sources, uint32_t num_sources, uint32_t frames) { int32_t *src[PLATFORM_MAX_CHANNELS]; diff --git a/src/audio/mixer/mixer_hifi3.c b/src/audio/mixer/mixer_hifi3.c index 3147ce0a35b6..2bba6c213df6 100644 --- a/src/audio/mixer/mixer_hifi3.c +++ b/src/audio/mixer/mixer_hifi3.c @@ -13,8 +13,8 @@ #if CONFIG_FORMAT_S16LE /* Mix n 16 bit PCM source streams to one sink stream */ -static void mix_n_s16(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, uint32_t num_sources, +static void mix_n_s16(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream **sources, uint32_t num_sources, uint32_t frames) { ae_int16x4 * in[PLATFORM_MAX_CHANNELS]; @@ -69,8 +69,8 @@ static void mix_n_s16(struct comp_dev *dev, struct audio_stream __sparse_cache * #if CONFIG_FORMAT_S24LE /* Mix n 24 bit PCM source streams to one sink stream */ -static void mix_n_s24(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, uint32_t num_sources, +static void mix_n_s24(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream **sources, uint32_t num_sources, uint32_t frames) { ae_int32x2 *in[PLATFORM_MAX_CHANNELS]; @@ -114,8 +114,8 @@ static void mix_n_s24(struct comp_dev *dev, struct audio_stream __sparse_cache * #if CONFIG_FORMAT_S32LE /* Mix n 32 bit PCM source streams to one sink stream */ -static void mix_n_s32(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, uint32_t num_sources, +static void mix_n_s32(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream **sources, uint32_t num_sources, uint32_t frames) { ae_q32s * in[PLATFORM_MAX_CHANNELS]; diff --git a/src/audio/mixin_mixout/mixin_mixout.c b/src/audio/mixin_mixout/mixin_mixout.c index 78d69223de56..ba3184c66e12 100644 --- a/src/audio/mixin_mixout/mixin_mixout.c +++ b/src/audio/mixin_mixout/mixin_mixout.c @@ -79,10 +79,22 @@ struct mixin_data { struct mixin_sink_config sink_config[MIXIN_MAX_SINKS]; }; -/* mixout component private data. This can be accessed from different cores. */ +/* + * Mixin calls "consume" on its source data but never calls "produce" -- that one is called + * by mixout for its sink data. So between mixin_process() and mixout_process() a number of + * consumed (in mixin) yet not produced (in mixout) frames should be stored for each mixin + * and mixout pair. + */ +struct pending_frames { + struct comp_dev *mixin; + uint32_t frames; +}; + +/* mixout component private data */ struct mixout_data { /* number of currently mixed frames in mixout sink buffer */ uint32_t mixed_frames; + /* * Source data is consumed by mixins in mixin_process() but sink data cannot be * immediately produced. Sink data is produced by mixout in mixout_process() after @@ -90,9 +102,22 @@ struct mixout_data { * So for each connected mixin, mixout keeps knowledge of data already consumed * by mixin but not yet produced in mixout. */ - uint32_t pending_frames[MIXOUT_MAX_SOURCES]; + struct pending_frames pending_frames[MIXOUT_MAX_SOURCES]; }; +/* NULL is also a valid mixin argument: in such case the function returns first unused entry */ +static struct pending_frames *get_mixin_pending_frames(struct mixout_data *mixout_data, + const struct comp_dev *mixin) +{ + int i; + + for (i = 0; i < MIXOUT_MAX_SOURCES; i++) + if (mixout_data->pending_frames[i].mixin == mixin) + return &mixout_data->pending_frames[i]; + + return NULL; +} + static int mixin_init(struct processing_module *mod) { struct module_data *mod_data = &mod->priv; @@ -121,7 +146,6 @@ static int mixin_init(struct processing_module *mod) static int mixout_init(struct processing_module *mod) { - struct module_source_info __sparse_cache *mod_source_info; struct comp_dev *dev = mod->dev; struct mixout_data *mo_data; @@ -131,9 +155,7 @@ static int mixout_init(struct processing_module *mod) if (!mo_data) return -ENOMEM; - mod_source_info = module_source_info_acquire(mod->source_info); - mod_source_info->private = mo_data; - module_source_info_release(mod_source_info); + mod->priv.private = mo_data; mod->skip_sink_buffer_writeback = true; @@ -154,22 +176,16 @@ static int mixin_free(struct processing_module *mod) static int mixout_free(struct processing_module *mod) { - struct module_source_info __sparse_cache *mod_source_info; - comp_dbg(mod->dev, "mixout_free()"); - - mod_source_info = module_source_info_acquire(mod->source_info); - rfree(mod_source_info->private); - mod_source_info->private = NULL; - module_source_info_release(mod_source_info); + rfree(module_get_private_data(mod)); return 0; } static int mix_and_remap(struct comp_dev *dev, const struct mixin_data *mixin_data, - uint16_t sink_index, struct audio_stream __sparse_cache *sink, + uint16_t sink_index, struct audio_stream *sink, uint32_t start_frame, uint32_t mixed_frames, - const struct audio_stream __sparse_cache *source, uint32_t frame_count) + const struct audio_stream *source, uint32_t frame_count) { const struct mixin_sink_config *sink_config; @@ -197,7 +213,7 @@ static int mix_and_remap(struct comp_dev *dev, const struct mixin_data *mixin_da } /* mix silence into stream, i.e. set not yet mixed data in stream to zero */ -static void silence(struct audio_stream __sparse_cache *stream, uint32_t start_frame, +static void silence(struct audio_stream *stream, uint32_t start_frame, uint32_t mixed_frames, uint32_t frame_count) { uint32_t skip_mixed_frames; @@ -236,9 +252,9 @@ static void silence(struct audio_stream __sparse_cache *stream, uint32_t start_f * Since there is no garantie that mixout processing is done in time we have * to account for a possibility having not yet produced data in mixout sink * buffer that was written there on previous run(s) of mixin_process(). So for each - * mixin <--> mixout pair we track consumed_yet_not_produced data amount. - * That value is also used in mixout_process() to calculate how many data was - * actually mixed and so xxx_produce() is called for that amount. + * mixin <--> mixout pair we track consumed yet not produced (pending_frames) data + * amount. That value is also used in mixout_process() to calculate how many data + * was actually mixed and so xxx_produce() is called for that amount. */ static int mixin_process(struct processing_module *mod, struct input_stream_buffer *input_buffers, int num_input_buffers, @@ -251,7 +267,7 @@ static int mixin_process(struct processing_module *mod, uint16_t sinks_ids[MIXIN_MAX_SINKS]; uint32_t bytes_to_consume_from_source_buf; uint32_t frames_to_copy; - int source_index; + struct pending_frames *pending_frames; int i, ret; comp_dbg(dev, "mixin_process()"); @@ -274,20 +290,17 @@ static int mixin_process(struct processing_module *mod, * and frames free in each connected mixout sink buffer. */ for (i = 0; i < num_output_buffers; i++) { - struct comp_buffer __sparse_cache *unused_in_between_buf_c; + struct comp_buffer *unused_in_between_buf_c; struct comp_dev *mixout; uint16_t sink_id; struct comp_buffer *sink; struct mixout_data *mixout_data; struct processing_module *mixout_mod; - struct module_source_info __sparse_cache *mod_source_info; - struct comp_buffer __sparse_cache *sink_c; - uint32_t free_frames, pending_frames; + uint32_t free_frames; /* unused buffer between mixin and mixout */ - unused_in_between_buf_c = attr_container_of(output_buffers[i].data, - struct comp_buffer __sparse_cache, - stream, __sparse_cache); + unused_in_between_buf_c = container_of(output_buffers[i].data, + struct comp_buffer, stream); mixout = unused_in_between_buf_c->sink; sink_id = IPC4_SRC_QUEUE_ID(unused_in_between_buf_c->id); @@ -297,53 +310,42 @@ static int mixin_process(struct processing_module *mod, sink = list_first_item(&mixout->bsink_list, struct comp_buffer, source_list); mixout_mod = comp_get_drvdata(mixout); - mod_source_info = module_source_info_acquire(mixout_mod->source_info); - mixout_data = mod_source_info->private; - source_index = find_module_source_index(mod_source_info, dev); - if (source_index < 0) { + mixout_data = module_get_private_data(mixout_mod); + pending_frames = get_mixin_pending_frames(mixout_data, dev); + if (!pending_frames) { comp_err(dev, "No source info"); - module_source_info_release(mod_source_info); return -EINVAL; } - sink_c = buffer_acquire(sink); - /* Normally this should never happen as we checked above * that mixout is in active state and so its sink buffer * should be already initialized in mixout .params(). */ - if (!sink_c->hw_params_configured) { + if (!sink->hw_params_configured) { comp_err(dev, "Uninitialized mixout sink buffer!"); - buffer_release(sink_c); - module_source_info_release(mod_source_info); return -EINVAL; } - free_frames = audio_stream_get_free_frames(&sink_c->stream); + free_frames = audio_stream_get_free_frames(&sink->stream); /* mixout sink buffer may still have not yet produced data -- data * consumed and written there by mixin on previous mixin_process() run. * We do NOT want to overwrite that data. */ - pending_frames = mixout_data->pending_frames[source_index]; - assert(free_frames >= pending_frames); - sinks_free_frames = MIN(sinks_free_frames, free_frames - pending_frames); - - buffer_release(sink_c); - module_source_info_release(mod_source_info); + assert(free_frames >= pending_frames->frames); + sinks_free_frames = MIN(sinks_free_frames, free_frames - pending_frames->frames); } if (source_avail_frames > 0) { - struct comp_buffer __sparse_cache *source_c; + struct comp_buffer *source_c; frames_to_copy = MIN(source_avail_frames, sinks_free_frames); bytes_to_consume_from_source_buf = audio_stream_period_bytes(input_buffers[0].data, frames_to_copy); if (bytes_to_consume_from_source_buf > 0) { input_buffers[0].consumed = bytes_to_consume_from_source_buf; - source_c = attr_container_of(input_buffers[0].data, - struct comp_buffer __sparse_cache, - stream, __sparse_cache); + source_c = container_of(input_buffers[0].data, struct comp_buffer, + stream); buffer_stream_invalidate(source_c, bytes_to_consume_from_source_buf); } } else { @@ -360,22 +362,18 @@ static int mixin_process(struct processing_module *mod, struct comp_dev *mixout; struct comp_buffer *sink; struct mixout_data *mixout_data; - struct module_source_info __sparse_cache *mod_source_info; struct processing_module *mixout_mod; uint32_t start_frame; - struct comp_buffer __sparse_cache *sink_c; uint32_t writeback_size; mixout = active_mixouts[i]; sink = list_first_item(&mixout->bsink_list, struct comp_buffer, source_list); mixout_mod = comp_get_drvdata(mixout); - mod_source_info = module_source_info_acquire(mixout_mod->source_info); - mixout_data = mod_source_info->private; - source_index = find_module_source_index(mod_source_info, dev); - if (source_index < 0) { + mixout_data = module_get_private_data(mixout_mod); + pending_frames = get_mixin_pending_frames(mixout_data, dev); + if (!pending_frames) { comp_err(dev, "No source info"); - module_source_info_release(mod_source_info); return -EINVAL; } @@ -383,28 +381,24 @@ static int mixin_process(struct processing_module *mod, * Normally start_frame would be 0 unless mixout pipeline has serious * performance problems with processing data on time in mixout. */ - start_frame = mixout_data->pending_frames[source_index]; - - sink_c = buffer_acquire(sink); + start_frame = pending_frames->frames; /* if source does not produce any data but mixin is in active state -- generate * silence instead of that source data */ if (source_avail_frames == 0) { /* generate silence */ - silence(&sink_c->stream, start_frame, mixout_data->mixed_frames, + silence(&sink->stream, start_frame, mixout_data->mixed_frames, frames_to_copy); } else { /* basically, if sink buffer has no data -- copy source data there, if * sink buffer has some data (written by another mixin) mix that data * with source data. */ - ret = mix_and_remap(dev, mixin_data, sinks_ids[i], &sink_c->stream, + ret = mix_and_remap(dev, mixin_data, sinks_ids[i], &sink->stream, start_frame, mixout_data->mixed_frames, input_buffers[0].data, frames_to_copy); if (ret < 0) { - buffer_release(sink_c); - module_source_info_release(mod_source_info); return ret; } } @@ -413,18 +407,15 @@ static int mixin_process(struct processing_module *mod, * of frames_to_copy size (converted to bytes, of course). However, seems * there is no appropreate API. Anyway, start_frame would be 0 most of the time. */ - writeback_size = audio_stream_period_bytes(&sink_c->stream, + writeback_size = audio_stream_period_bytes(&sink->stream, frames_to_copy + start_frame); if (writeback_size > 0) - buffer_stream_writeback(sink_c, writeback_size); - buffer_release(sink_c); + buffer_stream_writeback(sink, writeback_size); - mixout_data->pending_frames[source_index] += frames_to_copy; + pending_frames->frames += frames_to_copy; if (frames_to_copy + start_frame > mixout_data->mixed_frames) mixout_data->mixed_frames = frames_to_copy + start_frame; - - module_source_info_release(mod_source_info); } return 0; @@ -437,71 +428,60 @@ static int mixout_process(struct processing_module *mod, struct input_stream_buffer *input_buffers, int num_input_buffers, struct output_stream_buffer *output_buffers, int num_output_buffers) { - struct module_source_info __sparse_cache *mod_source_info; struct comp_dev *dev = mod->dev; struct mixout_data *md; uint32_t frames_to_produce = INT32_MAX; - uint32_t pending_frames; + struct pending_frames *pending_frames; uint32_t sink_bytes; int i; comp_dbg(dev, "mixout_process()"); - mod_source_info = module_source_info_acquire(mod->source_info); - md = mod_source_info->private; + md = module_get_private_data(mod); /* iterate over all connected mixins to find minimal value of frames they consumed * (i.e., mixed into mixout sink buffer). That is the amount that can/should be * produced now. */ for (i = 0; i < num_input_buffers; i++) { - const struct audio_stream __sparse_cache *source_stream; - struct comp_buffer __sparse_cache *unused_in_between_buf; + const struct audio_stream *source_stream; + struct comp_buffer *unused_in_between_buf; struct comp_dev *source; - int source_index; source_stream = input_buffers[i].data; - unused_in_between_buf = attr_container_of(source_stream, - struct comp_buffer __sparse_cache, - stream, __sparse_cache); + unused_in_between_buf = container_of(source_stream, struct comp_buffer, + stream); source = unused_in_between_buf->source; - source_index = find_module_source_index(mod_source_info, source); - /* this shouldn't happen but skip even if it does and move to the next source */ - if (source_index < 0) + pending_frames = get_mixin_pending_frames(md, source); + if (!pending_frames) continue; - pending_frames = md->pending_frames[source_index]; - - if (source->state == COMP_STATE_ACTIVE || pending_frames) - frames_to_produce = MIN(frames_to_produce, pending_frames); + if (source->state == COMP_STATE_ACTIVE || pending_frames->frames) + frames_to_produce = MIN(frames_to_produce, pending_frames->frames); } if (frames_to_produce > 0 && frames_to_produce < INT32_MAX) { for (i = 0; i < num_input_buffers; i++) { - const struct audio_stream __sparse_cache *source_stream; - struct comp_buffer __sparse_cache *unused_in_between_buf; + const struct audio_stream *source_stream; + struct comp_buffer *unused_in_between_buf; struct comp_dev *source; - int source_index; - uint32_t pending_frames; source_stream = input_buffers[i].data; - unused_in_between_buf = attr_container_of(source_stream, - struct comp_buffer __sparse_cache, - stream, __sparse_cache); + unused_in_between_buf = container_of(source_stream, + struct comp_buffer, stream); source = unused_in_between_buf->source; - source_index = find_module_source_index(mod_source_info, source); - if (source_index < 0) + pending_frames = get_mixin_pending_frames(md, source); + if (!pending_frames) continue; - pending_frames = md->pending_frames[source_index]; - if (pending_frames >= frames_to_produce) - md->pending_frames[source_index] -= frames_to_produce; + if (pending_frames->frames >= frames_to_produce) + pending_frames->frames -= frames_to_produce; else - md->pending_frames[source_index] = 0; + pending_frames->frames = 0; } assert(md->mixed_frames >= frames_to_produce); @@ -518,8 +498,6 @@ static int mixout_process(struct processing_module *mod, output_buffers[0].size = 0; } - module_source_info_release(mod_source_info); - return 0; } @@ -547,15 +525,12 @@ static int mixout_reset(struct processing_module *mod) if (dev->pipeline->source_comp->direction == SOF_IPC_STREAM_PLAYBACK) { list_for_item(blist, &dev->bsource_list) { struct comp_buffer *source; - struct comp_buffer __sparse_cache *source_c; bool stop; /* FIXME: this is racy and implicitly protected by serialised IPCs */ source = container_of(blist, struct comp_buffer, sink_list); - source_c = buffer_acquire(source); - stop = (dev->pipeline == source_c->source->pipeline && - source_c->source->state > COMP_STATE_PAUSED); - buffer_release(source_c); + stop = (dev->pipeline == source->source->pipeline && + source->source->state > COMP_STATE_PAUSED); if (stop) /* should not reset the downstream components */ @@ -584,28 +559,25 @@ static int mixin_params(struct processing_module *mod) */ list_for_item(blist, &dev->bsink_list) { struct comp_buffer *sink; - struct comp_buffer __sparse_cache *sink_c; enum sof_ipc_frame frame_fmt, valid_fmt; uint16_t sink_id; sink = buffer_from_list(blist, PPL_DIR_DOWNSTREAM); - sink_c = buffer_acquire(sink); - audio_stream_set_channels(&sink_c->stream, + audio_stream_set_channels(&sink->stream, mod->priv.cfg.base_cfg.audio_fmt.channels_count); /* Applying channel remapping may produce sink stream with channel count * different from source channel count. */ - sink_id = IPC4_SRC_QUEUE_ID(sink_c->id); + sink_id = IPC4_SRC_QUEUE_ID(sink->id); if (sink_id >= MIXIN_MAX_SINKS) { comp_err(dev, "Sink index out of range: %u, max sink count: %u", (uint32_t)sink_id, MIXIN_MAX_SINKS); - buffer_release(sink_c); return -EINVAL; } if (md->sink_config[sink_id].mixer_mode == IPC4_MIXER_CHANNEL_REMAPPING_MODE) - audio_stream_set_channels(&sink_c->stream, + audio_stream_set_channels(&sink->stream, md->sink_config[sink_id].output_channel_count); /* comp_verify_params() does not modify valid_sample_fmt (a BUG?), @@ -616,10 +588,8 @@ static int mixin_params(struct processing_module *mod) &frame_fmt, &valid_fmt, mod->priv.cfg.base_cfg.audio_fmt.s_type); - audio_stream_set_frm_fmt(&sink_c->stream, frame_fmt); - audio_stream_set_valid_fmt(&sink_c->stream, valid_fmt); - - buffer_release(sink_c); + audio_stream_set_frm_fmt(&sink->stream, frame_fmt); + audio_stream_set_valid_fmt(&sink->stream, valid_fmt); } /* use BUFF_PARAMS_CHANNELS to skip updating channel count */ @@ -641,13 +611,12 @@ static int mixin_params(struct processing_module *mod) * if downstream is not currently active. */ static int mixin_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct mixin_data *md = module_get_private_data(mod); struct comp_dev *dev = mod->dev; struct comp_buffer *sink; - struct comp_buffer __sparse_cache *sink_c; enum sof_ipc_frame fmt; int ret; @@ -658,9 +627,7 @@ static int mixin_prepare(struct processing_module *mod, return ret; sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - fmt = audio_stream_get_valid_fmt(&sink_c->stream); - buffer_release(sink_c); + fmt = audio_stream_get_valid_fmt(&sink->stream); /* currently inactive so setup mixer */ switch (fmt) { @@ -687,7 +654,6 @@ static int mixout_params(struct processing_module *mod) { struct sof_ipc_stream_params *params = mod->stream_params; struct comp_buffer *sink; - struct comp_buffer __sparse_cache *sink_c; struct comp_dev *dev = mod->dev; enum sof_ipc_frame frame_fmt, valid_fmt; uint32_t sink_period_bytes, sink_stream_size; @@ -704,7 +670,6 @@ static int mixout_params(struct processing_module *mod) } sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); /* comp_verify_params() does not modify valid_sample_fmt (a BUG?), let's do this here */ audio_stream_fmt_conversion(mod->priv.cfg.base_cfg.audio_fmt.depth, @@ -712,15 +677,14 @@ static int mixout_params(struct processing_module *mod) &frame_fmt, &valid_fmt, mod->priv.cfg.base_cfg.audio_fmt.s_type); - audio_stream_set_valid_fmt(&sink_c->stream, valid_fmt); - audio_stream_set_channels(&sink_c->stream, params->channels); + audio_stream_set_valid_fmt(&sink->stream, valid_fmt); + audio_stream_set_channels(&sink->stream, params->channels); - sink_stream_size = audio_stream_get_size(&sink_c->stream); + sink_stream_size = audio_stream_get_size(&sink->stream); /* calculate period size based on config */ - sink_period_bytes = audio_stream_period_bytes(&sink_c->stream, + sink_period_bytes = audio_stream_period_bytes(&sink->stream, dev->frames); - buffer_release(sink_c); if (sink_period_bytes == 0) { comp_err(dev, "mixout_params(): period_bytes = 0"); @@ -737,10 +701,9 @@ static int mixout_params(struct processing_module *mod) } static int mixout_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { - struct module_source_info __sparse_cache *mod_source_info; struct comp_dev *dev = mod->dev; struct mixout_data *md; int ret, i; @@ -755,13 +718,95 @@ static int mixout_prepare(struct processing_module *mod, * Since mixout sink buffer stream is reset on .prepare(), let's * reset counters for not yet produced frames in that buffer. */ - mod_source_info = module_source_info_acquire(mod->source_info); - md = mod_source_info->private; + md = module_get_private_data(mod); md->mixed_frames = 0; for (i = 0; i < MIXOUT_MAX_SOURCES; i++) - md->pending_frames[i] = 0; - module_source_info_release(mod_source_info); + md->pending_frames[i].frames = 0; + + return 0; +} + +int mixout_bind(struct processing_module *mod, void *data) +{ + struct ipc4_module_bind_unbind *bu; + struct comp_dev *mixin; + struct pending_frames *pending_frames; + int src_id; + struct mixout_data *mixout_data; + + comp_dbg(mod->dev, "mixout_bind() %p", data); + + bu = (struct ipc4_module_bind_unbind *)data; + src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); + + /* we are only interested in bind for mixin -> mixout pair */ + if (mod->dev->ipc_config.id == src_id) + return 0; + + mixin = ipc4_get_comp_dev(src_id); + if (!mixin) { + comp_err(mod->dev, "mixout_bind: no mixin with ID %d found", src_id); + return -EINVAL; + } + + mixout_data = module_get_private_data(mod); + + pending_frames = get_mixin_pending_frames(mixout_data, mixin); + /* + * this should never happen as pending_frames info for a particular mixin and mixout pair + * should have been already cleared in mixout_unbind() + */ + if (pending_frames) { + pending_frames->mixin = NULL; + pending_frames->frames = 0; + } + + /* find an empty slot in the pending_frames array */ + pending_frames = get_mixin_pending_frames(mixout_data, NULL); + if (!pending_frames) { + /* no free slot in pending_frames array */ + comp_err(mod->dev, "Too many inputs!"); + return -ENOMEM; + } + + pending_frames->frames = 0; + pending_frames->mixin = mixin; + + return 0; +} + +int mixout_unbind(struct processing_module *mod, void *data) +{ + struct ipc4_module_bind_unbind *bu; + struct comp_dev *mixin; + struct pending_frames *pending_frames; + int src_id; + struct mixout_data *mixout_data; + + comp_dbg(mod->dev, "mixout_unbind()"); + + bu = (struct ipc4_module_bind_unbind *)data; + src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); + + /* we are only interested in unbind for mixin -> mixout pair */ + if (mod->dev->ipc_config.id == src_id) + return 0; + + mixin = ipc4_get_comp_dev(src_id); + if (!mixin) { + comp_err(mod->dev, "mixout_bind: no mixin with ID %d found", src_id); + return -EINVAL; + } + + mixout_data = module_get_private_data(mod); + + /* remove mixin from pending_frames array */ + pending_frames = get_mixin_pending_frames(mixout_data, mixin); + if (pending_frames) { + pending_frames->mixin = NULL; + pending_frames->frames = 0; + } return 0; } @@ -856,8 +901,8 @@ static int mixin_set_config(struct processing_module *mod, uint32_t config_id, return 0; } -static struct module_interface mixin_interface = { - .init = mixin_init, +static const struct module_interface mixin_interface = { + .init = mixin_init, .prepare = mixin_prepare, .process_audio_stream = mixin_process, .set_configuration = mixin_set_config, @@ -868,12 +913,14 @@ static struct module_interface mixin_interface = { DECLARE_MODULE_ADAPTER(mixin_interface, mixin_uuid, mixin_tr); SOF_MODULE_INIT(mixin, sys_comp_module_mixin_interface_init); -static struct module_interface mixout_interface = { - .init = mixout_init, +static const struct module_interface mixout_interface = { + .init = mixout_init, .prepare = mixout_prepare, .process_audio_stream = mixout_process, .reset = mixout_reset, - .free = mixout_free + .free = mixout_free, + .bind = mixout_bind, + .unbind = mixout_unbind }; DECLARE_MODULE_ADAPTER(mixout_interface, mixout_uuid, mixout_tr); diff --git a/src/audio/mixin_mixout/mixin_mixout_generic.c b/src/audio/mixin_mixout/mixin_mixout_generic.c index 75468fdb4d67..a99788be32bc 100644 --- a/src/audio/mixin_mixout/mixin_mixout_generic.c +++ b/src/audio/mixin_mixout/mixin_mixout_generic.c @@ -17,9 +17,9 @@ * parameters: multichannel stream is treated as single channel and so the entire stream * contents is mixed. */ -static void normal_mix_channel_s16(struct audio_stream __sparse_cache *sink, int32_t start_frame, +static void normal_mix_channel_s16(struct audio_stream *sink, int32_t start_frame, int32_t mixed_frames, - const struct audio_stream __sparse_cache *source, + const struct audio_stream *source, int32_t frame_count, uint16_t gain) { int32_t frames_to_mix, frames_to_copy, left_frames; @@ -61,7 +61,7 @@ static void normal_mix_channel_s16(struct audio_stream __sparse_cache *sink, int } } -static void mute_channel_s16(struct audio_stream __sparse_cache *stream, int32_t channel_index, +static void mute_channel_s16(struct audio_stream *stream, int32_t channel_index, int32_t start_frame, int32_t mixed_frames, int32_t frame_count) { int32_t skip_mixed_frames, n, left_frames, i, channel_count, frames, samples; @@ -101,9 +101,9 @@ static void mute_channel_s16(struct audio_stream __sparse_cache *stream, int32_t * parameters: multichannel stream is treated as single channel and so the entire stream * contents is mixed. */ -static void normal_mix_channel_s24(struct audio_stream __sparse_cache *sink, int32_t start_frame, +static void normal_mix_channel_s24(struct audio_stream *sink, int32_t start_frame, int32_t mixed_frames, - const struct audio_stream __sparse_cache *source, + const struct audio_stream *source, int32_t frame_count, uint16_t gain) { int32_t frames_to_mix, frames_to_copy, left_frames; @@ -153,9 +153,9 @@ static void normal_mix_channel_s24(struct audio_stream __sparse_cache *sink, int * parameters: multichannel stream is treated as single channel and so the entire stream * contents is mixed. */ -static void normal_mix_channel_s32(struct audio_stream __sparse_cache *sink, int32_t start_frame, +static void normal_mix_channel_s32(struct audio_stream *sink, int32_t start_frame, int32_t mixed_frames, - const struct audio_stream __sparse_cache *source, + const struct audio_stream *source, int32_t frame_count, uint16_t gain) { int32_t frames_to_mix, frames_to_copy, left_frames; @@ -198,7 +198,7 @@ static void normal_mix_channel_s32(struct audio_stream __sparse_cache *sink, int #endif /* CONFIG_FORMAT_S32LE */ #if CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S24LE -static void mute_channel_s32(struct audio_stream __sparse_cache *stream, int32_t channel_index, +static void mute_channel_s32(struct audio_stream *stream, int32_t channel_index, int32_t start_frame, int32_t mixed_frames, int32_t frame_count) { int32_t skip_mixed_frames, left_frames, n, channel_count, i, frames, samples; diff --git a/src/audio/mixin_mixout/mixin_mixout_hifi3.c b/src/audio/mixin_mixout/mixin_mixout_hifi3.c index 3fb46f2b74f6..93905a5d80af 100644 --- a/src/audio/mixin_mixout/mixin_mixout_hifi3.c +++ b/src/audio/mixin_mixout/mixin_mixout_hifi3.c @@ -16,9 +16,9 @@ * parameters: multichannel stream is treated as single channel and so the entire stream * contents is mixed. */ -static void normal_mix_channel_s16(struct audio_stream __sparse_cache *sink, int32_t start_frame, +static void normal_mix_channel_s16(struct audio_stream *sink, int32_t start_frame, int32_t mixed_frames, - const struct audio_stream __sparse_cache *source, + const struct audio_stream *source, int32_t frame_count, uint16_t gain) { int frames_to_mix, frames_to_copy, left_frames; @@ -104,7 +104,7 @@ static void normal_mix_channel_s16(struct audio_stream __sparse_cache *sink, int } } -static void mute_channel_s16(struct audio_stream __sparse_cache *stream, int32_t channel_index, +static void mute_channel_s16(struct audio_stream *stream, int32_t channel_index, int32_t start_frame, int32_t mixed_frames, int32_t frame_count) { int skip_mixed_frames, left_frames; @@ -140,9 +140,9 @@ static void mute_channel_s16(struct audio_stream __sparse_cache *stream, int32_t * parameters: multichannel stream is treated as single channel and so the entire stream * contents is mixed. */ -static void normal_mix_channel_s24(struct audio_stream __sparse_cache *sink, int32_t start_frame, +static void normal_mix_channel_s24(struct audio_stream *sink, int32_t start_frame, int32_t mixed_frames, - const struct audio_stream __sparse_cache *source, + const struct audio_stream *source, int32_t frame_count, uint16_t gain) { int frames_to_mix, frames_to_copy, left_frames; @@ -230,9 +230,9 @@ static void normal_mix_channel_s24(struct audio_stream __sparse_cache *sink, int * parameters: multichannel stream is treated as single channel and so the entire stream * contents is mixed. */ -static void normal_mix_channel_s32(struct audio_stream __sparse_cache *sink, int32_t start_frame, +static void normal_mix_channel_s32(struct audio_stream *sink, int32_t start_frame, int32_t mixed_frames, - const struct audio_stream __sparse_cache *source, + const struct audio_stream *source, int32_t frame_count, uint16_t gain) { int frames_to_mix, frames_to_copy, left_frames; @@ -315,7 +315,7 @@ static void normal_mix_channel_s32(struct audio_stream __sparse_cache *sink, int #endif /* CONFIG_FORMAT_S32LE */ #if CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S24LE -static void mute_channel_s32(struct audio_stream __sparse_cache *stream, int32_t channel_index, +static void mute_channel_s32(struct audio_stream *stream, int32_t channel_index, int32_t start_frame, int32_t mixed_frames, int32_t frame_count) { int skip_mixed_frames, left_frames; diff --git a/src/audio/module_adapter/CMakeLists.txt b/src/audio/module_adapter/CMakeLists.txt index e803f78ba91a..72dc1492b3ff 100644 --- a/src/audio/module_adapter/CMakeLists.txt +++ b/src/audio/module_adapter/CMakeLists.txt @@ -1,9 +1,13 @@ # SPDX-License-Identifier: BSD-3-Clause -add_local_sources(sof module_adapter.c module/generic.c) +if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof module_adapter.c module_adapter_ipc3.c module/generic.c) +elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof module_adapter.c module_adapter_ipc4.c module/generic.c) +endif() -if((NOT CONFIG_LIBRARY) OR CONFIG_LIBRARY_STATIC) +if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) if(CONFIG_CADENCE_CODEC) add_local_sources(sof module/cadence.c) diff --git a/src/audio/module_adapter/Kconfig b/src/audio/module_adapter/Kconfig index 1bd6da3e5cf9..ba8370bf6f6e 100644 --- a/src/audio/module_adapter/Kconfig +++ b/src/audio/module_adapter/Kconfig @@ -150,86 +150,6 @@ if CADENCE_CODEC endif # Cadence - config COMP_VOLUME - bool "Volume component" - default y - depends on COMP_MODULE_ADAPTER - help - Select for Volume component - -if COMP_VOLUME - -config COMP_VOLUME_WINDOWS_FADE - bool "Windows Fade shape volume transitions support" - help - This option enables volume ramp shape that follows - power of 1.75. The shape is not linear, not logarithmic. - The power function uses a lookup table that consumes - 256 bytes. The topology must set volume ramp token to - SOF_VOLUME_WINDOWS_FADE for the volume instance to use - this ramp shape. - -config COMP_VOLUME_LINEAR_RAMP - bool "Linear ramp volume transitions support" - default y - depends on IPC_MAJOR_3 - help - This option enables volume linear ramp shape. - -config COMP_PEAK_VOL - bool "Report peak vol data to host" - default y - depends on IPC_MAJOR_4 - help - This option enables reporting to host peak vol regs. - See: struct ipc4_peak_volume_regs - -choice "PEAK_METER_UPDATE_PERIOD_CHOICE" - prompt "The periods(ms) of updating peak meter value" - default PEAK_METER_UPDATE_10MS - depends on COMP_PEAK_VOL - - config PEAK_METER_UPDATE_1MS - bool "1ms" - help - Update the peak meter value every 1ms - - config PEAK_METER_UPDATE_10MS - bool "10ms" - help - Update the peak meter value every 10ms - - config PEAK_METER_UPDATE_100MS - bool "100ms" - help - Update the peak meter value every 100ms - - config PEAK_METER_UPDATE_1000MS - bool "1000ms" - help - Update the peak meter value every 1000ms - endchoice - -config PEAK_METER_UPDATE_PERIOD - int - depends on COMP_PEAK_VOL - default 1 if PEAK_METER_UPDATE_1MS - default 10 if PEAK_METER_UPDATE_10MS - default 100 if PEAK_METER_UPDATE_100MS - default 1000 if PEAK_METER_UPDATE_1000MS - help - Decide which period of update the peak volume meter value - -config COMP_GAIN - bool "GAIN component" - default y - depends on IPC_MAJOR_4 - help - This option enables gain to change volume. It works - as peak volume without updating peak vol to host - -endif # volume - config PASSTHROUGH_CODEC bool "Passthrough codec" default n diff --git a/src/audio/module_adapter/iadk/module_initial_settings_concrete.cpp b/src/audio/module_adapter/iadk/module_initial_settings_concrete.cpp index 2460aaee51b3..bf8909d8b543 100644 --- a/src/audio/module_adapter/iadk/module_initial_settings_concrete.cpp +++ b/src/audio/module_adapter/iadk/module_initial_settings_concrete.cpp @@ -49,6 +49,9 @@ ModuleInitialSettingsConcrete::ModuleInitialSettingsConcrete(DwordArray const &c /* It shall contain BaseModuleCfg + BaseModuleCfgExt + */ /* optionally some InputPinFormat[] + OutputPinFormat[] data */ CompoundCfg const * unvalidated_compound_cfg = cfg_ipc_msg.dataAs(); + if (!unvalidated_compound_cfg) + return; + const size_t computed_msg_size = sizeof(CompoundCfg) - /* CompoundCfg already contains one InputPinFormat and diff --git a/src/audio/module_adapter/library/native_system_agent.c b/src/audio/module_adapter/library/native_system_agent.c index b2d798c14238..58c24fadf31a 100644 --- a/src/audio/module_adapter/library/native_system_agent.c +++ b/src/audio/module_adapter/library/native_system_agent.c @@ -30,9 +30,6 @@ void *native_system_agent_start(uint32_t *sys_service, native_sys_agent.log_handle = log_handle; void *system_agent_p = &native_sys_agent; - uint32_t **sys_service_p = &sys_service; - - *sys_service_p = (uint32_t *)(&native_sys_agent.system_service); native_create_instance_f ci = (native_create_instance_f)entry_point; diff --git a/src/audio/module_adapter/module/cadence.c b/src/audio/module_adapter/module/cadence.c index 9279ce3a430a..14a849cebe85 100644 --- a/src/audio/module_adapter/module/cadence.c +++ b/src/audio/module_adapter/module/cadence.c @@ -633,8 +633,8 @@ static int cadence_codec_init_process(struct processing_module *mod) } static int cadence_codec_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { int ret = 0, mem_tabs_size; struct comp_dev *dev = mod->dev; @@ -716,7 +716,6 @@ cadence_codec_process(struct processing_module *mod, struct output_stream_buffer *output_buffers, int num_output_buffers) { struct comp_buffer *local_buff; - struct comp_buffer __sparse_cache *buffer_c; struct comp_dev *dev = mod->dev; struct module_data *codec = &mod->priv; struct cadence_codec_data *cd = codec->private; @@ -747,9 +746,7 @@ cadence_codec_process(struct processing_module *mod, /* do not proceed with processing if not enough free space left in the local buffer */ local_buff = list_first_item(&mod->sink_buffer_list, struct comp_buffer, sink_list); - buffer_c = buffer_acquire(local_buff); - free_bytes = audio_stream_get_free(&buffer_c->stream); - buffer_release(buffer_c); + free_bytes = audio_stream_get_free(&local_buff->stream); if (free_bytes < output_bytes) return -ENOSPC; @@ -879,8 +876,8 @@ cadence_codec_set_configuration(struct processing_module *mod, uint32_t config_i return 0; } -static struct module_interface cadence_interface = { - .init = cadence_codec_init, +static const struct module_interface cadence_interface = { + .init = cadence_codec_init, .prepare = cadence_codec_prepare, .process_raw_data = cadence_codec_process, .set_configuration = cadence_codec_set_configuration, diff --git a/src/audio/module_adapter/module/dts/dts.c b/src/audio/module_adapter/module/dts/dts.c index 62415f38c660..01eb8063e70d 100644 --- a/src/audio/module_adapter/module/dts/dts.c +++ b/src/audio/module_adapter/module/dts/dts.c @@ -78,8 +78,7 @@ static int dts_effect_populate_buffer_configuration(struct comp_dev *dev, { struct comp_buffer *source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - struct comp_buffer __sparse_cache *source_c; - const struct audio_stream __sparse_cache *stream; + const struct audio_stream *stream; DtsSofInterfaceBufferLayout buffer_layout; DtsSofInterfaceBufferFormat buffer_format; unsigned int buffer_fmt, frame_fmt, rate, channels; @@ -89,16 +88,12 @@ static int dts_effect_populate_buffer_configuration(struct comp_dev *dev, if (!source) return -EINVAL; - source_c = buffer_acquire(source); - - stream = &source_c->stream; + stream = &source->stream; buffer_fmt = audio_stream_get_buffer_fmt(stream); frame_fmt = audio_stream_get_frm_fmt(stream); rate = audio_stream_get_rate(stream); channels = audio_stream_get_channels(stream); - buffer_release(source_c); - switch (buffer_fmt) { case SOF_IPC_BUFFER_INTERLEAVED: buffer_layout = DTS_SOF_INTERFACE_BUFFER_LAYOUT_INTERLEAVED; @@ -184,8 +179,8 @@ static int dts_codec_init(struct processing_module *mod) } static int dts_codec_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { int ret; struct comp_dev *dev = mod->dev; @@ -451,8 +446,8 @@ dts_codec_set_configuration(struct processing_module *mod, uint32_t config_id, return 0; } -static struct module_interface dts_interface = { - .init = dts_codec_init, +static const struct module_interface dts_interface = { + .init = dts_codec_init, .prepare = dts_codec_prepare, .process_raw_data = dts_codec_process, .set_configuration = dts_codec_set_configuration, diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 760652982245..3cba00e5b7bc 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -75,7 +75,7 @@ int module_load_config(struct comp_dev *dev, const void *cfg, size_t size) return ret; } -int module_init(struct processing_module *mod, struct module_interface *interface) +int module_init(struct processing_module *mod, const struct module_interface *interface) { int ret; struct module_data *md = &mod->priv; @@ -196,8 +196,8 @@ static int validate_config(struct module_config *cfg) } int module_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { int ret; struct module_data *md = &mod->priv; @@ -222,8 +222,7 @@ int module_prepare(struct processing_module *mod, * as it has been applied during the procedure - it is safe to * free it. */ - if (md->cfg.data) - rfree(md->cfg.data); + rfree(md->cfg.data); md->cfg.avail = false; md->cfg.data = NULL; @@ -283,8 +282,8 @@ int module_process_legacy(struct processing_module *mod, } int module_process_sink_src(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_dev *dev = mod->dev; @@ -520,3 +519,14 @@ int module_unbind(struct processing_module *mod, void *data) return md->ops->unbind(mod, data); return 0; } + +void module_update_buffer_position(struct input_stream_buffer *input_buffers, + struct output_stream_buffer *output_buffers, + uint32_t frames) +{ + struct audio_stream *source = input_buffers->data; + struct audio_stream *sink = output_buffers->data; + + input_buffers->consumed += audio_stream_frame_bytes(source) * frames; + output_buffers->size += audio_stream_frame_bytes(sink) * frames; +} diff --git a/src/audio/module_adapter/module/modules.c b/src/audio/module_adapter/module/modules.c index 865aa945baea..3a2fd29abd04 100644 --- a/src/audio/module_adapter/module/modules.c +++ b/src/audio/module_adapter/module/modules.c @@ -155,8 +155,8 @@ static int modules_init(struct processing_module *mod) * There is one assumption - all IADK modules utilize IPC4 protocol. */ static int modules_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_dev *dev = mod->dev; int ret = 0; @@ -375,8 +375,8 @@ static int modules_reset(struct processing_module *mod) } /* Processing Module Adapter API*/ -static struct module_interface interface = { - .init = modules_init, +static const struct module_interface interface = { + .init = modules_init, .prepare = modules_prepare, .process_raw_data = modules_process, .set_processing_mode = modules_set_processing_mode, diff --git a/src/audio/module_adapter/module/passthrough.c b/src/audio/module_adapter/module/passthrough.c index a7e41c04ff65..af8a7227f346 100644 --- a/src/audio/module_adapter/module/passthrough.c +++ b/src/audio/module_adapter/module/passthrough.c @@ -21,8 +21,8 @@ static int passthrough_codec_init(struct processing_module *mod) } static int passthrough_codec_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_dev *dev = mod->dev; struct module_data *codec = &mod->priv; @@ -116,8 +116,8 @@ static int passthrough_codec_free(struct processing_module *mod) return 0; } -static struct module_interface passthrough_interface = { - .init = passthrough_codec_init, +static const struct module_interface passthrough_interface = { + .init = passthrough_codec_init, .prepare = passthrough_codec_prepare, .process_raw_data = passthrough_codec_process, .reset = passthrough_codec_reset, diff --git a/src/audio/module_adapter/module/waves/waves.c b/src/audio/module_adapter/module/waves/waves.c index 570a68f27b82..ab178b022eb9 100644 --- a/src/audio/module_adapter/module/waves/waves.c +++ b/src/audio/module_adapter/module/waves/waves.c @@ -220,11 +220,8 @@ static int waves_effect_check(struct comp_dev *dev) source_list); struct comp_buffer *source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - struct comp_buffer __sparse_cache *source_c = buffer_acquire(source); - struct comp_buffer __sparse_cache *sink_c = buffer_acquire(sink); - const struct audio_stream __sparse_cache *src_fmt = &source_c->stream; - const struct audio_stream __sparse_cache *snk_fmt = &sink_c->stream; - int ret = 0; + const struct audio_stream *src_fmt = &source->stream; + const struct audio_stream *snk_fmt = &sink->stream; /* Init sink & source buffers */ comp_dbg(dev, "waves_effect_check() start"); @@ -235,66 +232,53 @@ static int waves_effect_check(struct comp_dev *dev) if (audio_stream_get_rate(src_fmt) != audio_stream_get_rate(snk_fmt)) { comp_err(dev, "waves_effect_check() source %d sink %d rate mismatch", audio_stream_get_rate(src_fmt), audio_stream_get_rate(snk_fmt)); - ret = -EINVAL; - goto out; + return -EINVAL; } /* upmix/downmix not supported */ if (audio_stream_get_channels(src_fmt) != audio_stream_get_channels(snk_fmt)) { comp_err(dev, "waves_effect_check() source %d sink %d channels mismatch", audio_stream_get_channels(src_fmt), audio_stream_get_channels(snk_fmt)); - ret = -EINVAL; - goto out; + return -EINVAL; } /* different frame format not supported */ if (audio_stream_get_frm_fmt(src_fmt) != audio_stream_get_frm_fmt(snk_fmt)) { comp_err(dev, "waves_effect_check() source %d sink %d sample format mismatch", audio_stream_get_frm_fmt(src_fmt), audio_stream_get_frm_fmt(snk_fmt)); - ret = -EINVAL; - goto out; + return -EINVAL; } /* different interleaving is not supported */ if (audio_stream_get_buffer_fmt(src_fmt) != audio_stream_get_buffer_fmt(snk_fmt)) { comp_err(dev, "waves_effect_check() source %d sink %d buffer format mismatch"); - ret = -EINVAL; - goto out; + return -EINVAL; } if (!format_is_supported(audio_stream_get_frm_fmt(src_fmt))) { comp_err(dev, "waves_effect_check() float samples not supported"); - ret = -EINVAL; - goto out; + return -EINVAL; } if (!layout_is_supported(audio_stream_get_buffer_fmt(src_fmt))) { comp_err(dev, "waves_effect_check() non interleaved format not supported"); - ret = -EINVAL; - goto out; + return -EINVAL; } if (!rate_is_supported(audio_stream_get_rate(src_fmt))) { comp_err(dev, "waves_effect_check() rate %d not supported", audio_stream_get_rate(src_fmt)); - ret = -EINVAL; - goto out; + return -EINVAL; } if (audio_stream_get_channels(src_fmt) != 2) { comp_err(dev, "waves_effect_check() channels %d not supported", audio_stream_get_channels(src_fmt)); - ret = -EINVAL; - goto out; + return -EINVAL; } comp_dbg(dev, "waves_effect_check() done"); - -out: - buffer_release(sink_c); - buffer_release(source_c); - - return ret; + return 0; } /* initializes MaxxEffect based on stream parameters */ @@ -303,17 +287,15 @@ static int waves_effect_init(struct processing_module *mod) struct comp_dev *dev = mod->dev; struct comp_buffer *source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - struct comp_buffer __sparse_cache *source_c = buffer_acquire(source); struct module_data *codec = &mod->priv; struct waves_codec_data *waves_codec = codec->private; - const struct audio_stream __sparse_cache *src_fmt = &source_c->stream; + const struct audio_stream *src_fmt = &source->stream; MaxxStatus_t status; MaxxBuffer_Format_t sample_format; MaxxBuffer_Layout_t buffer_format; int32_t sample_bytes; MaxxStreamFormat_t *i_formats[NUM_IO_STREAMS] = { &waves_codec->i_format }; MaxxStreamFormat_t *o_formats[NUM_IO_STREAMS] = { &waves_codec->o_format }; - int ret = 0; comp_dbg(dev, "waves_effect_init() start"); @@ -321,24 +303,21 @@ static int waves_effect_init(struct processing_module *mod) if (sample_format < 0) { comp_err(dev, "waves_effect_init() sof sample format %d not supported", audio_stream_get_frm_fmt(src_fmt)); - ret = -EINVAL; - goto out; + return -EINVAL; } buffer_format = layout_convert_sof_to_me(audio_stream_get_buffer_fmt(src_fmt)); if (buffer_format < 0) { comp_err(dev, "waves_effect_init() sof buffer format %d not supported", audio_stream_get_buffer_fmt(src_fmt)); - ret = -EINVAL; - goto out; + return -EINVAL; } sample_bytes = sample_format_convert_to_bytes(sample_format); if (sample_bytes < 0) { comp_err(dev, "waves_effect_init() sample_format %d not supported", sample_format); - ret = -EINVAL; - goto out; + return -EINVAL; } waves_codec->request_max_bytes = 0; @@ -373,16 +352,11 @@ static int waves_effect_init(struct processing_module *mod) if (status) { comp_err(dev, "waves_effect_init() MaxxEffect_Initialize returned %d", status); - ret = -EINVAL; - goto out; + return -EINVAL; } comp_dbg(dev, "waves_effect_init() done"); - -out: - buffer_release(source_c); - - return ret; + return 0; } /* allocate additional buffers for MaxxEffect */ @@ -686,8 +660,8 @@ static int waves_codec_init(struct processing_module *mod) } static int waves_codec_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_dev *dev = mod->dev; int ret; @@ -883,8 +857,8 @@ waves_codec_set_configuration(struct processing_module *mod, uint32_t config_id, return 0; } -static struct module_interface waves_interface = { - .init = waves_codec_init, +static const struct module_interface waves_interface = { + .init = waves_codec_init, .prepare = waves_codec_prepare, .process_raw_data = waves_codec_process, .set_configuration = waves_codec_set_configuration, diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index e28541560403..e7e4619ad840 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -14,6 +14,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -24,19 +28,6 @@ LOG_MODULE_REGISTER(module_adapter, CONFIG_SOF_LOG_LEVEL); -/* - * helpers to determine processing type - * Needed till all the modules use PROCESSING_MODE_SINK_SOURCE - */ -#define IS_PROCESSING_MODE_AUDIO_STREAM(mod) \ - (!!((struct module_data *)&(mod)->priv)->ops->process_audio_stream) - -#define IS_PROCESSING_MODE_RAW_DATA(mod) \ - (!!((struct module_data *)&(mod)->priv)->ops->process_raw_data) - -#define IS_PROCESSING_MODE_SINK_SOURCE(mod) \ - (!!((struct module_data *)&(mod)->priv)->ops->process) - /* * \brief Create a module adapter component. * \param[in] drv - component driver pointer. @@ -46,7 +37,7 @@ LOG_MODULE_REGISTER(module_adapter, CONFIG_SOF_LOG_LEVEL); */ struct comp_dev *module_adapter_new(const struct comp_driver *drv, const struct comp_ipc_config *config, - struct module_interface *interface, const void *spec) + const struct module_interface *interface, const void *spec) { int ret; struct comp_dev *dev; @@ -69,83 +60,34 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv, dev->ipc_config = *config; dev->drv = drv; - mod = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*mod)); + /* allocate module information. + * for DP shared modules this struct must be accessible from all cores + * Unfortunately at this point there's no information of components the module + * will be bound to. So we need to allocate shared memory for each DP module + * To be removed when pipeline 2.0 is ready + */ + enum mem_zone zone = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ? + SOF_MEM_ZONE_RUNTIME_SHARED : SOF_MEM_ZONE_RUNTIME; + + mod = rzalloc(zone, 0, SOF_MEM_CAPS_RAM, sizeof(*mod)); if (!mod) { comp_err(dev, "module_adapter_new(), failed to allocate memory for module"); rfree(dev); return NULL; } - /* align the allocation size to a cache line for the coherent API */ - mod->source_info = coherent_init_thread(struct module_source_info, c); - if (!mod->source_info) { - rfree(dev); - rfree(mod); - return NULL; - } - dst = &mod->priv.cfg; mod->dev = dev; comp_set_drvdata(dev, mod); list_init(&mod->sink_buffer_list); -#if CONFIG_IPC_MAJOR_3 - const unsigned char *data; - uint32_t size; - - switch (config->type) { - case SOF_COMP_VOLUME: - { - const struct ipc_config_volume *ipc_volume = spec; - - size = sizeof(*ipc_volume); - data = spec; - break; - } - case SOF_COMP_SRC: - { - const struct ipc_config_src *ipc_src = spec; - - size = sizeof(*ipc_src); - data = spec; - break; - } - default: - { - const struct ipc_config_process *ipc_module_adapter = spec; - - size = ipc_module_adapter->size; - data = ipc_module_adapter->data; - break; - } - } - - /* Copy initial config */ - if (size) { - ret = module_load_config(dev, data, size); - if (ret) { - comp_err(dev, "module_adapter_new() error %d: config loading has failed.", - ret); - goto err; - } - dst->init_data = dst->data; - } else { + ret = module_adapter_init_data(dev, dst, config, spec); + if (ret) { + comp_err(dev, "module_adapter_new() %d: module init data failed", + ret); goto err; } -#else - if (drv->type == SOF_COMP_MODULE_ADAPTER) { - const struct ipc_config_process *ipc_module_adapter = spec; - - dst->init_data = ipc_module_adapter->data; - dst->size = ipc_module_adapter->size; - dst->avail = true; - - memcpy(&dst->base_cfg, ipc_module_adapter->data, sizeof(dst->base_cfg)); - } else { - dst->init_data = spec; - } -#endif /* Modules must modify them if they support more than 1 source/sink */ mod->max_sources = 1; @@ -159,15 +101,19 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv, goto err; } -#if CONFIG_IPC_MAJOR_4 - dst->init_data = NULL; -#endif +#if CONFIG_ZEPHYR_DP_SCHEDULER + /* create a task for DP processing */ + if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP) + pipeline_comp_dp_task_init(dev); +#endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ + + module_adapter_reset_data(dst); + dev->state = COMP_STATE_READY; comp_dbg(dev, "module_adapter_new() done"); return dev; err: - coherent_free_thread(mod->source_info, c); rfree(mod); rfree(dev); return NULL; @@ -175,53 +121,181 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv, static int module_adapter_sink_src_prepare(struct comp_dev *dev) { - struct comp_buffer __sparse_cache *source_buffers_c[PLATFORM_MAX_STREAMS]; - struct comp_buffer __sparse_cache *sinks_buffers_c[PLATFORM_MAX_STREAMS]; - struct sof_sink __sparse_cache *audio_sink[PLATFORM_MAX_STREAMS]; - struct sof_source __sparse_cache *audio_src[PLATFORM_MAX_STREAMS]; struct processing_module *mod = comp_get_drvdata(dev); struct list_item *blist; - uint32_t num_of_sources = 0; - uint32_t num_of_sinks = 0; int ret; - int i = 0; + int i; /* acquire all sink and source buffers, get handlers to sink/source API */ + i = 0; list_for_item(blist, &dev->bsink_list) { - struct comp_buffer *sink_buffer_uc; - - sink_buffer_uc = container_of(blist, struct comp_buffer, source_list); - sinks_buffers_c[num_of_sinks] = buffer_acquire(sink_buffer_uc); - audio_sink[num_of_sinks] = - audio_stream_get_sink(&sinks_buffers_c[num_of_sinks]->stream); - sink_reset_num_of_processed_bytes(audio_sink[num_of_sinks]); - num_of_sinks++; + struct comp_buffer *sink_buffer = + container_of(blist, struct comp_buffer, source_list); + mod->sinks[i] = audio_stream_get_sink(&sink_buffer->stream); + i++; } + mod->num_of_sinks = i; + i = 0; list_for_item(blist, &dev->bsource_list) { - struct comp_buffer *source_buffer_uc; + struct comp_buffer *source_buffer = + container_of(blist, struct comp_buffer, sink_list); - source_buffer_uc = container_of(blist, struct comp_buffer, sink_list); - source_buffers_c[num_of_sources] = buffer_acquire(source_buffer_uc); - audio_src[num_of_sources] = - audio_stream_get_source(&source_buffers_c[num_of_sources]->stream); - source_reset_num_of_processed_bytes(audio_src[num_of_sources]); - num_of_sources++; + mod->sources[i] = audio_stream_get_source(&source_buffer->stream); + i++; } + mod->num_of_sources = i; /* Prepare module */ - ret = module_prepare(mod, audio_src, num_of_sources, audio_sink, num_of_sinks); + ret = module_prepare(mod, mod->sources, mod->num_of_sources, mod->sinks, mod->num_of_sinks); + + return ret; +} + +#if CONFIG_ZEPHYR_DP_SCHEDULER +static int module_adapter_dp_queue_prepare(struct comp_dev *dev) +{ + int dp_mode = dev->is_shared ? DP_QUEUE_MODE_SHARED : DP_QUEUE_MODE_LOCAL; + struct processing_module *mod = comp_get_drvdata(dev); + struct dp_queue *dp_queue; + struct list_item *blist; + int ret; + int i; + + /* for DP processing we need to create a DP QUEUE for each module input/output + * till pipeline2.0 is ready, DP processing requires double buffering + * + * first, set all parameters by calling "module prepare" with pointers to + * "main" audio_stream buffers + */ + ret = module_adapter_sink_src_prepare(dev); + if (ret) + return ret; - /* release all source buffers in reverse order */ - for (i = num_of_sources - 1; i >= 0; i--) - buffer_release(source_buffers_c[i]); + /* + * second step - create a "shadow" cross-core DpQueue for existing buffers + * and copy stream parameters to shadow buffers + */ + i = 0; + list_init(&mod->dp_queue_ll_to_dp_list); + list_for_item(blist, &dev->bsource_list) { + struct comp_buffer *source_buffer = + container_of(blist, struct comp_buffer, sink_list); - /* release all sink buffers in reverse order */ - for (i = num_of_sinks - 1; i >= 0 ; i--) - buffer_release(sinks_buffers_c[i]); + /* copy IBS & OBS from buffer to be shadowed */ + size_t min_available = + source_get_min_available(audio_stream_get_source(&source_buffer->stream)); + size_t min_free_space = + sink_get_min_free_space(audio_stream_get_sink(&source_buffer->stream)); - return ret; + /* create a shadow dp queue */ + dp_queue = dp_queue_create(min_available, min_free_space, dp_mode); + + if (!dp_queue) + goto err; + dp_queue_append_to_list(dp_queue, &mod->dp_queue_ll_to_dp_list); + + /* it will override source pointers set by module_adapter_sink_src_prepare + * module will use shadow dpQueue for processing + */ + mod->sources[i] = dp_queue_get_source(dp_queue); + + /* copy parameters from buffer to be shadowed */ + memcpy_s(&dp_queue->audio_stream_params, + sizeof(dp_queue->audio_stream_params), + &source_buffer->stream.runtime_stream_params, + sizeof(source_buffer->stream.runtime_stream_params)); + i++; + } + mod->num_of_sources = i; + unsigned int period = UINT32_MAX; + + i = 0; + list_init(&mod->dp_queue_dp_to_ll_list); + list_for_item(blist, &dev->bsink_list) { + struct comp_buffer *sink_buffer = + container_of(blist, struct comp_buffer, source_list); + + /* copy IBS & OBS from buffer to be shadowed */ + size_t min_available = + source_get_min_available(audio_stream_get_source(&sink_buffer->stream)); + size_t min_free_space = + sink_get_min_free_space(audio_stream_get_sink(&sink_buffer->stream)); + + /* create a shadow dp queue */ + dp_queue = dp_queue_create(min_available, min_free_space, dp_mode); + + if (!dp_queue) + goto err; + + dp_queue_append_to_list(dp_queue, &mod->dp_queue_dp_to_ll_list); + /* it will override sink pointers set by module_adapter_sink_src_prepare + * module will use shadow dpQueue for processing + */ + mod->sinks[i] = dp_queue_get_sink(dp_queue); + + /* copy parameters from buffer to be shadowed */ + memcpy_s(&dp_queue->audio_stream_params, + sizeof(dp_queue->audio_stream_params), + &sink_buffer->stream.runtime_stream_params, + sizeof(sink_buffer->stream.runtime_stream_params)); + /* calculate time required the module to provide OBS data portion - a period */ + unsigned int sink_period = 1000000 * sink_get_min_free_space(mod->sinks[i]) / + (sink_get_frame_bytes(mod->sinks[i]) * + sink_get_rate(mod->sinks[i])); + /* note the minimal period for the module */ + if (period > sink_period) + period = sink_period; + + i++; + } + mod->num_of_sinks = i; + /* set the period for the module unless it has already been calculated by the + * module itself during prepare + * It may happen i.e. for modules like phrase detect that do not produce audio data + * but events and therefore don't have any deadline for processing + * Second example is a module with variable data rate on output (like MPEG encoder) + */ + if (!dev->period) { + comp_info(dev, "DP Module period set to %u", period); + dev->period = period; + } + + return 0; + +err:; + struct list_item *dp_queue_list_item; + struct list_item *tmp; + + i = 0; + list_for_item_safe(dp_queue_list_item, tmp, &mod->dp_queue_dp_to_ll_list) { + struct dp_queue *dp_queue = + container_of(dp_queue_list_item, struct dp_queue, list); + + /* dp free will also remove the queue from a list */ + dp_queue_free(dp_queue); + mod->sources[i++] = NULL; + } + mod->num_of_sources = 0; + + i = 0; + list_for_item_safe(dp_queue_list_item, tmp, &mod->dp_queue_ll_to_dp_list) { + struct dp_queue *dp_queue = + container_of(dp_queue_list_item, struct dp_queue, list); + + dp_queue_free(dp_queue); + mod->sinks[i++] = NULL; + } + mod->num_of_sinks = 0; + + return -ENOMEM; +} +#else +static inline int module_adapter_dp_queue_prepare(struct comp_dev *dev) +{ + return -EINVAL; } +#endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ /* * \brief Prepare the module @@ -236,8 +310,6 @@ int module_adapter_prepare(struct comp_dev *dev) int ret; struct processing_module *mod = comp_get_drvdata(dev); struct module_data *md = &mod->priv; - struct comp_buffer __sparse_cache *buffer_c; - struct comp_buffer __sparse_cache *sink_c; struct comp_buffer *sink; struct list_item *blist, *_blist; uint32_t buff_periods; @@ -247,11 +319,21 @@ int module_adapter_prepare(struct comp_dev *dev) comp_dbg(dev, "module_adapter_prepare() start"); /* Prepare module */ - if (IS_PROCESSING_MODE_SINK_SOURCE(mod)) + if (IS_PROCESSING_MODE_SINK_SOURCE(mod) && + mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) + ret = module_adapter_dp_queue_prepare(dev); + + else if (IS_PROCESSING_MODE_SINK_SOURCE(mod) && + mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) ret = module_adapter_sink_src_prepare(dev); - else + + else if ((IS_PROCESSING_MODE_RAW_DATA(mod) || IS_PROCESSING_MODE_AUDIO_STREAM(mod)) && + mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) ret = module_prepare(mod, NULL, 0, NULL, 0); + else + ret = -EINVAL; + if (ret) { if (ret != PPL_STATUS_PATH_STOP) comp_err(dev, "module_adapter_prepare() error %x: module prepare failed", @@ -286,35 +368,25 @@ int module_adapter_prepare(struct comp_dev *dev) * parameter from sink buffer is settled, and still prior to all references to period_bytes. */ sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - mod->period_bytes = audio_stream_period_bytes(&sink_c->stream, dev->frames); + mod->period_bytes = audio_stream_period_bytes(&sink->stream, dev->frames); comp_dbg(dev, "module_adapter_prepare(): got period_bytes = %u", mod->period_bytes); - buffer_release(sink_c); - - /* - * compute number of input buffers and make the source_info shared if the module is on a - * different core than any of it's sources - */ - list_for_item(blist, &dev->bsource_list) { - struct comp_buffer *buf; - struct comp_dev *source; - - buf = buffer_from_list(blist, PPL_DIR_UPSTREAM); - source = buffer_get_comp(buf, PPL_DIR_UPSTREAM); - - if (source->pipeline && source->pipeline->core != dev->pipeline->core) - coherent_shared_thread(mod->source_info, c); + /* no more to do for sink/source mode */ + if (IS_PROCESSING_MODE_SINK_SOURCE(mod)) + return 0; - mod->num_input_buffers++; - } + /* compute number of input buffers */ + mod->num_of_sources = 0; + list_for_item(blist, &dev->bsource_list) + mod->num_of_sources++; /* compute number of output buffers */ + mod->num_of_sinks = 0; list_for_item(blist, &dev->bsink_list) - mod->num_output_buffers++; + mod->num_of_sinks++; - if (!mod->num_input_buffers && !mod->num_output_buffers) { + if (!mod->num_of_sources && !mod->num_of_sinks) { comp_err(dev, "module_adapter_prepare(): no source and sink buffers connected!"); return -EINVAL; } @@ -325,18 +397,7 @@ int module_adapter_prepare(struct comp_dev *dev) return -EINVAL; } -#if CONFIG_IPC_MAJOR_3 - /* Check if audio stream client has only one source and one sink buffer to use a - * simplified copy function. - */ - if (IS_PROCESSING_MODE_AUDIO_STREAM(mod) && mod->num_input_buffers == 1 && - mod->num_output_buffers == 1) { - mod->source_comp_buffer = list_first_item(&dev->bsource_list, - struct comp_buffer, sink_list); - mod->sink_comp_buffer = sink; - mod->stream_copy_single_to_single = true; - } -#endif + module_adapter_check_data(mod, dev, sink); /* allocate memory for input buffers */ if (mod->max_sources) { @@ -421,8 +482,7 @@ int module_adapter_prepare(struct comp_dev *dev) list_for_item(blist, &dev->bsource_list) { size_t size = MAX(mod->deep_buff_bytes, mod->period_bytes); - mod->input_buffers[i].data = - (__sparse_force void __sparse_cache *)rballoc(0, SOF_MEM_CAPS_RAM, size); + mod->input_buffers[i].data = rballoc(0, SOF_MEM_CAPS_RAM, size); if (!mod->input_buffers[i].data) { comp_err(mod->dev, "module_adapter_prepare(): Failed to alloc input buffer data"); ret = -ENOMEM; @@ -434,9 +494,7 @@ int module_adapter_prepare(struct comp_dev *dev) /* allocate memory for output buffer data */ i = 0; list_for_item(blist, &dev->bsink_list) { - mod->output_buffers[i].data = - (__sparse_force void __sparse_cache *)rballoc(0, SOF_MEM_CAPS_RAM, - md->mpd.out_buff_size); + mod->output_buffers[i].data = rballoc(0, SOF_MEM_CAPS_RAM, md->mpd.out_buff_size); if (!mod->output_buffers[i].data) { comp_err(mod->dev, "module_adapter_prepare(): Failed to alloc output buffer data"); ret = -ENOMEM; @@ -447,9 +505,10 @@ int module_adapter_prepare(struct comp_dev *dev) /* allocate buffer for all sinks */ if (list_is_empty(&mod->sink_buffer_list)) { - for (i = 0; i < mod->num_output_buffers; i++) { + for (i = 0; i < mod->num_of_sinks; i++) { + /* allocate not shared buffer */ struct comp_buffer *buffer = buffer_alloc(buff_size, SOF_MEM_CAPS_RAM, - 0, PLATFORM_DCACHE_ALIGN); + 0, PLATFORM_DCACHE_ALIGN, false); uint32_t flags; if (!buffer) { @@ -462,28 +521,23 @@ int module_adapter_prepare(struct comp_dev *dev) buffer_attach(buffer, &mod->sink_buffer_list, PPL_DIR_UPSTREAM); irq_local_enable(flags); - buffer_c = buffer_acquire(buffer); - buffer_set_params(buffer_c, mod->stream_params, BUFFER_UPDATE_FORCE); - buffer_reset_pos(buffer_c, NULL); - buffer_release(buffer_c); + buffer_set_params(buffer, mod->stream_params, BUFFER_UPDATE_FORCE); + buffer_reset_pos(buffer, NULL); } } else { list_for_item(blist, &mod->sink_buffer_list) { struct comp_buffer *buffer = container_of(blist, struct comp_buffer, sink_list); - buffer_c = buffer_acquire(buffer); - ret = buffer_set_size(buffer_c, buff_size, 0); + ret = buffer_set_size(buffer, buff_size, 0); if (ret < 0) { - buffer_release(buffer_c); comp_err(dev, "module_adapter_prepare(): buffer_set_size() failed, buff_size = %u", buff_size); goto free; } - buffer_set_params(buffer_c, mod->stream_params, BUFFER_UPDATE_FORCE); - buffer_reset_pos(buffer_c, NULL); - buffer_release(buffer_c); + buffer_set_params(buffer, mod->stream_params, BUFFER_UPDATE_FORCE); + buffer_reset_pos(buffer, NULL); } } @@ -504,16 +558,18 @@ int module_adapter_prepare(struct comp_dev *dev) } out_data_free: - for (i = 0; i < mod->num_output_buffers; i++) - rfree((__sparse_force void *)mod->output_buffers[i].data); + for (i = 0; i < mod->num_of_sinks; i++) + rfree(mod->output_buffers[i].data); in_data_free: - for (i = 0; i < mod->num_input_buffers; i++) - rfree((__sparse_force void *)mod->input_buffers[i].data); + for (i = 0; i < mod->num_of_sources; i++) + rfree(mod->input_buffers[i].data); in_out_free: rfree(mod->output_buffers); + mod->output_buffers = NULL; rfree(mod->input_buffers); + mod->input_buffers = NULL; return ret; } @@ -551,10 +607,7 @@ int module_adapter_params(struct comp_dev *dev, struct sof_ipc_stream_params *pa return ret; } -#if CONFIG_IPC_MAJOR_4 - ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); - ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, mod->stream_params); -#endif + module_adapter_set_params(mod, params); return 0; } @@ -566,8 +619,8 @@ int module_adapter_params(struct comp_dev *dev, struct sof_ipc_stream_params *pa * @bytes: number of bytes available in the source buffer */ static void -ca_copy_from_source_to_module(const struct audio_stream __sparse_cache *source, - void __sparse_cache *buff, uint32_t buff_size, size_t bytes) +ca_copy_from_source_to_module(const struct audio_stream *source, + void *buff, uint32_t buff_size, size_t bytes) { /* head_size - available data until end of source buffer */ const int without_wrap = audio_stream_bytes_without_wrap(source, @@ -594,8 +647,8 @@ ca_copy_from_source_to_module(const struct audio_stream __sparse_cache *source, * @bytes: number of bytes available in the module output buffer */ static void -ca_copy_from_module_to_sink(const struct audio_stream __sparse_cache *sink, - void __sparse_cache *buff, size_t bytes) +ca_copy_from_module_to_sink(const struct audio_stream *sink, + void *buff, size_t bytes) { /* head_size - free space until end of sink buffer */ const int without_wrap = audio_stream_bytes_without_wrap(sink, audio_stream_get_wptr(sink)); @@ -623,7 +676,7 @@ ca_copy_from_module_to_sink(const struct audio_stream __sparse_cache *sink, * * \return: none. */ -static void generate_zeroes(struct comp_buffer __sparse_cache *sink, uint32_t bytes) +static void generate_zeroes(struct comp_buffer *sink, uint32_t bytes) { uint32_t tmp, copy_bytes = bytes; void *ptr; @@ -638,8 +691,8 @@ static void generate_zeroes(struct comp_buffer __sparse_cache *sink, uint32_t by comp_update_buffer_produce(sink, bytes); } -static void module_copy_samples(struct comp_dev *dev, struct comp_buffer __sparse_cache *src_buffer, - struct comp_buffer __sparse_cache *sink_buffer, uint32_t produced) +static void module_copy_samples(struct comp_dev *dev, struct comp_buffer *src_buffer, + struct comp_buffer *sink_buffer, uint32_t produced) { struct processing_module *mod = comp_get_drvdata(dev); struct comp_copy_limits cl; @@ -680,7 +733,6 @@ static void module_adapter_process_output(struct comp_dev *dev) { struct processing_module *mod = comp_get_drvdata(dev); struct comp_buffer *sink; - struct comp_buffer __sparse_cache *sink_c; struct list_item *blist; int i = 0; @@ -691,15 +743,12 @@ static void module_adapter_process_output(struct comp_dev *dev) list_for_item(blist, &mod->sink_buffer_list) { if (mod->output_buffers[i].size > 0) { struct comp_buffer *buffer; - struct comp_buffer __sparse_cache *buffer_c; buffer = container_of(blist, struct comp_buffer, sink_list); - buffer_c = buffer_acquire(buffer); - ca_copy_from_module_to_sink(&buffer_c->stream, mod->output_buffers[i].data, + ca_copy_from_module_to_sink(&buffer->stream, mod->output_buffers[i].data, mod->output_buffers[i].size); - audio_stream_produce(&buffer_c->stream, mod->output_buffers[i].size); - buffer_release(buffer_c); + audio_stream_produce(&buffer->stream, mod->output_buffers[i].size); } i++; } @@ -713,17 +762,12 @@ static void module_adapter_process_output(struct comp_dev *dev) list_for_item(_blist, &mod->sink_buffer_list) { if (i == j) { struct comp_buffer *source; - struct comp_buffer __sparse_cache *source_c; sink = container_of(blist, struct comp_buffer, source_list); source = container_of(_blist, struct comp_buffer, sink_list); - sink_c = buffer_acquire(sink); - source_c = buffer_acquire(source); - module_copy_samples(dev, source_c, sink_c, + module_copy_samples(dev, source, sink, mod->output_buffers[i].size); - buffer_release(source_c); - buffer_release(sink_c); mod->output_buffers[i].size = 0; break; @@ -738,8 +782,8 @@ static void module_adapter_process_output(struct comp_dev *dev) static uint32_t module_single_sink_setup(struct comp_dev *dev, - struct comp_buffer __sparse_cache **source_c, - struct comp_buffer __sparse_cache **sinks_c) + struct comp_buffer **source, + struct comp_buffer **sinks) { struct processing_module *mod = comp_get_drvdata(dev); struct list_item *blist; @@ -748,14 +792,14 @@ module_single_sink_setup(struct comp_dev *dev, int i = 0; list_for_item(blist, &dev->bsource_list) { - frames = audio_stream_avail_frames_aligned(&source_c[i]->stream, - &sinks_c[0]->stream); + frames = audio_stream_avail_frames_aligned(&source[i]->stream, + &sinks[0]->stream); if (!mod->skip_src_buffer_invalidate) { uint32_t source_frame_bytes; - source_frame_bytes = audio_stream_frame_bytes(&source_c[i]->stream); - buffer_stream_invalidate(source_c[i], frames * source_frame_bytes); + source_frame_bytes = audio_stream_frame_bytes(&source[i]->stream); + buffer_stream_invalidate(source[i], frames * source_frame_bytes); } /* @@ -765,22 +809,22 @@ module_single_sink_setup(struct comp_dev *dev, mod->input_buffers[i].size = frames; mod->input_buffers[i].consumed = 0; - mod->input_buffers[i].data = &source_c[i]->stream; + mod->input_buffers[i].data = &source[i]->stream; i++; } num_input_buffers = i; mod->output_buffers[0].size = 0; - mod->output_buffers[0].data = &sinks_c[0]->stream; + mod->output_buffers[0].data = &sinks[0]->stream; return num_input_buffers; } static uint32_t module_single_source_setup(struct comp_dev *dev, - struct comp_buffer __sparse_cache **source_c, - struct comp_buffer __sparse_cache **sinks_c) + struct comp_buffer **source, + struct comp_buffer **sinks) { struct processing_module *mod = comp_get_drvdata(dev); struct list_item *blist; @@ -789,20 +833,20 @@ module_single_source_setup(struct comp_dev *dev, uint32_t source_frame_bytes; int i = 0; - source_frame_bytes = audio_stream_frame_bytes(&source_c[0]->stream); + source_frame_bytes = audio_stream_frame_bytes(&source[0]->stream); if (list_is_empty(&dev->bsink_list)) { - min_frames = audio_stream_get_avail_frames(&source_c[0]->stream); + min_frames = audio_stream_get_avail_frames(&source[0]->stream); } else { uint32_t frames; list_for_item(blist, &dev->bsink_list) { - frames = audio_stream_avail_frames_aligned(&source_c[0]->stream, - &sinks_c[i]->stream); + frames = audio_stream_avail_frames_aligned(&source[0]->stream, + &sinks[i]->stream); min_frames = MIN(min_frames, frames); mod->output_buffers[i].size = 0; - mod->output_buffers[i].data = &sinks_c[i]->stream; + mod->output_buffers[i].data = &sinks[i]->stream; i++; } } @@ -810,12 +854,12 @@ module_single_source_setup(struct comp_dev *dev, num_output_buffers = i; if (!mod->skip_src_buffer_invalidate) - buffer_stream_invalidate(source_c[0], min_frames * source_frame_bytes); + buffer_stream_invalidate(source[0], min_frames * source_frame_bytes); /* note that the size is in number of frames not the number of bytes */ mod->input_buffers[0].size = min_frames; mod->input_buffers[0].consumed = 0; - mod->input_buffers[0].data = &source_c[0]->stream; + mod->input_buffers[0].data = &source[0]->stream; return num_output_buffers; } @@ -823,28 +867,30 @@ module_single_source_setup(struct comp_dev *dev, static int module_adapter_audio_stream_copy_1to1(struct comp_dev *dev) { struct processing_module *mod = comp_get_drvdata(dev); - struct comp_buffer __sparse_cache *source_c; - struct comp_buffer __sparse_cache *sink_c; uint32_t num_output_buffers = 0; uint32_t frames; int ret; - source_c = buffer_acquire(mod->source_comp_buffer); - sink_c = buffer_acquire(mod->sink_comp_buffer); - frames = audio_stream_avail_frames_aligned(&source_c->stream, &sink_c->stream); + frames = audio_stream_avail_frames_aligned(&mod->source_comp_buffer->stream, + &mod->sink_comp_buffer->stream); mod->input_buffers[0].size = frames; mod->input_buffers[0].consumed = 0; - mod->input_buffers[0].data = &source_c->stream; + mod->input_buffers[0].data = &mod->source_comp_buffer->stream; mod->output_buffers[0].size = 0; - mod->output_buffers[0].data = &sink_c->stream; - if (!mod->skip_src_buffer_invalidate) /* TODO: add mod->is_multi_core && optimization */ - buffer_stream_invalidate(source_c, - frames * audio_stream_frame_bytes(&source_c->stream)); + mod->output_buffers[0].data = &mod->sink_comp_buffer->stream; + + if (!mod->skip_src_buffer_invalidate) { /* TODO: add mod->is_multi_core && optimization */ + /* moved bytes to its own variable to fix checkpatch */ + uint32_t bytes = + frames * audio_stream_frame_bytes(&mod->source_comp_buffer->stream); + buffer_stream_invalidate(mod->source_comp_buffer, + bytes); + } /* Note: Source buffer state is not checked to enable mixout to generate zero * PCM codes when source is not active. */ - if (sink_c->sink->state == dev->state) + if (mod->sink_comp_buffer->sink->state == dev->state) num_output_buffers = 1; ret = module_process_legacy(mod, mod->input_buffers, 1, @@ -853,26 +899,24 @@ static int module_adapter_audio_stream_copy_1to1(struct comp_dev *dev) /* consume from the input buffer */ mod->total_data_consumed += mod->input_buffers[0].consumed; if (mod->input_buffers[0].consumed) - audio_stream_consume(&source_c->stream, mod->input_buffers[0].consumed); + audio_stream_consume(&mod->source_comp_buffer->stream, + mod->input_buffers[0].consumed); /* produce data into the output buffer */ mod->total_data_produced += mod->output_buffers[0].size; if (!mod->skip_sink_buffer_writeback) /* TODO: add mod->is_multi_core && optimization */ - buffer_stream_writeback(sink_c, mod->output_buffers[0].size); + buffer_stream_writeback(mod->sink_comp_buffer, mod->output_buffers[0].size); if (mod->output_buffers[0].size) - comp_update_buffer_produce(sink_c, mod->output_buffers[0].size); + comp_update_buffer_produce(mod->sink_comp_buffer, mod->output_buffers[0].size); - /* release all buffers */ - buffer_release(sink_c); - buffer_release(source_c); return ret; } static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) { - struct comp_buffer __sparse_cache *source_c[PLATFORM_MAX_STREAMS]; - struct comp_buffer __sparse_cache *sinks_c[PLATFORM_MAX_STREAMS]; + struct comp_buffer *sources[PLATFORM_MAX_STREAMS]; + struct comp_buffer *sinks[PLATFORM_MAX_STREAMS]; struct processing_module *mod = comp_get_drvdata(dev); struct list_item *blist; uint32_t num_input_buffers, num_output_buffers; @@ -880,11 +924,7 @@ static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) /* handle special case of HOST/DAI type components */ if (dev->ipc_config.type == SOF_COMP_HOST || dev->ipc_config.type == SOF_COMP_DAI) -#if CONFIG_IPC_MAJOR_3 - return module_process_legacy(mod, NULL, 0, NULL, 0); -#else - return module_process_stream(mod, NULL, 0, NULL, 0); -#endif + return module_process_endpoint(mod, NULL, 0, NULL, 0); if (mod->stream_copy_single_to_single) return module_adapter_audio_stream_copy_1to1(dev); @@ -894,7 +934,7 @@ static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) struct comp_buffer *sink; sink = container_of(blist, struct comp_buffer, source_list); - sinks_c[i++] = buffer_acquire(sink); + sinks[i++] = sink; } num_output_buffers = i; if (num_output_buffers > mod->max_sinks) { @@ -907,26 +947,23 @@ static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) struct comp_buffer *source; source = container_of(blist, struct comp_buffer, sink_list); - source_c[i++] = buffer_acquire(source); + sources[i++] = source; } num_input_buffers = i; if (num_input_buffers > mod->max_sources) { - comp_err(dev, "Invalid number of sinks %d\n", num_input_buffers); + comp_err(dev, "Invalid number of sources %d\n", num_input_buffers); return -EINVAL; } /* setup active input/output buffers for processing */ if (num_output_buffers == 1) { - module_single_sink_setup(dev, source_c, sinks_c); - if (sinks_c[0]->sink->state != dev->state) { + module_single_sink_setup(dev, sources, sinks); + if (sinks[0]->sink->state != dev->state) num_output_buffers = 0; - buffer_release(sinks_c[0]); - } } else if (num_input_buffers == 1) { - module_single_source_setup(dev, source_c, sinks_c); - if (source_c[0]->source->state != dev->state) { + module_single_source_setup(dev, sources, sinks); + if (sources[0]->source->state != dev->state) { num_input_buffers = 0; - buffer_release(source_c[0]); } } else { ret = -EINVAL; @@ -948,13 +985,11 @@ static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) /* consume from all active input buffers */ for (i = 0; i < num_input_buffers; i++) { - struct comp_buffer __sparse_cache *src_c; + struct comp_buffer *src = + container_of(mod->input_buffers[i].data, struct comp_buffer, stream); - src_c = attr_container_of(mod->input_buffers[i].data, - struct comp_buffer __sparse_cache, - stream, __sparse_cache); if (mod->input_buffers[i].consumed) - audio_stream_consume(&src_c->stream, mod->input_buffers[i].consumed); + audio_stream_consume(&src->stream, mod->input_buffers[i].consumed); } /* compute data consumed based on pin 0 since it is processed with base config @@ -964,42 +999,35 @@ static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) /* release all source buffers */ for (i = 0; i < num_input_buffers; i++) { - buffer_release(source_c[i]); mod->input_buffers[i].size = 0; mod->input_buffers[i].consumed = 0; } /* produce data into all active output buffers */ for (i = 0; i < num_output_buffers; i++) { - struct comp_buffer __sparse_cache *sink_c; - - sink_c = attr_container_of(mod->output_buffers[i].data, - struct comp_buffer __sparse_cache, - stream, __sparse_cache); + struct comp_buffer *sink = + container_of(mod->output_buffers[i].data, struct comp_buffer, stream); if (!mod->skip_sink_buffer_writeback) - buffer_stream_writeback(sink_c, mod->output_buffers[i].size); + buffer_stream_writeback(sink, mod->output_buffers[i].size); if (mod->output_buffers[i].size) - comp_update_buffer_produce(sink_c, mod->output_buffers[i].size); + comp_update_buffer_produce(sink, mod->output_buffers[i].size); } mod->total_data_produced += mod->output_buffers[0].size; /* release all sink buffers */ for (i = 0; i < num_output_buffers; i++) { - buffer_release(sinks_c[i]); mod->output_buffers[i].size = 0; } return 0; out: for (i = 0; i < num_output_buffers; i++) { - buffer_release(sinks_c[i]); mod->output_buffers[i].size = 0; } for (i = 0; i < num_input_buffers; i++) { - buffer_release(source_c[i]); mod->input_buffers[i].size = 0; mod->input_buffers[i].consumed = 0; } @@ -1007,62 +1035,96 @@ static int module_adapter_audio_stream_type_copy(struct comp_dev *dev) return ret; } -static int module_adapter_sink_source_copy(struct comp_dev *dev) +#if CONFIG_ZEPHYR_DP_SCHEDULER +static int module_adapter_copy_dp_queues(struct comp_dev *dev) { - struct comp_buffer __sparse_cache *source_buffers_c[PLATFORM_MAX_STREAMS]; - struct comp_buffer __sparse_cache *sinks_buffers_c[PLATFORM_MAX_STREAMS]; - struct sof_sink __sparse_cache *audio_sink[PLATFORM_MAX_STREAMS]; - struct sof_source __sparse_cache *audio_src[PLATFORM_MAX_STREAMS]; + /* + * copy data from component audio streams to dp_queue + * DP module processing itself will take place in DP thread + * This is an adapter, to be removed when pipeline2.0 is ready + */ struct processing_module *mod = comp_get_drvdata(dev); + struct dp_queue *dp_queue; struct list_item *blist; - uint32_t num_of_sources = 0; - uint32_t num_of_sinks = 0; - int ret; - int i = 0; + int err; - comp_dbg(dev, "module_adapter_sink_source_copy(): start"); + dp_queue = dp_queue_get_first_item(&mod->dp_queue_ll_to_dp_list); + list_for_item(blist, &dev->bsource_list) { + /* input - we need to copy data from audio_stream (as source) + * to dp_queue (as sink) + */ + assert(dp_queue); + struct comp_buffer *buffer = + container_of(blist, struct comp_buffer, sink_list); + struct sof_source *data_src = audio_stream_get_source(&buffer->stream); + struct sof_sink *data_sink = dp_queue_get_sink(dp_queue); + uint32_t to_copy = MIN(sink_get_free_size(data_sink), + source_get_data_available(data_src)); - /* acquire all sink and source buffers, get handlers to sink/source API */ - list_for_item(blist, &dev->bsink_list) { - struct comp_buffer *sink_buffer; + err = source_to_sink_copy(data_src, data_sink, true, to_copy); + if (err) + return err; - sink_buffer = container_of(blist, struct comp_buffer, source_list); - sinks_buffers_c[num_of_sinks] = buffer_acquire(sink_buffer); - audio_sink[num_of_sinks] = - audio_stream_get_sink(&sinks_buffers_c[num_of_sinks]->stream); - sink_reset_num_of_processed_bytes(audio_sink[num_of_sinks]); - num_of_sinks++; + dp_queue = dp_queue_get_next_item(dp_queue); } - list_for_item(blist, &dev->bsource_list) { - struct comp_buffer *source_buffer; + dp_queue = dp_queue_get_first_item(&mod->dp_queue_dp_to_ll_list); + list_for_item(blist, &dev->bsink_list) { + /* output - we need to copy data from dp_queue (as source) + * to audio_stream (as sink) + */ + assert(dp_queue); + struct comp_buffer *buffer = + container_of(blist, struct comp_buffer, source_list); + struct sof_sink *data_sink = audio_stream_get_sink(&buffer->stream); + struct sof_source *data_src = dp_queue_get_source(dp_queue); + uint32_t to_copy = MIN(sink_get_free_size(data_sink), + source_get_data_available(data_src)); - source_buffer = container_of(blist, struct comp_buffer, sink_list); - source_buffers_c[num_of_sources] = buffer_acquire(source_buffer); - audio_src[num_of_sources] = - audio_stream_get_source(&source_buffers_c[num_of_sources]->stream); - source_reset_num_of_processed_bytes(audio_src[num_of_sources]); - num_of_sources++; + err = source_to_sink_copy(data_src, data_sink, true, to_copy); + if (err) + return err; + + dp_queue = dp_queue_get_next_item(dp_queue); } + return 0; +} +#else +static inline int module_adapter_copy_dp_queues(struct comp_dev *dev) +{ + return -ENOTSUP; +} +#endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ + +static int module_adapter_sink_source_copy(struct comp_dev *dev) +{ + struct processing_module *mod = comp_get_drvdata(dev); + int ret; + int i = 0; + + comp_dbg(dev, "module_adapter_sink_source_copy(): start"); + + /* reset number of processed bytes */ + for (i = 0; i < mod->num_of_sources; i++) + source_reset_num_of_processed_bytes(mod->sources[i]); - ret = module_process_sink_src(mod, audio_src, num_of_sources, audio_sink, num_of_sinks); + for (i = 0; i < mod->num_of_sinks; i++) + sink_reset_num_of_processed_bytes(mod->sinks[i]); + + ret = module_process_sink_src(mod, mod->sources, mod->num_of_sources, + mod->sinks, mod->num_of_sinks); if (ret != -ENOSPC && ret != -ENODATA && ret) { comp_err(dev, "module_adapter_sink_source_copy() process failed with error: %x", ret); } - /* release all source buffers in reverse order */ - for (i = num_of_sources - 1; i >= 0; i--) { - mod->total_data_consumed += source_get_num_of_processed_bytes(audio_src[i]); - buffer_release(source_buffers_c[i]); - } + /* count number of processed data. To be removed in pipeline 2.0 */ + for (i = 0; i < mod->num_of_sources; i++) + mod->total_data_consumed += source_get_num_of_processed_bytes(mod->sources[i]); - /* release all sink buffers in reverse order */ - for (i = num_of_sinks - 1; i >= 0 ; i--) { - mod->total_data_produced += sink_get_num_of_processed_bytes(audio_sink[i]); - buffer_release(sinks_buffers_c[i]); - } + for (i = 0; i < mod->num_of_sinks; i++) + mod->total_data_produced += sink_get_num_of_processed_bytes(mod->sinks[i]); comp_dbg(dev, "module_adapter_sink_source_copy(): done"); @@ -1074,7 +1136,6 @@ static int module_adapter_raw_data_type_copy(struct comp_dev *dev) struct processing_module *mod = comp_get_drvdata(dev); struct module_data *md = &mod->priv; struct comp_buffer *source, *sink; - struct comp_buffer __sparse_cache *sink_c = NULL; struct list_item *blist; size_t size = MAX(mod->deep_buff_bytes, mod->period_bytes); uint32_t min_free_frames = UINT_MAX; @@ -1085,45 +1146,38 @@ static int module_adapter_raw_data_type_copy(struct comp_dev *dev) list_for_item(blist, &mod->sink_buffer_list) { sink = container_of(blist, struct comp_buffer, sink_list); - sink_c = buffer_acquire(sink); min_free_frames = MIN(min_free_frames, - audio_stream_get_free_frames(&sink_c->stream)); - buffer_release(sink_c); + audio_stream_get_free_frames(&sink->stream)); } /* copy source samples into input buffer */ list_for_item(blist, &dev->bsource_list) { - struct comp_buffer __sparse_cache *src_c; uint32_t bytes_to_process; int frames, source_frame_bytes; source = container_of(blist, struct comp_buffer, sink_list); - src_c = buffer_acquire(source); /* check if the source dev is in the same state as the dev */ - if (!src_c->source || src_c->source->state != dev->state) { - buffer_release(src_c); + if (!source->source || source->source->state != dev->state) continue; - } frames = MIN(min_free_frames, - audio_stream_get_avail_frames(&src_c->stream)); - source_frame_bytes = audio_stream_frame_bytes(&src_c->stream); + audio_stream_get_avail_frames(&source->stream)); + source_frame_bytes = audio_stream_frame_bytes(&source->stream); bytes_to_process = MIN(frames * source_frame_bytes, md->mpd.in_buff_size); - buffer_stream_invalidate(src_c, bytes_to_process); + buffer_stream_invalidate(source, bytes_to_process); mod->input_buffers[i].size = bytes_to_process; mod->input_buffers[i].consumed = 0; - ca_copy_from_source_to_module(&src_c->stream, mod->input_buffers[i].data, + ca_copy_from_source_to_module(&source->stream, mod->input_buffers[i].data, md->mpd.in_buff_size, bytes_to_process); - buffer_release(src_c); i++; } - ret = module_process_legacy(mod, mod->input_buffers, mod->num_input_buffers, - mod->output_buffers, mod->num_output_buffers); + ret = module_process_legacy(mod, mod->input_buffers, mod->num_of_sources, + mod->output_buffers, mod->num_of_sinks); if (ret) { if (ret != -ENOSPC && ret != -ENODATA) { comp_err(dev, @@ -1138,13 +1192,10 @@ static int module_adapter_raw_data_type_copy(struct comp_dev *dev) i = 0; /* consume from all input buffers */ list_for_item(blist, &dev->bsource_list) { - struct comp_buffer __sparse_cache *src_c; source = container_of(blist, struct comp_buffer, sink_list); - src_c = buffer_acquire(source); - comp_update_buffer_consume(src_c, mod->input_buffers[i].consumed); - buffer_release(src_c); + comp_update_buffer_consume(source, mod->input_buffers[i].consumed); bzero((__sparse_force void *)mod->input_buffers[i].data, size); mod->input_buffers[i].size = 0; @@ -1162,10 +1213,10 @@ static int module_adapter_raw_data_type_copy(struct comp_dev *dev) return 0; out: - for (i = 0; i < mod->num_output_buffers; i++) + for (i = 0; i < mod->num_of_sinks; i++) mod->output_buffers[i].size = 0; - for (i = 0; i < mod->num_input_buffers; i++) { + for (i = 0; i < mod->num_of_sources; i++) { bzero((__sparse_force void *)mod->input_buffers[i].data, size); mod->input_buffers[i].size = 0; mod->input_buffers[i].consumed = 0; @@ -1186,8 +1237,13 @@ int module_adapter_copy(struct comp_dev *dev) if (IS_PROCESSING_MODE_RAW_DATA(mod)) return module_adapter_raw_data_type_copy(dev); - if (IS_PROCESSING_MODE_SINK_SOURCE(mod)) - return module_adapter_sink_source_copy(dev); + if (IS_PROCESSING_MODE_SINK_SOURCE(mod)) { + if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) + return module_adapter_copy_dp_queues(dev); + else + return module_adapter_sink_source_copy(dev); + + } comp_err(dev, "module_adapter_copy(): unknown processing_data_type"); return -EINVAL; @@ -1316,34 +1372,6 @@ int module_adapter_cmd(struct comp_dev *dev, int cmd, void *data, int max_data_s return ret; } -#if CONFIG_IPC_MAJOR_3 -static int module_source_status_count(struct comp_dev *dev, uint32_t status) -{ - struct list_item *blist; - int count = 0; - - /* count source with state == status */ - list_for_item(blist, &dev->bsource_list) { - /* - * FIXME: this is racy, state can be changed by another core. - * This is implicitly protected by serialised IPCs. Even when - * IPCs are processed in the pipeline thread, the next IPC will - * not be sent until the thread has processed and replied to the - * current one. - */ - struct comp_buffer *source = container_of(blist, struct comp_buffer, - sink_list); - struct comp_buffer __sparse_cache *source_c = buffer_acquire(source); - - if (source_c->source && source_c->source->state == status) - count++; - buffer_release(source_c); - } - - return count; -} -#endif - int module_adapter_trigger(struct comp_dev *dev, int cmd) { struct processing_module *mod = comp_get_drvdata(dev); @@ -1366,28 +1394,7 @@ int module_adapter_trigger(struct comp_dev *dev, int cmd) return PPL_STATUS_PATH_STOP; } -#if CONFIG_IPC_MAJOR_3 - if (mod->num_input_buffers > 1) { - bool sources_active; - int ret; - - sources_active = module_source_status_count(dev, COMP_STATE_ACTIVE) || - module_source_status_count(dev, COMP_STATE_PAUSED); - - /* don't stop/start module if one of the sources is active/paused */ - if ((cmd == COMP_TRIGGER_STOP || cmd == COMP_TRIGGER_PRE_START) && sources_active) { - dev->state = COMP_STATE_ACTIVE; - return PPL_STATUS_PATH_STOP; - } - - ret = comp_set_state(dev, cmd); - if (ret == COMP_STATUS_STATE_ALREADY_SET) - return PPL_STATUS_PATH_STOP; - - return ret; - } -#endif - return comp_set_state(dev, cmd); + return module_adapter_set_state(mod, dev, cmd); } int module_adapter_reset(struct comp_dev *dev) @@ -1406,16 +1413,50 @@ int module_adapter_reset(struct comp_dev *dev) } if (IS_PROCESSING_MODE_RAW_DATA(mod)) { - for (i = 0; i < mod->num_output_buffers; i++) + for (i = 0; i < mod->num_of_sinks; i++) rfree((__sparse_force void *)mod->output_buffers[i].data); - for (i = 0; i < mod->num_input_buffers; i++) + for (i = 0; i < mod->num_of_sources; i++) rfree((__sparse_force void *)mod->input_buffers[i].data); } - rfree(mod->output_buffers); - rfree(mod->input_buffers); - mod->num_input_buffers = 0; - mod->num_output_buffers = 0; + if (IS_PROCESSING_MODE_RAW_DATA(mod) || IS_PROCESSING_MODE_AUDIO_STREAM(mod)) { + rfree(mod->output_buffers); + rfree(mod->input_buffers); + + mod->num_of_sources = 0; + mod->num_of_sinks = 0; + } +#if CONFIG_ZEPHYR_DP_SCHEDULER + if (IS_PROCESSING_MODE_SINK_SOURCE(mod) && + mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { + /* for DP processing - free DP Queues */ + struct list_item *dp_queue_list_item; + struct list_item *tmp; + + list_for_item_safe(dp_queue_list_item, tmp, &mod->dp_queue_dp_to_ll_list) { + struct dp_queue *dp_queue = + container_of(dp_queue_list_item, struct dp_queue, list); + + /* dp free will also remove the queue from a list */ + dp_queue_free(dp_queue); + } + list_for_item_safe(dp_queue_list_item, tmp, &mod->dp_queue_ll_to_dp_list) { + struct dp_queue *dp_queue = + container_of(dp_queue_list_item, struct dp_queue, list); + + dp_queue_free(dp_queue); + } + } +#endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ + if (IS_PROCESSING_MODE_SINK_SOURCE(mod)) { + /* for both LL and DP processing */ + for (int i = 0; i < mod->num_of_sources; i++) + mod->sources[i] = NULL; + for (int i = 0; i < mod->num_of_sinks; i++) + mod->sinks[i] = NULL; + mod->num_of_sinks = 0; + mod->num_of_sources = 0; + } mod->total_data_consumed = 0; mod->total_data_produced = 0; @@ -1423,10 +1464,7 @@ int module_adapter_reset(struct comp_dev *dev) list_for_item(blist, &mod->sink_buffer_list) { struct comp_buffer *buffer = container_of(blist, struct comp_buffer, sink_list); - struct comp_buffer __sparse_cache *buffer_c = buffer_acquire(buffer); - - buffer_zero(buffer_c); - buffer_release(buffer_c); + buffer_zero(buffer); } rfree(mod->stream_params); @@ -1460,7 +1498,6 @@ void module_adapter_free(struct comp_dev *dev) buffer_free(buffer); } - coherent_free_thread(mod->source_info, c); rfree(mod); rfree(dev); } @@ -1573,7 +1610,11 @@ int module_adapter_ts_stop_op(struct comp_dev *dev) * 0 - success * value < 0 - failure. */ +#if CONFIG_ZEPHYR_NATIVE_DRIVERS +int module_adapter_ts_get_op(struct comp_dev *dev, struct dai_ts_data *tsd) +#else int module_adapter_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd) +#endif { struct processing_module *mod = comp_get_drvdata(dev); struct module_data *md = &mod->priv; @@ -1584,253 +1625,3 @@ int module_adapter_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd) return -EOPNOTSUPP; } -#if CONFIG_IPC_MAJOR_4 -int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, - bool last_block, uint32_t data_offset_size, const char *data) -{ - struct processing_module *mod = comp_get_drvdata(dev); - struct module_data *md = &mod->priv; - enum module_cfg_fragment_position pos; - size_t fragment_size; - - /* set fragment position */ - pos = first_last_block_to_frag_pos(first_block, last_block); - - switch (pos) { - case MODULE_CFG_FRAGMENT_SINGLE: - fragment_size = data_offset_size; - break; - case MODULE_CFG_FRAGMENT_MIDDLE: - fragment_size = MAILBOX_DSPBOX_SIZE; - break; - case MODULE_CFG_FRAGMENT_FIRST: - md->new_cfg_size = data_offset_size; - fragment_size = MAILBOX_DSPBOX_SIZE; - break; - case MODULE_CFG_FRAGMENT_LAST: - fragment_size = md->new_cfg_size - data_offset_size; - break; - default: - comp_err(dev, "module_set_large_config(): invalid fragment position"); - return -EINVAL; - } - - if (md->ops->set_configuration) - return md->ops->set_configuration(mod, param_id, pos, data_offset_size, - (const uint8_t *)data, - fragment_size, NULL, 0); - return 0; -} - -int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, - bool last_block, uint32_t *data_offset_size, char *data) -{ - struct processing_module *mod = comp_get_drvdata(dev); - struct module_data *md = &mod->priv; - size_t fragment_size; - - /* set fragment size */ - if (first_block) { - if (last_block) - fragment_size = md->cfg.size; - else - fragment_size = SOF_IPC_MSG_MAX_SIZE; - } else { - if (!last_block) - fragment_size = SOF_IPC_MSG_MAX_SIZE; - else - fragment_size = md->cfg.size - *data_offset_size; - } - - if (md->ops->get_configuration) - return md->ops->get_configuration(mod, param_id, data_offset_size, - (uint8_t *)data, fragment_size); - return 0; -} - -int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value) -{ - struct processing_module *mod = comp_get_drvdata(dev); - - switch (type) { - case COMP_ATTR_BASE_CONFIG: - memcpy_s(value, sizeof(struct ipc4_base_module_cfg), - &mod->priv.cfg.base_cfg, sizeof(mod->priv.cfg.base_cfg)); - break; - default: - return -EINVAL; - } - - return 0; -} - -static bool module_adapter_multi_sink_source_check(struct comp_dev *dev) -{ - struct processing_module *mod = comp_get_drvdata(dev); - struct list_item *blist; - int num_sources = 0; - int num_sinks = 0; - - list_for_item(blist, &dev->bsource_list) - num_sources++; - - list_for_item(blist, &dev->bsink_list) - num_sinks++; - - comp_dbg(dev, "num_sources=%d num_sinks=%d", num_sources, num_sinks); - - if (num_sources != 1 || num_sinks != 1) - return true; - - /* re-assign the source/sink modules */ - mod->sink_comp_buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - mod->source_comp_buffer = list_first_item(&dev->bsource_list, - struct comp_buffer, sink_list); - - return false; -} - -int module_adapter_bind(struct comp_dev *dev, void *data) -{ - struct module_source_info __sparse_cache *mod_source_info; - struct processing_module *mod = comp_get_drvdata(dev); - struct ipc4_module_bind_unbind *bu; - struct comp_dev *source_dev; - int source_index; - int src_id; - int ret; - - ret = module_bind(mod, data); - if (ret < 0) - return ret; - - bu = (struct ipc4_module_bind_unbind *)data; - src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); - - mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_check(dev); - - /* nothing to do if this module is the source during bind */ - if (dev->ipc_config.id == src_id) - return 0; - - source_dev = ipc4_get_comp_dev(src_id); - if (!source_dev) { - comp_err(dev, "module_adapter_bind: no source with ID %d found", src_id); - return -EINVAL; - } - - mod_source_info = module_source_info_acquire(mod->source_info); - - source_index = find_module_source_index(mod_source_info, source_dev); - /* - * this should never happen as source_info should have been already cleared in - * module_adapter_unbind() - */ - if (source_index >= 0) - mod_source_info->sources[source_index] = NULL; - - /* find an empty slot in the source_info array */ - source_index = find_module_source_index(mod_source_info, NULL); - if (source_index < 0) { - /* no free slot in module source_info array */ - comp_err(dev, "Too many inputs!"); - module_source_info_release(mod_source_info); - return -ENOMEM; - } - - /* set the source dev pointer */ - mod_source_info->sources[source_index] = source_dev; - - module_source_info_release(mod_source_info); - - return 0; -} - -int module_adapter_unbind(struct comp_dev *dev, void *data) -{ - struct module_source_info __sparse_cache *mod_source_info; - struct processing_module *mod = comp_get_drvdata(dev); - struct ipc4_module_bind_unbind *bu; - struct comp_dev *source_dev; - int source_index; - int src_id; - int ret; - - ret = module_unbind(mod, data); - if (ret < 0) - return ret; - - bu = (struct ipc4_module_bind_unbind *)data; - src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); - - mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_check(dev); - - /* nothing to do if this module is the source during unbind */ - if (dev->ipc_config.id == src_id) - return 0; - - source_dev = ipc4_get_comp_dev(src_id); - if (!source_dev) { - comp_err(dev, "module_adapter_bind: no source with ID %d found", src_id); - return -EINVAL; - } - - mod_source_info = module_source_info_acquire(mod->source_info); - - /* find the index of the source in the sources array and clear it */ - source_index = find_module_source_index(mod_source_info, source_dev); - if (source_index >= 0) - mod_source_info->sources[source_index] = NULL; - - module_source_info_release(mod_source_info); - - return 0; -} - -uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, - uint32_t stream_no, bool input) -{ - struct processing_module *mod = comp_get_drvdata(dev); - struct module_data *md = &mod->priv; - - if (md->ops->endpoint_ops && md->ops->endpoint_ops->get_total_data_processed) - return md->ops->endpoint_ops->get_total_data_processed(dev, stream_no, input); - - if (input) - return mod->total_data_produced; - else - return mod->total_data_consumed; -} -#else -int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value) -{ - return -EINVAL; -} -int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, - bool last_block, uint32_t data_offset, const char *data) -{ - return 0; -} - -int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, - bool last_block, uint32_t *data_offset, char *data) -{ - return 0; -} - -int module_adapter_bind(struct comp_dev *dev, void *data) -{ - return 0; -} - -int module_adapter_unbind(struct comp_dev *dev, void *data) -{ - return 0; -} - -uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, - uint32_t stream_no, bool input) -{ - return 0; -} -#endif diff --git a/src/audio/module_adapter/module_adapter_ipc3.c b/src/audio/module_adapter/module_adapter_ipc3.c new file mode 100644 index 000000000000..0f9a31be4139 --- /dev/null +++ b/src/audio/module_adapter/module_adapter_ipc3.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. +// +// Author: Baofeng Tian + +/** + * \file + * \brief Module Adapter ipc3: module adapter ipc3 specific code + * \author Baofeng Tian + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL); + +/* + * \module adapter data initialize. + * \param[in] dev - device. + * \param[in] config - component ipc descriptor pointer. + * \param[in] dst - module adapter config data. + * \param[in] spec - passdowned data from driver. + * + * \return: 0 - no error; < 0, error happened. + */ +int module_adapter_init_data(struct comp_dev *dev, + struct module_config *dst, + const struct comp_ipc_config *config, + const void *spec) +{ + int ret; + + const unsigned char *data; + uint32_t size; + + switch (config->type) { + case SOF_COMP_VOLUME: + { + const struct ipc_config_volume *ipc_volume = spec; + + size = sizeof(*ipc_volume); + data = spec; + break; + } + case SOF_COMP_SRC: + { + const struct ipc_config_src *ipc_src = spec; + + size = sizeof(*ipc_src); + data = spec; + break; + } + default: + { + const struct ipc_config_process *ipc_module_adapter = spec; + + size = ipc_module_adapter->size; + data = ipc_module_adapter->data; + break; + } + } + + /* Copy initial config */ + if (size) { + ret = module_load_config(dev, data, size); + if (ret < 0) { + comp_err(dev, "module_adapter_new() error %d: config loading has failed.", + ret); + return ret; + } + dst->init_data = dst->data; + } + + return 0; +} + +void module_adapter_reset_data(struct module_config *dst) +{ +} + +void module_adapter_check_data(struct processing_module *mod, struct comp_dev *dev, + struct comp_buffer *sink) +{ + /* Check if audio stream client has only one source and one sink buffer to use a + * simplified copy function. + */ + if (IS_PROCESSING_MODE_AUDIO_STREAM(mod) && mod->num_of_sources == 1 && + mod->num_of_sinks == 1) { + mod->source_comp_buffer = list_first_item(&dev->bsource_list, + struct comp_buffer, sink_list); + mod->sink_comp_buffer = sink; + mod->stream_copy_single_to_single = true; + } +} + +void module_adapter_set_params(struct processing_module *mod, struct sof_ipc_stream_params *params) +{ +} + +static int module_source_status_count(struct comp_dev *dev, uint32_t status) +{ + struct list_item *blist; + int count = 0; + + /* count source with state == status */ + list_for_item(blist, &dev->bsource_list) { + /* + * FIXME: this is racy, state can be changed by another core. + * This is implicitly protected by serialised IPCs. Even when + * IPCs are processed in the pipeline thread, the next IPC will + * not be sent until the thread has processed and replied to the + * current one. + */ + struct comp_buffer *source = container_of(blist, struct comp_buffer, + sink_list); + + if (source->source && source->source->state == status) + count++; + } + + return count; +} + +int module_adapter_set_state(struct processing_module *mod, struct comp_dev *dev, + int cmd) +{ + if (mod->num_of_sources > 1) { + bool sources_active; + int ret; + + sources_active = module_source_status_count(dev, COMP_STATE_ACTIVE) || + module_source_status_count(dev, COMP_STATE_PAUSED); + + /* don't stop/start module if one of the sources is active/paused */ + if ((cmd == COMP_TRIGGER_STOP || cmd == COMP_TRIGGER_PRE_START) && sources_active) { + dev->state = COMP_STATE_ACTIVE; + return PPL_STATUS_PATH_STOP; + } + + ret = comp_set_state(dev, cmd); + if (ret == COMP_STATUS_STATE_ALREADY_SET) + return PPL_STATUS_PATH_STOP; + + return ret; + } + + return comp_set_state(dev, cmd); +} + diff --git a/src/audio/module_adapter/module_adapter_ipc4.c b/src/audio/module_adapter/module_adapter_ipc4.c new file mode 100644 index 000000000000..65ca8e806e3f --- /dev/null +++ b/src/audio/module_adapter/module_adapter_ipc4.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. +// +// Author: Baofeng Tian + +/** + * \file + * \brief Module Adapter ipc4: module adapter ipc4 specific code + * \author Baofeng Tian + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL); + +/* + * \module adapter data initialize. + * \param[in] dev - device. + * \param[in] config - component ipc descriptor pointer. + * \param[in] dst - module adapter config data. + * \param[in] spec - passdowned data from driver. + * + * \return: 0 - no error; < 0, error happened. + */ +int module_adapter_init_data(struct comp_dev *dev, + struct module_config *dst, + const struct comp_ipc_config *config, + const void *spec) +{ + if (dev->drv->type == SOF_COMP_MODULE_ADAPTER) { + const struct ipc_config_process *ipc_module_adapter = spec; + + dst->init_data = ipc_module_adapter->data; + dst->size = ipc_module_adapter->size; + dst->avail = true; + + memcpy_s(&dst->base_cfg, sizeof(dst->base_cfg), ipc_module_adapter->data, + sizeof(dst->base_cfg)); + } else { + dst->init_data = spec; + } + + return 0; +} + +void module_adapter_reset_data(struct module_config *dst) +{ + dst->init_data = NULL; +} + +void module_adapter_check_data(struct processing_module *mod, struct comp_dev *dev, + struct comp_buffer *sink) +{ +} + +void module_adapter_set_params(struct processing_module *mod, struct sof_ipc_stream_params *params) +{ + ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); + ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, mod->stream_params); +} + +int module_adapter_set_state(struct processing_module *mod, struct comp_dev *dev, + int cmd) +{ + return comp_set_state(dev, cmd); +} + +int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, + bool last_block, uint32_t data_offset_size, const char *data) +{ + struct processing_module *mod = comp_get_drvdata(dev); + struct module_data *md = &mod->priv; + enum module_cfg_fragment_position pos; + size_t fragment_size; + + /* set fragment position */ + pos = first_last_block_to_frag_pos(first_block, last_block); + + switch (pos) { + case MODULE_CFG_FRAGMENT_SINGLE: + fragment_size = data_offset_size; + break; + case MODULE_CFG_FRAGMENT_MIDDLE: + fragment_size = MAILBOX_DSPBOX_SIZE; + break; + case MODULE_CFG_FRAGMENT_FIRST: + md->new_cfg_size = data_offset_size; + fragment_size = MAILBOX_DSPBOX_SIZE; + break; + case MODULE_CFG_FRAGMENT_LAST: + fragment_size = md->new_cfg_size - data_offset_size; + break; + default: + comp_err(dev, "module_set_large_config(): invalid fragment position"); + return -EINVAL; + } + + if (md->ops->set_configuration) + return md->ops->set_configuration(mod, param_id, pos, data_offset_size, + (const uint8_t *)data, + fragment_size, NULL, 0); + return 0; +} + +int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, + bool last_block, uint32_t *data_offset_size, char *data) +{ + struct processing_module *mod = comp_get_drvdata(dev); + struct module_data *md = &mod->priv; + size_t fragment_size; + + /* set fragment size */ + if (first_block) { + if (last_block) + fragment_size = md->cfg.size; + else + fragment_size = SOF_IPC_MSG_MAX_SIZE; + } else { + if (!last_block) + fragment_size = SOF_IPC_MSG_MAX_SIZE; + else + fragment_size = md->cfg.size - *data_offset_size; + } + + if (md->ops->get_configuration) + return md->ops->get_configuration(mod, param_id, data_offset_size, + (uint8_t *)data, fragment_size); + return 0; +} + +int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value) +{ + struct processing_module *mod = comp_get_drvdata(dev); + + switch (type) { + case COMP_ATTR_BASE_CONFIG: + memcpy_s(value, sizeof(struct ipc4_base_module_cfg), + &mod->priv.cfg.base_cfg, sizeof(mod->priv.cfg.base_cfg)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static bool module_adapter_multi_sink_source_check(struct comp_dev *dev) +{ + struct processing_module *mod = comp_get_drvdata(dev); + struct list_item *blist; + int num_sources = 0; + int num_sinks = 0; + + list_for_item(blist, &dev->bsource_list) + num_sources++; + + list_for_item(blist, &dev->bsink_list) + num_sinks++; + + comp_dbg(dev, "num_sources=%d num_sinks=%d", num_sources, num_sinks); + + if (num_sources != 1 || num_sinks != 1) + return true; + + /* re-assign the source/sink modules */ + mod->sink_comp_buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); + mod->source_comp_buffer = list_first_item(&dev->bsource_list, + struct comp_buffer, sink_list); + + return false; +} + +int module_adapter_bind(struct comp_dev *dev, void *data) +{ + struct processing_module *mod = comp_get_drvdata(dev); + int ret; + + ret = module_bind(mod, data); + if (ret < 0) + return ret; + + mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_check(dev); + + return 0; +} + +int module_adapter_unbind(struct comp_dev *dev, void *data) +{ + struct processing_module *mod = comp_get_drvdata(dev); + int ret; + + ret = module_unbind(mod, data); + if (ret < 0) + return ret; + + mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_check(dev); + + return 0; +} + +uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, + uint32_t stream_no, bool input) +{ + struct processing_module *mod = comp_get_drvdata(dev); + struct module_data *md = &mod->priv; + + if (md->ops->endpoint_ops && md->ops->endpoint_ops->get_total_data_processed) + return md->ops->endpoint_ops->get_total_data_processed(dev, stream_no, input); + + if (input) + return mod->total_data_produced; + else + return mod->total_data_consumed; +} + diff --git a/src/audio/multiband_drc/multiband_drc.c b/src/audio/multiband_drc/multiband_drc.c index a23a6eebc830..fe1c11f3cdab 100644 --- a/src/audio/multiband_drc/multiband_drc.c +++ b/src/audio/multiband_drc/multiband_drc.c @@ -251,11 +251,10 @@ static int multiband_drc_init(struct processing_module *mod) cd->multiband_drc_func = NULL; cd->crossover_split = NULL; #if CONFIG_IPC_MAJOR_4 - /* Note: Currently there is no ALSA switch control in IPC4 to control - * processing on/off. This workaround can be removed after is available. - * Binary control for configuration blob can be used instead. There is - * no processing bypass control in the blob but all processing can be - * switched to neutral with supported min. 2-band mode. + /* Initialize to enabled is a workaround for IPC4 kernel version 6.6 and + * before where the processing is never enabled via switch control. New + * kernel sends the IPC4 switch control and sets this to desired state + * before prepare. */ cd->process_enabled = true; #else @@ -321,18 +320,42 @@ static int multiband_drc_cmd_set_value(struct processing_module *mod, } #endif -static int multiband_drc_set_config(struct processing_module *mod, uint32_t config_id, +static int multiband_drc_set_config(struct processing_module *mod, uint32_t param_id, enum module_cfg_fragment_position pos, uint32_t data_offset_size, const uint8_t *fragment, size_t fragment_size, uint8_t *response, size_t response_size) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; - comp_dbg(mod->dev, "multiband_drc_set_config()"); + comp_dbg(dev, "multiband_drc_set_config()"); -#if CONFIG_IPC_MAJOR_3 - /* Other control types are possible only with IPC3 */ +#if CONFIG_IPC_MAJOR_4 + struct sof_ipc4_control_msg_payload *ctl = (struct sof_ipc4_control_msg_payload *)fragment; + + switch (param_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + comp_dbg(dev, "SOF_IPC4_SWITCH_CONTROL_PARAM_ID id = %d, num_elems = %d", + ctl->id, ctl->num_elems); + + if (ctl->id == 0 && ctl->num_elems == 1) { + cd->process_enabled = ctl->chanv[0].value; + comp_info(dev, "process_enabled = %d", cd->process_enabled); + } else { + comp_err(dev, "Illegal control id = %d, num_elems = %d", + ctl->id, ctl->num_elems); + return -EINVAL; + } + + return 0; + + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + comp_err(dev, "multiband_drc_set_config(), illegal control."); + return -EINVAL; + } + +#elif CONFIG_IPC_MAJOR_3 struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; if (cdata->cmd != SOF_CTRL_CMD_BINARY) @@ -388,8 +411,8 @@ static int multiband_drc_get_config(struct processing_module *mod, return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); } -static void multiband_drc_set_alignment(struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink) +static void multiband_drc_set_alignment(struct audio_stream *source, + struct audio_stream *sink) { /* Currently no optimizations those would use wider loads and stores */ audio_stream_init_alignment_constants(1, 1, source); @@ -403,8 +426,8 @@ static int multiband_drc_process(struct processing_module *mod, { struct multiband_drc_comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct audio_stream __sparse_cache *source = input_buffers[0].data; - struct audio_stream __sparse_cache *sink = output_buffers[0].data; + struct audio_stream *source = input_buffers[0].data; + struct audio_stream *sink = output_buffers[0].data; int frames = input_buffers[0].size; int ret; @@ -435,7 +458,6 @@ static int multiband_drc_params(struct processing_module *mod) struct sof_ipc_stream_params comp_params; struct comp_dev *dev = mod->dev; struct comp_buffer *sinkb; - struct comp_buffer __sparse_cache *sink_c; enum sof_ipc_frame valid_fmt, frame_fmt; int i, ret; @@ -458,21 +480,19 @@ static int multiband_drc_params(struct processing_module *mod) component_set_nearest_period_frames(dev, comp_params.rate); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sinkb); - ret = buffer_set_params(sink_c, &comp_params, true); - buffer_release(sink_c); + ret = buffer_set_params(sinkb, &comp_params, true); + return ret; } #endif /* CONFIG_IPC_MAJOR_4 */ static int multiband_drc_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; int channels; int rate; int ret = 0; @@ -489,17 +509,12 @@ static int multiband_drc_prepare(struct processing_module *mod, sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - multiband_drc_set_alignment(&source_c->stream, &sink_c->stream); + multiband_drc_set_alignment(&sourceb->stream, &sinkb->stream); /* get source data format */ - cd->source_format = audio_stream_get_frm_fmt(&source_c->stream); - channels = audio_stream_get_channels(&source_c->stream); - rate = audio_stream_get_rate(&source_c->stream); - - buffer_release(sink_c); - buffer_release(source_c); + cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); + channels = audio_stream_get_channels(&sourceb->stream); + rate = audio_stream_get_rate(&sourceb->stream); /* Initialize DRC */ comp_dbg(dev, "multiband_drc_prepare(), source_format=%d, sink_format=%d", @@ -551,8 +566,8 @@ static int multiband_drc_reset(struct processing_module *mod) return 0; } -static struct module_interface multiband_drc_interface = { - .init = multiband_drc_init, +static const struct module_interface multiband_drc_interface = { + .init = multiband_drc_init, .prepare = multiband_drc_prepare, .process_audio_stream = multiband_drc_process, .set_configuration = multiband_drc_set_config, diff --git a/src/audio/multiband_drc/multiband_drc_generic.c b/src/audio/multiband_drc/multiband_drc_generic.c index e4d3014c9270..fff21e2653bf 100644 --- a/src/audio/multiband_drc/multiband_drc_generic.c +++ b/src/audio/multiband_drc/multiband_drc_generic.c @@ -11,8 +11,8 @@ #include static void multiband_drc_default_pass(const struct processing_module *mod, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames) { audio_stream_copy(source, 0, sink, 0, audio_stream_get_channels(source) * frames); @@ -203,8 +203,8 @@ static void multiband_drc_process_deemp(struct multiband_drc_state *state, */ #if CONFIG_FORMAT_S16LE static void multiband_drc_s16_default(const struct processing_module *mod, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); @@ -270,8 +270,8 @@ static void multiband_drc_s16_default(const struct processing_module *mod, #if CONFIG_FORMAT_S24LE static void multiband_drc_s24_default(const struct processing_module *mod, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); @@ -337,8 +337,8 @@ static void multiband_drc_s24_default(const struct processing_module *mod, #if CONFIG_FORMAT_S32LE static void multiband_drc_s32_default(const struct processing_module *mod, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); diff --git a/src/audio/mux/mux.c b/src/audio/mux/mux.c index 3223f515438c..92d278a22186 100644 --- a/src/audio/mux/mux.c +++ b/src/audio/mux/mux.c @@ -274,7 +274,6 @@ static void set_mux_params(struct processing_module *mod) struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; struct comp_buffer *sink, *source; - struct comp_buffer __sparse_cache *sink_c, *source_c; struct list_item *source_list; int j; const uint32_t byte_align = 1; @@ -298,15 +297,13 @@ static void set_mux_params(struct processing_module *mod) /* update sink format */ if (!list_is_empty(&dev->bsink_list)) { sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); audio_stream_init_alignment_constants(byte_align, frame_align_req, - &sink_c->stream); + &sink->stream); - if (!sink_c->hw_params_configured) { - ipc4_update_buffer_format(sink_c, &cd->md.output_format); - params->frame_fmt = audio_stream_get_frm_fmt(&sink_c->stream); + if (!sink->hw_params_configured) { + ipc4_update_buffer_format(sink, &cd->md.output_format); + params->frame_fmt = audio_stream_get_frm_fmt(&sink->stream); } - buffer_release(sink_c); } /* update each source format */ @@ -316,18 +313,16 @@ static void set_mux_params(struct processing_module *mod) list_for_item(source_list, &dev->bsource_list) { source = container_of(source_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(source); audio_stream_init_alignment_constants(byte_align, frame_align_req, - &source_c->stream); - j = source_c->id; - cd->config.streams[j].pipeline_id = source_c->pipeline_id; + &source->stream); + j = source->id; + cd->config.streams[j].pipeline_id = source->pipeline_id; if (j == BASE_CFG_QUEUED_ID) audio_fmt = &cd->md.base_cfg.audio_fmt; else audio_fmt = &cd->md.reference_format; - ipc4_update_buffer_format(source_c, audio_fmt); - buffer_release(source_c); + ipc4_update_buffer_format(source, audio_fmt); } } @@ -375,10 +370,10 @@ static struct mux_look_up *get_lookup_table(struct comp_dev *dev, struct comp_da } static void mux_prepare_active_look_up(struct comp_data *cd, - struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources) + struct audio_stream *sink, + const struct audio_stream **sources) { - const struct audio_stream __sparse_cache *source; + const struct audio_stream *source; int elem; int active_elem = 0; @@ -400,8 +395,8 @@ static void mux_prepare_active_look_up(struct comp_data *cd, } static void demux_prepare_active_look_up(struct comp_data *cd, - struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, + struct audio_stream *sink, + const struct audio_stream *source, struct mux_look_up *look_up) { int elem; @@ -429,8 +424,7 @@ static int demux_process(struct processing_module *mod, struct comp_dev *dev = mod->dev; struct list_item *clist; struct comp_buffer *sink; - struct comp_buffer __sparse_cache *sink_c; - struct audio_stream __sparse_cache *sinks_stream[MUX_MAX_STREAMS] = { NULL }; + struct audio_stream *sinks_stream[MUX_MAX_STREAMS] = { NULL }; struct mux_look_up *look_ups[MUX_MAX_STREAMS] = { NULL }; int frames; int sink_bytes; @@ -442,20 +436,16 @@ static int demux_process(struct processing_module *mod, /* align sink streams with their respective configurations */ list_for_item(clist, &dev->bsink_list) { sink = container_of(clist, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - if (sink_c->sink->state == dev->state) { - i = get_stream_index(dev, cd, sink_c->pipeline_id); + if (sink->sink->state == dev->state) { + i = get_stream_index(dev, cd, sink->pipeline_id); /* return if index wrong */ if (i < 0) { - buffer_release(sink_c); return i; } - look_ups[i] = get_lookup_table(dev, cd, sink_c->pipeline_id); - sinks_stream[i] = &sink_c->stream; + look_ups[i] = get_lookup_table(dev, cd, sink->pipeline_id); + sinks_stream[i] = &sink->stream; } - - buffer_release(sink_c); } /* if there are no sinks active, then sinks[] is also empty */ @@ -487,9 +477,8 @@ static int mux_process(struct processing_module *mod, struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; struct comp_buffer *source; - struct comp_buffer __sparse_cache *source_c; struct list_item *clist; - const struct audio_stream __sparse_cache *sources_stream[MUX_MAX_STREAMS] = { NULL }; + const struct audio_stream *sources_stream[MUX_MAX_STREAMS] = { NULL }; int frames = 0; int sink_bytes; int source_bytes; @@ -501,23 +490,20 @@ static int mux_process(struct processing_module *mod, j = 0; list_for_item(clist, &dev->bsource_list) { source = container_of(clist, struct comp_buffer, sink_list); - source_c = buffer_acquire(source); - if (source_c->source->state == dev->state) { + if (source->source->state == dev->state) { if (frames) frames = MIN(frames, input_buffers[j].size); else frames = input_buffers[j].size; - i = get_stream_index(dev, cd, source_c->pipeline_id); + i = get_stream_index(dev, cd, source->pipeline_id); /* return if index wrong */ if (i < 0) { - buffer_release(source_c); return i; } - sources_stream[i] = &source_c->stream; + sources_stream[i] = &source->stream; } - buffer_release(source_c); j++; } @@ -536,11 +522,8 @@ static int mux_process(struct processing_module *mod, j = 0; list_for_item(clist, &dev->bsource_list) { source = container_of(clist, struct comp_buffer, sink_list); - source_c = buffer_acquire(source); - if (source_c->source->state == dev->state) + if (source->source->state == dev->state) mod->input_buffers[j].consumed = source_bytes; - - buffer_release(source_c); j++; } mod->output_buffers[0].size = sink_bytes; @@ -560,10 +543,7 @@ static int mux_reset(struct processing_module *mod) list_for_item(blist, &dev->bsource_list) { struct comp_buffer *source = container_of(blist, struct comp_buffer, sink_list); - struct comp_buffer __sparse_cache *source_c = buffer_acquire(source); - int state = source_c->source->state; - - buffer_release(source_c); + int state = source->source->state; /* only mux the sources with the same state with mux */ if (state > COMP_STATE_READY) @@ -578,16 +558,14 @@ static int mux_reset(struct processing_module *mod) } static int mux_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_dev *dev = mod->dev; struct comp_data *cd = module_get_private_data(mod); struct list_item *blist; struct comp_buffer *source; struct comp_buffer *sink; - struct comp_buffer __sparse_cache *source_c; - struct comp_buffer __sparse_cache *sink_c; struct sof_mux_config *config; size_t blob_size; int state; @@ -628,10 +606,8 @@ static int mux_prepare(struct processing_module *mod, /* check each mux source state, set source align to 1 byte, 1 frame */ list_for_item(blist, &dev->bsource_list) { source = container_of(blist, struct comp_buffer, sink_list); - source_c = buffer_acquire(source); - state = source_c->source->state; - audio_stream_init_alignment_constants(1, 1, &source_c->stream); - buffer_release(source_c); + state = source->source->state; + audio_stream_init_alignment_constants(1, 1, &source->stream); /* only prepare downstream if we have no active sources */ if (state == COMP_STATE_PAUSED || state == COMP_STATE_ACTIVE) @@ -641,9 +617,7 @@ static int mux_prepare(struct processing_module *mod, /* set sink align to 1 byte, 1 frame */ list_for_item(blist, &dev->bsink_list) { sink = container_of(blist, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - audio_stream_init_alignment_constants(1, 1, &sink_c->stream); - buffer_release(sink_c); + audio_stream_init_alignment_constants(1, 1, &sink->stream); } /* prepare downstream */ @@ -675,8 +649,8 @@ static int mux_set_config(struct processing_module *mod, uint32_t config_id, fragment, fragment_size); } -static struct module_interface mux_interface = { - .init = mux_init, +static const struct module_interface mux_interface = { + .init = mux_init, .set_configuration = mux_set_config, .get_configuration = mux_get_config, .prepare = mux_prepare, @@ -688,8 +662,8 @@ static struct module_interface mux_interface = { DECLARE_MODULE_ADAPTER(mux_interface, mux_uuid, mux_tr); SOF_MODULE_INIT(mux, sys_comp_module_mux_interface_init); -static struct module_interface demux_interface = { - .init = demux_init, +static const struct module_interface demux_interface = { + .init = demux_init, .set_configuration = mux_set_config, .get_configuration = mux_get_config, .prepare = mux_prepare, diff --git a/src/audio/mux/mux_generic.c b/src/audio/mux/mux_generic.c index dd58cedbbd6b..f2b513759f61 100644 --- a/src/audio/mux/mux_generic.c +++ b/src/audio/mux/mux_generic.c @@ -19,11 +19,11 @@ LOG_MODULE_DECLARE(muxdemux, CONFIG_SOF_LOG_LEVEL); -static void mux_check_for_wrap(struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, +static void mux_check_for_wrap(struct audio_stream *sink, + const struct audio_stream **sources, struct mux_look_up *lookup) { - const struct audio_stream __sparse_cache *source; + const struct audio_stream *source; uint32_t elem; /* check sources and destinations for wrap */ @@ -36,8 +36,8 @@ static void mux_check_for_wrap(struct audio_stream __sparse_cache *sink, } } -static void demux_check_for_wrap(struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, +static void demux_check_for_wrap(struct audio_stream *sink, + const struct audio_stream *source, struct mux_look_up *lookup) { uint32_t elem; @@ -53,9 +53,8 @@ static void demux_check_for_wrap(struct audio_stream __sparse_cache *sink, #if CONFIG_FORMAT_S16LE -static uint32_t demux_calc_frames_without_wrap_s16(struct audio_stream __sparse_cache *sink, - const struct audio_stream - __sparse_cache *source, +static uint32_t demux_calc_frames_without_wrap_s16(struct audio_stream *sink, + const struct audio_stream *source, struct mux_look_up *lookup) { uint32_t frames; @@ -79,12 +78,11 @@ static uint32_t demux_calc_frames_without_wrap_s16(struct audio_stream __sparse_ return min_frames; } -static uint32_t mux_calc_frames_without_wrap_s16(struct audio_stream __sparse_cache *sink, - const struct audio_stream - __sparse_cache **sources, +static uint32_t mux_calc_frames_without_wrap_s16(struct audio_stream *sink, + const struct audio_stream **sources, struct mux_look_up *lookup) { - const struct audio_stream __sparse_cache *source; + const struct audio_stream *source; uint32_t frames; uint32_t min_frames; uint32_t elem; @@ -111,11 +109,11 @@ static uint32_t mux_calc_frames_without_wrap_s16(struct audio_stream __sparse_ca return min_frames; } -static void mux_init_look_up_pointers_s16(struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, +static void mux_init_look_up_pointers_s16(struct audio_stream *sink, + const struct audio_stream **sources, struct mux_look_up *lookup) { - const struct audio_stream __sparse_cache *source; + const struct audio_stream *source; uint32_t elem; /* init pointers */ @@ -132,8 +130,8 @@ static void mux_init_look_up_pointers_s16(struct audio_stream __sparse_cache *si } } -static void demux_init_look_up_pointers_s16(struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, +static void demux_init_look_up_pointers_s16(struct audio_stream *sink, + const struct audio_stream *source, struct mux_look_up *lookup) { uint32_t elem; @@ -162,8 +160,8 @@ static void demux_init_look_up_pointers_s16(struct audio_stream __sparse_cache * * @param[in] frames Number of frames to process. * @param[in] lookup mux look up table. */ -static void demux_s16le(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, uint32_t frames, +static void demux_s16le(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream *source, uint32_t frames, struct mux_look_up *lookup) { uint32_t i; @@ -215,8 +213,8 @@ static void demux_s16le(struct comp_dev *dev, struct audio_stream __sparse_cache * @param[in] frames Number of frames to process. * @param[in] lookup mux look up table. */ -static void mux_s16le(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, uint32_t frames, +static void mux_s16le(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream **sources, uint32_t frames, struct mux_look_up *lookup) { uint32_t i; @@ -259,12 +257,11 @@ static void mux_s16le(struct comp_dev *dev, struct audio_stream __sparse_cache * #if CONFIG_FORMAT_S24LE || CONFIG_FORMAT_S32LE -static uint32_t mux_calc_frames_without_wrap_s32(struct audio_stream __sparse_cache *sink, - const struct audio_stream - __sparse_cache **sources, +static uint32_t mux_calc_frames_without_wrap_s32(struct audio_stream *sink, + const struct audio_stream **sources, struct mux_look_up *lookup) { - const struct audio_stream __sparse_cache *source; + const struct audio_stream *source; uint32_t frames; uint32_t min_frames; uint32_t elem; @@ -289,9 +286,8 @@ static uint32_t mux_calc_frames_without_wrap_s32(struct audio_stream __sparse_ca return min_frames; } -static uint32_t demux_calc_frames_without_wrap_s32(struct audio_stream __sparse_cache *sink, - const struct audio_stream - __sparse_cache *source, +static uint32_t demux_calc_frames_without_wrap_s32(struct audio_stream *sink, + const struct audio_stream *source, struct mux_look_up *lookup) { uint32_t frames; @@ -313,11 +309,11 @@ static uint32_t demux_calc_frames_without_wrap_s32(struct audio_stream __sparse_ return min_frames; } -static void mux_init_look_up_pointers_s32(struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, +static void mux_init_look_up_pointers_s32(struct audio_stream *sink, + const struct audio_stream **sources, struct mux_look_up *lookup) { - const struct audio_stream __sparse_cache *source; + const struct audio_stream *source; uint32_t elem; /* init pointers */ @@ -334,8 +330,8 @@ static void mux_init_look_up_pointers_s32(struct audio_stream __sparse_cache *si } } -static void demux_init_look_up_pointers_s32(struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, +static void demux_init_look_up_pointers_s32(struct audio_stream *sink, + const struct audio_stream *source, struct mux_look_up *lookup) { uint32_t elem; @@ -364,8 +360,8 @@ static void demux_init_look_up_pointers_s32(struct audio_stream __sparse_cache * * @param[in] frames Number of frames to process. * @param[in] lookup mux look up table. */ -static void demux_s32le(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, uint32_t frames, +static void demux_s32le(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream *source, uint32_t frames, struct mux_look_up *lookup) { uint32_t i; @@ -417,8 +413,8 @@ static void demux_s32le(struct comp_dev *dev, struct audio_stream __sparse_cache * @param[in] frames Number of frames to process. * @param[in] lookup mux look up table. */ -static void mux_s32le(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, uint32_t frames, +static void mux_s32le(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream **sources, uint32_t frames, struct mux_look_up *lookup) { uint32_t i; @@ -534,8 +530,7 @@ mux_func mux_get_processing_function(struct processing_module *mod) source_list); for (i = 0; i < ARRAY_SIZE(mux_func_map); i++) { - struct comp_buffer __sparse_cache *sink_c = buffer_acquire(sinkb); - enum sof_ipc_frame fmt = audio_stream_get_frm_fmt(&sink_c->stream); + enum sof_ipc_frame fmt = audio_stream_get_frm_fmt(&sinkb->stream); if (fmt == mux_func_map[i].frame_format) @@ -558,10 +553,7 @@ demux_func demux_get_processing_function(struct processing_module *mod) sink_list); for (i = 0; i < ARRAY_SIZE(mux_func_map); i++) { - struct comp_buffer __sparse_cache *source_c = buffer_acquire(sourceb); - enum sof_ipc_frame fmt = audio_stream_get_frm_fmt(&source_c->stream); - - buffer_release(source_c); + enum sof_ipc_frame fmt = audio_stream_get_frm_fmt(&sourceb->stream); if (fmt == mux_func_map[i].frame_format) return mux_func_map[i].demux_proc_func; diff --git a/src/audio/pcm_converter/pcm_converter.c b/src/audio/pcm_converter/pcm_converter.c index 6c3753b8d8e7..5335ee295b51 100644 --- a/src/audio/pcm_converter/pcm_converter.c +++ b/src/audio/pcm_converter/pcm_converter.c @@ -15,8 +15,8 @@ #include #include -int pcm_convert_as_linear(const struct audio_stream __sparse_cache *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, uint32_t ooffset, +int pcm_convert_as_linear(const struct audio_stream *source, uint32_t ioffset, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples, pcm_converter_lin_func converter) { const int s_size_in = audio_stream_sample_bytes(source); diff --git a/src/audio/pcm_converter/pcm_converter_generic.c b/src/audio/pcm_converter/pcm_converter_generic.c index db3bbe9b88d4..6de32bd52495 100644 --- a/src/audio/pcm_converter/pcm_converter_generic.c +++ b/src/audio/pcm_converter/pcm_converter_generic.c @@ -34,9 +34,9 @@ #define BYTES_TO_S32_SAMPLES 2 #if CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE -static int pcm_convert_u8_to_s32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, - uint32_t ooffset, uint32_t samples) +static int pcm_convert_u8_to_s32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, + uint32_t ooffset, uint32_t samples) { uint8_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -63,9 +63,9 @@ static int pcm_convert_u8_to_s32(const struct audio_stream __sparse_cache *sourc return samples; } -static int pcm_convert_s32_to_u8(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, - uint32_t ooffset, uint32_t samples) +static int pcm_convert_s32_to_u8(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, + uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); uint8_t *dst = audio_stream_get_wptr(sink); @@ -95,8 +95,8 @@ static int pcm_convert_s32_to_u8(const struct audio_stream __sparse_cache *sourc #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE -static int pcm_convert_s16_to_s24(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s16_to_s24(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int16_t *src = audio_stream_get_rptr(source); @@ -124,8 +124,8 @@ static int pcm_convert_s16_to_s24(const struct audio_stream __sparse_cache *sour return samples; } -static int pcm_convert_s24_to_s16(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s24_to_s16(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -157,8 +157,8 @@ static int pcm_convert_s24_to_s16(const struct audio_stream __sparse_cache *sour #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S32LE -static int pcm_convert_s16_to_s32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s16_to_s32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int16_t *src = audio_stream_get_rptr(source); @@ -186,8 +186,8 @@ static int pcm_convert_s16_to_s32(const struct audio_stream __sparse_cache *sour return samples; } -static int pcm_convert_s32_to_s16(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s32_to_s16(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -219,8 +219,8 @@ static int pcm_convert_s32_to_s16(const struct audio_stream __sparse_cache *sour #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S32LE -static int pcm_convert_s24_to_s32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s24_to_s32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -248,8 +248,8 @@ static int pcm_convert_s24_to_s32(const struct audio_stream __sparse_cache *sour return samples; } -static int pcm_convert_s32_to_s24(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s32_to_s24(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -277,8 +277,8 @@ static int pcm_convert_s32_to_s24(const struct audio_stream __sparse_cache *sour return samples; } -static int pcm_convert_s32_to_s24_be(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s32_to_s24_be(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -442,16 +442,16 @@ static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst, dst[i] = sat_int16(_pcm_convert_f_to_i(src[i], 15)); } -static int pcm_convert_s16_to_f(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s16_to_f(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s16_to_f_lin); } -static int pcm_convert_f_to_s16(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_f_to_s16(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, @@ -486,16 +486,16 @@ static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst, dst[i] = sat_int24(_pcm_convert_f_to_i(src[i], 23)); } -static int pcm_convert_s24_to_f(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s24_to_f(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s24_to_f_lin); } -static int pcm_convert_f_to_s24(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_f_to_s24(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, @@ -530,16 +530,16 @@ static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst, dst[i] = _pcm_convert_f_to_i(src[i], 31); } -static int pcm_convert_s32_to_f(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s32_to_f(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s32_to_f_lin); } -static int pcm_convert_f_to_s32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_f_to_s32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, @@ -599,8 +599,8 @@ const struct pcm_func_map pcm_func_map[] = { const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map); #if CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32 -static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int16_t *src = audio_stream_get_rptr(source); @@ -628,8 +628,8 @@ static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream __sparse_cac return samples; } -static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -658,8 +658,8 @@ static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream __sparse_cac } #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32 -static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -687,8 +687,8 @@ static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream __sparse_cac return samples; } -static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -717,8 +717,8 @@ static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream __sparse_cac } #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32 -static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -746,8 +746,8 @@ static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream __sparse_cac return samples; } -static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -777,8 +777,8 @@ static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream __sparse_cac #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 -static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { uint8_t *src = audio_stream_get_rptr(source); @@ -807,8 +807,8 @@ static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream __sparse_cac return samples; } -static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -841,8 +841,8 @@ static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream __sparse_cac } /* 2x24bit samples are packed into 3x16bit samples for hda link dma */ -static int pcm_convert_s24_c32_to_s24_c24_link_gtw(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s24_c32_to_s24_c24_link_gtw(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); diff --git a/src/audio/pcm_converter/pcm_converter_hifi3.c b/src/audio/pcm_converter/pcm_converter_hifi3.c index ac5c14b379bc..da7e2ff1c7d1 100644 --- a/src/audio/pcm_converter/pcm_converter_hifi3.c +++ b/src/audio/pcm_converter/pcm_converter_hifi3.c @@ -36,8 +36,8 @@ * \param[in,out] sink Destination buffer. * \param[in] samples Number of samples to process. */ -static int pcm_convert_s16_to_s24(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s16_to_s24(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { ae_int16x4 sample = AE_ZERO16(); @@ -110,8 +110,8 @@ static ae_int32x2 pcm_shift_s24_to_s16(ae_int32x2 sample) * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s24_to_s16(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s24_to_s16(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { ae_int16x4 sample = AE_ZERO16(); @@ -181,8 +181,8 @@ static int pcm_convert_s24_to_s16(const struct audio_stream __sparse_cache *sour * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s16_to_s32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s16_to_s32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int16_t *src = audio_stream_get_rptr(source); @@ -237,8 +237,8 @@ static int pcm_convert_s16_to_s32(const struct audio_stream __sparse_cache *sour * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s32_to_s16(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s32_to_s16(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -303,8 +303,8 @@ static int pcm_convert_s32_to_s16(const struct audio_stream __sparse_cache *sour * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s24_to_s32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s24_to_s32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -368,8 +368,8 @@ static ae_int32x2 pcm_shift_s32_to_s24(ae_int32x2 sample) * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s32_to_s24(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s32_to_s24(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -413,8 +413,8 @@ static int pcm_convert_s32_to_s24(const struct audio_stream __sparse_cache *sour return samples; } -static int pcm_convert_s32_to_s24_be(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s32_to_s24_be(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -541,8 +541,8 @@ static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s16_to_f(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s16_to_f(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, @@ -556,8 +556,8 @@ static int pcm_convert_s16_to_f(const struct audio_stream __sparse_cache *source * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_f_to_s16(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_f_to_s16(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, @@ -642,8 +642,8 @@ static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s24_to_f(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s24_to_f(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, @@ -657,8 +657,8 @@ static int pcm_convert_s24_to_f(const struct audio_stream __sparse_cache *source * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_f_to_s24(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_f_to_s24(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, @@ -739,8 +739,8 @@ static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s32_to_f(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_s32_to_f(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, @@ -754,8 +754,8 @@ static int pcm_convert_s32_to_f(const struct audio_stream __sparse_cache *source * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_f_to_s32(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +static int pcm_convert_f_to_s32(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, @@ -810,9 +810,9 @@ const struct pcm_func_map pcm_func_map[] = { const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map); #if CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32 -static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream __sparse_cache *source, +static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int16_t *src = audio_stream_get_rptr(source); @@ -860,9 +860,9 @@ static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream __sparse_cac return samples; } -static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream __sparse_cache *source, +static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -919,9 +919,9 @@ static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream __sparse_cac #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32 -static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream __sparse_cache *source, +static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -962,9 +962,9 @@ static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream __sparse_cac return samples; } -static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream __sparse_cache *source, +static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -1007,9 +1007,9 @@ static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream __sparse_cac #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32 -static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream __sparse_cache *source, +static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -1062,9 +1062,9 @@ static ae_int32x2 pcm_shift_s24_c32_to_s16(ae_int32x2 sample) return sample; } -static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream __sparse_cache *source, +static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); @@ -1109,9 +1109,9 @@ static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream __sparse_cac #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 -static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream __sparse_cache *source, +static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { uint8_t *src = audio_stream_get_rptr(source); @@ -1156,9 +1156,9 @@ static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream __sparse_cac return samples; } -static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream __sparse_cache *source, +static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples) { int32_t *src = audio_stream_get_rptr(source); diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index 71645c69fa84..82fe49bbed20 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -168,18 +168,10 @@ struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t static void buffer_set_comp(struct comp_buffer *buffer, struct comp_dev *comp, int dir) { - struct comp_buffer __sparse_cache *buffer_c = buffer_acquire(buffer); - if (dir == PPL_CONN_DIR_COMP_TO_BUFFER) - buffer_c->source = comp; + buffer->source = comp; else - buffer_c->sink = comp; - - buffer_release(buffer_c); - - /* The buffer might be marked as shared later, write back the cache */ - if (!buffer->c.shared) - dcache_writeback_invalidate_region(uncache_to_cache(buffer), sizeof(*buffer)); + buffer->sink = comp; } int pipeline_connect(struct comp_dev *comp, struct comp_buffer *buffer, @@ -235,7 +227,9 @@ int pipeline_free(struct pipeline *p) /* remove from any scheduling */ if (p->pipe_task) { +#if !CONFIG_LIBRARY || UNIT_TEST schedule_task_free(p->pipe_task); +#endif rfree(p->pipe_task); } @@ -268,7 +262,14 @@ static int pipeline_comp_complete(struct comp_dev *current, /* complete component init */ current->pipeline = ppl_data->p; - current->period = ppl_data->p->period; + /* LL module has its period always eq period of the pipeline + * DP period is set to 0 as sink format may not yet been set + * It will be calculated during module prepare operation + * either by the module or to default value based on module's OBS + */ + if (current->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) + current->period = ppl_data->p->period; + current->priority = ppl_data->p->priority; return pipeline_for_each_comp(current, ctx, dir); @@ -414,7 +415,6 @@ int pipeline_for_each_comp(struct comp_dev *current, /* run this operation further */ list_for_item(clist, buffer_list) { struct comp_buffer *buffer = buffer_from_list(clist, dir); - struct comp_buffer __sparse_cache *buffer_c; struct comp_dev *buffer_comp; int err = 0; @@ -438,28 +438,22 @@ int pipeline_for_each_comp(struct comp_dev *current, buffer_comp = buffer_get_comp(buffer, dir); - buffer_c = buffer_acquire(buffer); - /* execute operation on buffer */ if (ctx->buff_func) - ctx->buff_func(buffer_c, ctx->buff_data); + ctx->buff_func(buffer, ctx->buff_data); /* don't go further if this component is not connected */ if (buffer_comp && (!ctx->skip_incomplete || buffer_comp->pipeline) && ctx->comp_func) { - buffer_c->walking = true; - buffer_release(buffer_c); + buffer->walking = true; err = ctx->comp_func(buffer_comp, buffer, ctx, dir); - buffer_c = buffer_acquire(buffer); - buffer_c->walking = false; + buffer->walking = false; } - buffer_release(buffer_c); - if (err < 0 || err == PPL_STATUS_PATH_STOP) return err; } diff --git a/src/audio/pipeline/pipeline-params.c b/src/audio/pipeline/pipeline-params.c index 43974e290fb4..ecf27bfa3d3c 100644 --- a/src/audio/pipeline/pipeline-params.c +++ b/src/audio/pipeline/pipeline-params.c @@ -30,7 +30,6 @@ static int pipeline_comp_params_neg(struct comp_dev *current, int dir) { struct pipeline_data *ppl_data = ctx->comp_data; - struct comp_buffer __sparse_cache *buf_c = buffer_acquire(calling_buf); int err = 0; pipe_dbg(current->pipeline, "pipeline_comp_params_neg(), current->comp.id = %u, dir = %u", @@ -48,12 +47,12 @@ static int pipeline_comp_params_neg(struct comp_dev *current, * a component who has different channels input/output buffers * should explicitly configure the channels of the branched buffers. */ - err = buffer_set_params(buf_c, &ppl_data->params->params, + err = buffer_set_params(calling_buf, &ppl_data->params->params, BUFFER_UPDATE_FORCE); break; default: /* return 0 if params matches */ - if (!buffer_params_match(buf_c, + if (!buffer_params_match(calling_buf, &ppl_data->params->params, BUFF_PARAMS_FRAME_FMT | BUFF_PARAMS_RATE)) { @@ -66,8 +65,6 @@ static int pipeline_comp_params_neg(struct comp_dev *current, err = -EINVAL; } } - - buffer_release(buf_c); return err; } @@ -131,7 +128,7 @@ static int pipeline_comp_params(struct comp_dev *current, } /* save params changes made by component */ -static void pipeline_update_buffer_pcm_params(struct comp_buffer __sparse_cache *buffer, +static void pipeline_update_buffer_pcm_params(struct comp_buffer *buffer, void *data) { struct sof_ipc_stream_params *params = data; @@ -188,11 +185,8 @@ static int pipeline_comp_hw_params_buf(struct comp_dev *current, return ret; /* set buffer parameters */ if (calling_buf) { - struct comp_buffer __sparse_cache *buf_c = buffer_acquire(calling_buf); - - ret = buffer_set_params(buf_c, &ppl_data->params->params, + ret = buffer_set_params(calling_buf, &ppl_data->params->params, BUFFER_UPDATE_IF_UNSET); - buffer_release(buf_c); if (ret < 0) pipe_err(current->pipeline, "pipeline_comp_hw_params(): buffer_set_params(): %d", ret); @@ -317,36 +311,13 @@ static int pipeline_comp_prepare(struct comp_dev *current, } } - switch (current->ipc_config.proc_domain) { - case COMP_PROCESSING_DOMAIN_LL: - /* this is a LL scheduled module */ + if (current->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) { + /* init a task for LL module, DP task has been created in during init_instance */ err = pipeline_comp_ll_task_init(current->pipeline); - break; - -#if CONFIG_ZEPHYR_DP_SCHEDULER - case COMP_PROCESSING_DOMAIN_DP: - /* this is a DP scheduled module */ - - /* - * workaround - because of some issues with cache, currently we can allow DP - * modules to run on the same core as LL pipeline only. - * to be removed once buffering is fixed - */ - if (current->pipeline->core != current->ipc_config.core) - err = -EINVAL; - else - err = pipeline_comp_dp_task_init(current); - - break; -#endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ - - default: - err = -EINVAL; + if (err < 0) + return err; } - if (err < 0) - return err; - err = comp_prepare(current); if (err < 0 || err == PPL_STATUS_PATH_STOP) return err; diff --git a/src/audio/pipeline/pipeline-schedule.c b/src/audio/pipeline/pipeline-schedule.c index a4a7a71da50f..0a61752079e9 100644 --- a/src/audio/pipeline/pipeline-schedule.c +++ b/src/audio/pipeline/pipeline-schedule.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -378,15 +379,18 @@ int pipeline_comp_ll_task_init(struct pipeline *p) #if CONFIG_ZEPHYR_DP_SCHEDULER static enum task_state dp_task_run(void *data) { - struct comp_dev *comp = data; + struct processing_module *mod = data; + + module_process_sink_src(mod, mod->sources, mod->num_of_sources, + mod->sinks, mod->num_of_sinks); - comp->drv->ops.copy(comp); return SOF_TASK_STATE_RESCHEDULE; } int pipeline_comp_dp_task_init(struct comp_dev *comp) { int ret; + struct processing_module *mod = comp_get_drvdata(comp); struct task_ops ops = { .run = dp_task_run, .get_deadline = NULL, @@ -397,7 +401,7 @@ int pipeline_comp_dp_task_init(struct comp_dev *comp) ret = scheduler_dp_task_init(&comp->task, SOF_UUID(dp_task_uuid), &ops, - comp, + mod, comp->ipc_config.core, TASK_DP_STACK_SIZE, ZEPHYR_DP_THREAD_PRIORITY); diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index 6fe795cf54f5..547b3198f311 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -147,6 +147,37 @@ int pipeline_copy(struct pipeline *p) return ret; } +#if CONFIG_LIBRARY && !CONFIG_LIBRARY_STATIC +/* trigger pipeline immediately in IPC context. TODO: Add support for XRUN */ +int pipeline_trigger(struct pipeline *p, struct comp_dev *host, int cmd) +{ + int ret; + + pipe_info(p, "pipe trigger cmd %d", cmd); + + p->trigger.aborted = false; + + ret = pipeline_trigger_run(p, host, cmd); + if (ret < 0) + return ret; + + switch (cmd) { + case COMP_TRIGGER_PRE_START: + case COMP_TRIGGER_START: + case COMP_TRIGGER_PRE_RELEASE: + p->status = COMP_STATE_ACTIVE; + break; + case COMP_TRIGGER_STOP: + case COMP_TRIGGER_PAUSE: + p->status = COMP_STATE_PAUSED; + break; + default: + break; + } + + return 0; +} +#else /* only collect scheduling components */ static int pipeline_comp_list(struct comp_dev *current, struct comp_buffer *calling_buf, @@ -304,6 +335,7 @@ int pipeline_trigger(struct pipeline *p, struct comp_dev *host, int cmd) return 0; } +#endif /* Runs in IPC or in pipeline task context */ static int pipeline_comp_trigger(struct comp_dev *current, diff --git a/src/audio/rtnr/rtnr.c b/src/audio/rtnr/rtnr.c index 8c3ce8496c14..49db44eac1cb 100644 --- a/src/audio/rtnr/rtnr.c +++ b/src/audio/rtnr/rtnr.c @@ -325,7 +325,6 @@ static int rtnr_params(struct comp_dev *dev, struct sof_ipc_stream_params *param int ret; struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sinkb, *sourceb; - struct comp_buffer __sparse_cache *sink_c, *source_c; bool channels_valid; comp_info(dev, "rtnr_params()"); @@ -341,21 +340,17 @@ static int rtnr_params(struct comp_dev *dev, struct sof_ipc_stream_params *param sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - /* set source/sink_frames/rate */ - cd->source_rate = audio_stream_get_rate(&source_c->stream); - cd->sink_rate = audio_stream_get_rate(&sink_c->stream); - cd->sources_stream[0].rate = audio_stream_get_rate(&source_c->stream); - cd->sink_stream.rate = audio_stream_get_rate(&sink_c->stream); - channels_valid = audio_stream_get_channels(&source_c->stream) == - audio_stream_get_channels(&sink_c->stream); + cd->source_rate = audio_stream_get_rate(&sourceb->stream); + cd->sink_rate = audio_stream_get_rate(&sinkb->stream); + cd->sources_stream[0].rate = audio_stream_get_rate(&sourceb->stream); + cd->sink_stream.rate = audio_stream_get_rate(&sinkb->stream); + channels_valid = audio_stream_get_channels(&sourceb->stream) == + audio_stream_get_channels(&sinkb->stream); if (!cd->sink_rate) { comp_err(dev, "rtnr_nr_params(), zero sink rate"); - ret = -EINVAL; - goto out; + return -EINVAL; } /* Currently support 16kHz sample rate only. */ @@ -369,31 +364,25 @@ static int rtnr_params(struct comp_dev *dev, struct sof_ipc_stream_params *param default: comp_err(dev, "rtnr_nr_params(), invalid sample rate(%d kHz)", cd->source_rate); - ret = -EINVAL; - goto out; + return -EINVAL; } if (!channels_valid) { comp_err(dev, "rtnr_params(), source/sink stream must have same channels"); - ret = -EINVAL; - goto out; + return -EINVAL; } /* set source/sink stream channels */ - cd->sources_stream[0].channels = audio_stream_get_channels(&source_c->stream); - cd->sink_stream.channels = audio_stream_get_channels(&sink_c->stream); + cd->sources_stream[0].channels = audio_stream_get_channels(&sourceb->stream); + cd->sink_stream.channels = audio_stream_get_channels(&sinkb->stream); /* set source/sink stream overrun/underrun permitted */ - cd->sources_stream[0].overrun_permitted = audio_stream_get_overrun(&source_c->stream); - cd->sink_stream.overrun_permitted = audio_stream_get_overrun(&sink_c->stream); - cd->sources_stream[0].underrun_permitted = audio_stream_get_underrun(&source_c->stream); - cd->sink_stream.underrun_permitted = audio_stream_get_underrun(&sink_c->stream); - -out: - buffer_release(sink_c); - buffer_release(source_c); + cd->sources_stream[0].overrun_permitted = audio_stream_get_overrun(&sourceb->stream); + cd->sink_stream.overrun_permitted = audio_stream_get_overrun(&sinkb->stream); + cd->sources_stream[0].underrun_permitted = audio_stream_get_underrun(&sourceb->stream); + cd->sink_stream.underrun_permitted = audio_stream_get_underrun(&sinkb->stream); - return ret; + return 0; } static int rtnr_get_comp_config(struct comp_data *cd, struct sof_ipc_ctrl_data *cdata, @@ -727,7 +716,7 @@ static int rtnr_trigger(struct comp_dev *dev, int cmd) } static void rtnr_copy_from_sof_stream(struct audio_stream_rtnr *dst, - struct audio_stream __sparse_cache *src) + struct audio_stream *src) { dst->size = audio_stream_get_size(src); @@ -739,7 +728,7 @@ static void rtnr_copy_from_sof_stream(struct audio_stream_rtnr *dst, dst->end_addr = audio_stream_get_end_addr(src); } -static void rtnr_copy_to_sof_stream(struct audio_stream __sparse_cache *dst, +static void rtnr_copy_to_sof_stream(struct audio_stream *dst, struct audio_stream_rtnr *src) { audio_stream_set_size(dst, src->size); @@ -832,7 +821,7 @@ static int rtnr_copy(struct comp_dev *dev) comp_dbg(dev, "rtnr_copy() passthrough"); /* Get source, sink, number of frames etc. to process. */ - comp_get_copy_limits_with_lock(source, sink, &cl); + comp_get_copy_limits(source, sink, &cl); buffer_stream_invalidate(source, cl.source_bytes); @@ -851,7 +840,7 @@ static int rtnr_prepare(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sinkb; - struct comp_buffer __sparse_cache *sink_c; + struct comp_buffer *sink_c; int ret; comp_dbg(dev, "rtnr_prepare()"); @@ -874,10 +863,8 @@ static int rtnr_prepare(struct comp_dev *dev) /* Get sink data format */ sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sinkb); - cd->sink_format = audio_stream_get_frm_fmt(&sink_c->stream); - cd->sink_stream.frame_fmt = audio_stream_get_frm_fmt(&sink_c->stream); - buffer_release(sink_c); + cd->sink_format = audio_stream_get_frm_fmt(&sinkb->stream); + cd->sink_stream.frame_fmt = audio_stream_get_frm_fmt(&sinkb->stream); /* Check source and sink PCM format and get processing function */ comp_info(dev, "rtnr_prepare(), sink_format=%d", cd->sink_format); diff --git a/src/audio/selector/selector.c b/src/audio/selector/selector.c index 8a39db81b2ef..97126168ac77 100644 --- a/src/audio/selector/selector.c +++ b/src/audio/selector/selector.c @@ -60,7 +60,6 @@ static int selector_verify_params(struct comp_dev *dev, { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *buffer, *sinkb; - struct comp_buffer __sparse_cache *buffer_c, *sink_c; uint32_t in_channels; uint32_t out_channels; @@ -86,15 +85,13 @@ static int selector_verify_params(struct comp_dev *dev, } in_channels = cd->config.in_channels_count; - buffer_c = buffer_acquire(buffer); - /* if cd->config.out_channels_count are equal to 0 * (it can vary), we set params->channels to sink buffer * channels, which were previously set in * pipeline_comp_hw_params() */ out_channels = cd->config.out_channels_count ? - cd->config.out_channels_count : audio_stream_get_channels(&buffer_c->stream); + cd->config.out_channels_count : audio_stream_get_channels(&buffer->stream); params->channels = out_channels; } else { /* fetch source buffer for capture */ @@ -107,27 +104,21 @@ static int selector_verify_params(struct comp_dev *dev, } out_channels = cd->config.out_channels_count; - buffer_c = buffer_acquire(buffer); - /* if cd->config.in_channels_count are equal to 0 * (it can vary), we set params->channels to source buffer * channels, which were previously set in * pipeline_comp_hw_params() */ in_channels = cd->config.in_channels_count ? - cd->config.in_channels_count : audio_stream_get_channels(&buffer_c->stream); + cd->config.in_channels_count : audio_stream_get_channels(&buffer->stream); params->channels = in_channels; } /* Set buffer params */ - buffer_set_params(buffer_c, params, BUFFER_UPDATE_FORCE); - - buffer_release(buffer_c); + buffer_set_params(buffer, params, BUFFER_UPDATE_FORCE); /* set component period frames */ - sink_c = buffer_acquire(sinkb); - component_set_nearest_period_frames(dev, audio_stream_get_rate(&sink_c->stream)); - buffer_release(sink_c); + component_set_nearest_period_frames(dev, audio_stream_get_rate(&sinkb->stream)); /* verify input channels */ switch (in_channels) { @@ -358,7 +349,6 @@ static int selector_cmd(struct comp_dev *dev, int cmd, void *data, static int selector_trigger(struct comp_dev *dev, int cmd) { struct comp_buffer *sourceb; - struct comp_buffer __sparse_cache *source_c; enum sof_comp_type type; int ret; @@ -367,17 +357,13 @@ static int selector_trigger(struct comp_dev *dev, int cmd) sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(sourceb); - ret = comp_set_state(dev, cmd); /* TODO: remove in the future after adding support for case when * kpb_init_draining() and kpb_draining_task() are interrupted by * new pipeline_task() */ - type = dev_comp_type(source_c->source); - - buffer_release(source_c); + type = dev_comp_type(sourceb->source); return type == SOF_COMP_KPB ? PPL_STATUS_PATH_TERMINATE : ret; } @@ -391,7 +377,6 @@ static int selector_copy(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sink, *source; - struct comp_buffer __sparse_cache *sink_c, *source_c; uint32_t frames; uint32_t source_bytes; uint32_t sink_bytes; @@ -404,33 +389,24 @@ static int selector_copy(struct comp_dev *dev) sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(source); - - if (!audio_stream_get_avail(&source_c->stream)) { - buffer_release(source_c); + if (!audio_stream_get_avail(&source->stream)) return PPL_STATUS_PATH_STOP; - } - sink_c = buffer_acquire(sink); - - frames = audio_stream_avail_frames(&source_c->stream, &sink_c->stream); - source_bytes = frames * audio_stream_frame_bytes(&source_c->stream); - sink_bytes = frames * audio_stream_frame_bytes(&sink_c->stream); + frames = audio_stream_avail_frames(&source->stream, &sink->stream); + source_bytes = frames * audio_stream_frame_bytes(&source->stream); + sink_bytes = frames * audio_stream_frame_bytes(&sink->stream); comp_dbg(dev, "selector_copy(), source_bytes = 0x%x, sink_bytes = 0x%x", source_bytes, sink_bytes); /* copy selected channels from in to out */ - buffer_stream_invalidate(source_c, source_bytes); - cd->sel_func(dev, &sink_c->stream, &source_c->stream, frames); - buffer_stream_writeback(sink_c, sink_bytes); + buffer_stream_invalidate(source, source_bytes); + cd->sel_func(dev, &sink->stream, &source->stream, frames); + buffer_stream_writeback(sink, sink_bytes); /* calculate new free and available */ - comp_update_buffer_produce(sink_c, sink_bytes); - comp_update_buffer_consume(source_c, source_bytes); - - buffer_release(sink_c); - buffer_release(source_c); + comp_update_buffer_produce(sink, sink_bytes); + comp_update_buffer_consume(source, source_bytes); return 0; } @@ -444,7 +420,6 @@ static int selector_prepare(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sinkb, *sourceb; - struct comp_buffer __sparse_cache *sink_c, *source_c; size_t sink_size; int ret; @@ -463,30 +438,24 @@ static int selector_prepare(struct comp_dev *dev) sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - /* get source data format and period bytes */ - cd->source_format = audio_stream_get_frm_fmt(&source_c->stream); - cd->source_period_bytes = audio_stream_period_bytes(&source_c->stream, dev->frames); + cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); + cd->source_period_bytes = audio_stream_period_bytes(&sourceb->stream, dev->frames); /* get sink data format and period bytes */ - cd->sink_format = audio_stream_get_frm_fmt(&sink_c->stream); - cd->sink_period_bytes = audio_stream_period_bytes(&sink_c->stream, dev->frames); + cd->sink_format = audio_stream_get_frm_fmt(&sinkb->stream); + cd->sink_period_bytes = audio_stream_period_bytes(&sinkb->stream, dev->frames); /* There is an assumption that sink component will report out * proper number of channels [1] for selector to actually * reduce channel count between source and sink */ comp_dbg(dev, "selector_prepare(): sourceb->schannels = %u", - audio_stream_get_channels(&source_c->stream)); + audio_stream_get_channels(&sourceb->stream)); comp_dbg(dev, "selector_prepare(): sinkb->channels = %u", - audio_stream_get_channels(&sink_c->stream)); - - sink_size = audio_stream_get_size(&sink_c->stream); + audio_stream_get_channels(&sinkb->stream)); - buffer_release(sink_c); - buffer_release(source_c); + sink_size = audio_stream_get_size(&sinkb->stream); if (sink_size < cd->sink_period_bytes) { comp_err(dev, "selector_prepare(): sink buffer size %d is insufficient < %d", @@ -673,7 +642,6 @@ static void set_selector_params(struct processing_module *mod, { struct comp_dev *dev = mod->dev; struct comp_data *cd = module_get_private_data(mod); - struct comp_buffer __sparse_cache *source; const struct sof_selector_ipc4_config *sel_cfg = &cd->sel_ipc4_cfg; const struct ipc4_audio_format *out_fmt = NULL; struct comp_buffer *src_buf; @@ -700,12 +668,10 @@ static void set_selector_params(struct processing_module *mod, list_for_item(sink_list, &dev->bsink_list) { struct comp_buffer *sink_buf = container_of(sink_list, struct comp_buffer, source_list); - struct comp_buffer __sparse_cache *sink = buffer_acquire(sink_buf); - ipc4_update_buffer_format(sink, out_fmt); - audio_stream_set_channels(&sink->stream, params->channels); - audio_stream_set_rate(&sink->stream, params->rate); - buffer_release(sink); + ipc4_update_buffer_format(sink_buf, out_fmt); + audio_stream_set_channels(&sink_buf->stream, params->channels); + audio_stream_set_rate(&sink_buf->stream, params->rate); } /* update the source format @@ -715,12 +681,9 @@ static void set_selector_params(struct processing_module *mod, * and the first one is not ready yet along with sink buffers params */ src_buf = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source = buffer_acquire(src_buf); - if (!source->hw_params_configured) - ipc4_update_buffer_format(source, &mod->priv.cfg.base_cfg.audio_fmt); - - buffer_release(source); + if (!src_buf->hw_params_configured) + ipc4_update_buffer_format(src_buf, &mod->priv.cfg.base_cfg.audio_fmt); } static int selector_verify_params(struct processing_module *mod, @@ -729,7 +692,6 @@ static int selector_verify_params(struct processing_module *mod, struct comp_dev *dev = mod->dev; struct comp_data *cd = module_get_private_data(mod); struct comp_buffer *buffer; - struct comp_buffer __sparse_cache *buffer_c; uint32_t in_channels = cd->config.in_channels_count; uint32_t out_channels = cd->config.out_channels_count; @@ -755,15 +717,11 @@ static int selector_verify_params(struct processing_module *mod, params->channels = in_channels; buffer = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); } - buffer_c = buffer_acquire(buffer); - buffer_set_params(buffer_c, params, BUFFER_UPDATE_FORCE); - buffer_release(buffer_c); + buffer_set_params(buffer, params, BUFFER_UPDATE_FORCE); /* set component period frames */ buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - buffer_c = buffer_acquire(buffer); - component_set_nearest_period_frames(dev, audio_stream_get_rate(&buffer_c->stream)); - buffer_release(buffer_c); + component_set_nearest_period_frames(dev, audio_stream_get_rate(&buffer->stream)); return 0; } @@ -862,14 +820,13 @@ static int selector_process(struct processing_module *mod, * \return Error code. */ static int selector_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_data *cd = module_get_private_data(mod); struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; struct comp_buffer *sinkb, *sourceb; - struct comp_buffer __sparse_cache *sink_c, *source_c; size_t sink_size; int ret; @@ -886,36 +843,30 @@ static int selector_prepare(struct processing_module *mod, sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - - audio_stream_init_alignment_constants(4, 1, &source_c->stream); - audio_stream_init_alignment_constants(4, 1, &sink_c->stream); + audio_stream_init_alignment_constants(4, 1, &sourceb->stream); + audio_stream_init_alignment_constants(4, 1, &sinkb->stream); /* get source data format and period bytes */ - cd->source_format = audio_stream_get_frm_fmt(&source_c->stream); - cd->source_period_bytes = audio_stream_period_bytes(&source_c->stream, dev->frames); + cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); + cd->source_period_bytes = audio_stream_period_bytes(&sourceb->stream, dev->frames); /* get sink data format and period bytes */ - cd->sink_format = audio_stream_get_frm_fmt(&sink_c->stream); - cd->sink_period_bytes = audio_stream_period_bytes(&sink_c->stream, dev->frames); + cd->sink_format = audio_stream_get_frm_fmt(&sinkb->stream); + cd->sink_period_bytes = audio_stream_period_bytes(&sinkb->stream, dev->frames); /* There is an assumption that sink component will report out * proper number of channels [1] for selector to actually * reduce channel count between source and sink */ comp_info(dev, "selector_prepare(): source sink channel = %u %u", - audio_stream_get_channels(&source_c->stream), - audio_stream_get_channels(&sink_c->stream)); + audio_stream_get_channels(&sourceb->stream), + audio_stream_get_channels(&sinkb->stream)); - sink_size = audio_stream_get_size(&sink_c->stream); + sink_size = audio_stream_get_size(&sinkb->stream); md->mpd.in_buff_size = cd->source_period_bytes; md->mpd.out_buff_size = cd->sink_period_bytes; - buffer_release(sink_c); - buffer_release(source_c); - if (sink_size < cd->sink_period_bytes) { comp_err(dev, "selector_prepare(): sink buffer size %d is insufficient < %d", sink_size, cd->sink_period_bytes); @@ -965,7 +916,7 @@ static int selector_reset(struct processing_module *mod) } /** \brief Selector component definition. */ -static struct module_interface selector_interface = { +static const struct module_interface selector_interface = { .init = selector_init, .prepare = selector_prepare, .process_audio_stream = selector_process, diff --git a/src/audio/selector/selector_generic.c b/src/audio/selector/selector_generic.c index ca9e72f656d5..923277ec3f46 100644 --- a/src/audio/selector/selector_generic.c +++ b/src/audio/selector/selector_generic.c @@ -32,8 +32,8 @@ LOG_MODULE_DECLARE(selector, CONFIG_SOF_LOG_LEVEL); * \param[in,out] source Source buffer. * \param[in] frames Number of frames to process. */ -static void sel_s16le_1ch(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, uint32_t frames) +static void sel_s16le_1ch(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream *source, uint32_t frames) { struct comp_data *cd = comp_get_drvdata(dev); int16_t *src = audio_stream_get_rptr(source); @@ -72,8 +72,8 @@ static void sel_s16le_1ch(struct comp_dev *dev, struct audio_stream __sparse_cac * \param[in,out] source Source buffer. * \param[in] frames Number of frames to process. */ -static void sel_s16le_nch(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, uint32_t frames) +static void sel_s16le_nch(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream *source, uint32_t frames) { int8_t *src = audio_stream_get_rptr(source); int8_t *dst = audio_stream_get_wptr(sink); @@ -104,8 +104,8 @@ static void sel_s16le_nch(struct comp_dev *dev, struct audio_stream __sparse_cac * \param[in,out] source Source buffer. * \param[in] frames Number of frames to process. */ -static void sel_s32le_1ch(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, uint32_t frames) +static void sel_s32le_1ch(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream *source, uint32_t frames) { struct comp_data *cd = comp_get_drvdata(dev); int32_t *src = audio_stream_get_rptr(source); @@ -144,8 +144,8 @@ static void sel_s32le_1ch(struct comp_dev *dev, struct audio_stream __sparse_cac * \param[in,out] source Source buffer. * \param[in] frames Number of frames to process. */ -static void sel_s32le_nch(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, uint32_t frames) +static void sel_s32le_nch(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream *source, uint32_t frames) { int8_t *src = audio_stream_get_rptr(source); int8_t *dst = audio_stream_get_wptr(sink); @@ -206,8 +206,8 @@ static void sel_s16le(struct processing_module *mod, struct input_stream_buffer struct output_stream_buffer *bsink, uint32_t frames) { struct comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int16_t *src = audio_stream_get_rptr(source); int16_t *dest = audio_stream_get_wptr(sink); int nmax; @@ -277,8 +277,8 @@ static void sel_s32le(struct processing_module *mod, struct input_stream_buffer struct output_stream_buffer *bsink, uint32_t frames) { struct comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *src = audio_stream_get_rptr(source); int32_t *dest = audio_stream_get_wptr(sink); int nmax; diff --git a/src/audio/sink_api_helper.c b/src/audio/sink_api_helper.c index 4655fdbde347..46ffbfd6b860 100644 --- a/src/audio/sink_api_helper.c +++ b/src/audio/sink_api_helper.c @@ -7,19 +7,19 @@ #include #include -void sink_init(struct sof_sink __sparse_cache *sink, const struct sink_ops *ops, +void sink_init(struct sof_sink *sink, const struct sink_ops *ops, struct sof_audio_stream_params *audio_stream_params) { sink->ops = ops; sink->audio_stream_params = audio_stream_params; } -size_t sink_get_free_size(struct sof_sink __sparse_cache *sink) +size_t sink_get_free_size(struct sof_sink *sink) { return sink->ops->get_free_size(sink); } -int sink_get_buffer(struct sof_sink __sparse_cache *sink, size_t req_size, +int sink_get_buffer(struct sof_sink *sink, size_t req_size, void **data_ptr, void **buffer_start, size_t *buffer_size) { int ret; @@ -35,7 +35,7 @@ int sink_get_buffer(struct sof_sink __sparse_cache *sink, size_t req_size, return ret; } -int sink_commit_buffer(struct sof_sink __sparse_cache *sink, size_t commit_size) +int sink_commit_buffer(struct sof_sink *sink, size_t commit_size) { int ret; @@ -56,47 +56,47 @@ int sink_commit_buffer(struct sof_sink __sparse_cache *sink, size_t commit_size) return ret; } -size_t sink_get_num_of_processed_bytes(struct sof_sink __sparse_cache *sink) +size_t sink_get_num_of_processed_bytes(struct sof_sink *sink) { return sink->num_of_bytes_processed; } -void sink_reset_num_of_processed_bytes(struct sof_sink __sparse_cache *sink) +void sink_reset_num_of_processed_bytes(struct sof_sink *sink) { sink->num_of_bytes_processed = 0; } -enum sof_ipc_frame sink_get_frm_fmt(struct sof_sink __sparse_cache *sink) +enum sof_ipc_frame sink_get_frm_fmt(struct sof_sink *sink) { return sink->audio_stream_params->frame_fmt; } -enum sof_ipc_frame sink_get_valid_fmt(struct sof_sink __sparse_cache *sink) +enum sof_ipc_frame sink_get_valid_fmt(struct sof_sink *sink) { return sink->audio_stream_params->valid_sample_fmt; } -uint32_t sink_get_rate(struct sof_sink __sparse_cache *sink) +uint32_t sink_get_rate(struct sof_sink *sink) { return sink->audio_stream_params->rate; } -uint32_t sink_get_channels(struct sof_sink __sparse_cache *sink) +uint32_t sink_get_channels(struct sof_sink *sink) { return sink->audio_stream_params->channels; } -uint32_t sink_get_buffer_fmt(struct sof_sink __sparse_cache *sink) +uint32_t sink_get_buffer_fmt(struct sof_sink *sink) { return sink->audio_stream_params->buffer_fmt; } -bool sink_get_overrun(struct sof_sink __sparse_cache *sink) +bool sink_get_overrun(struct sof_sink *sink) { return sink->audio_stream_params->overrun_permitted; } -int sink_set_frm_fmt(struct sof_sink __sparse_cache *sink, enum sof_ipc_frame frame_fmt) +int sink_set_frm_fmt(struct sof_sink *sink, enum sof_ipc_frame frame_fmt) { sink->audio_stream_params->frame_fmt = frame_fmt; @@ -106,7 +106,7 @@ int sink_set_frm_fmt(struct sof_sink __sparse_cache *sink, enum sof_ipc_frame fr return 0; } -int sink_set_valid_fmt(struct sof_sink __sparse_cache *sink, +int sink_set_valid_fmt(struct sof_sink *sink, enum sof_ipc_frame valid_sample_fmt) { sink->audio_stream_params->valid_sample_fmt = valid_sample_fmt; @@ -115,7 +115,7 @@ int sink_set_valid_fmt(struct sof_sink __sparse_cache *sink, return 0; } -int sink_set_rate(struct sof_sink __sparse_cache *sink, unsigned int rate) +int sink_set_rate(struct sof_sink *sink, unsigned int rate) { sink->audio_stream_params->rate = rate; if (sink->ops->on_audio_format_set) @@ -123,7 +123,7 @@ int sink_set_rate(struct sof_sink __sparse_cache *sink, unsigned int rate) return 0; } -int sink_set_channels(struct sof_sink __sparse_cache *sink, unsigned int channels) +int sink_set_channels(struct sof_sink *sink, unsigned int channels) { sink->audio_stream_params->channels = channels; if (sink->ops->on_audio_format_set) @@ -131,7 +131,7 @@ int sink_set_channels(struct sof_sink __sparse_cache *sink, unsigned int channel return 0; } -int sink_set_buffer_fmt(struct sof_sink __sparse_cache *sink, uint32_t buffer_fmt) +int sink_set_buffer_fmt(struct sof_sink *sink, uint32_t buffer_fmt) { sink->audio_stream_params->buffer_fmt = buffer_fmt; if (sink->ops->on_audio_format_set) @@ -139,7 +139,7 @@ int sink_set_buffer_fmt(struct sof_sink __sparse_cache *sink, uint32_t buffer_fm return 0; } -int sink_set_overrun(struct sof_sink __sparse_cache *sink, bool overrun_permitted) +int sink_set_overrun(struct sof_sink *sink, bool overrun_permitted) { sink->audio_stream_params->overrun_permitted = overrun_permitted; if (sink->ops->on_audio_format_set) @@ -147,19 +147,19 @@ int sink_set_overrun(struct sof_sink __sparse_cache *sink, bool overrun_permitte return 0; } -size_t sink_get_frame_bytes(struct sof_sink __sparse_cache *sink) +size_t sink_get_frame_bytes(struct sof_sink *sink) { return get_frame_bytes(sink_get_frm_fmt(sink), sink_get_channels(sink)); } -size_t sink_get_free_frames(struct sof_sink __sparse_cache *sink) +size_t sink_get_free_frames(struct sof_sink *sink) { return sink_get_free_size(sink) / sink_get_frame_bytes(sink); } -int sink_set_params(struct sof_sink __sparse_cache *sink, +int sink_set_params(struct sof_sink *sink, struct sof_ipc_stream_params *params, bool force_update) { if (sink->ops->audio_set_ipc_params) @@ -167,7 +167,7 @@ int sink_set_params(struct sof_sink __sparse_cache *sink, return 0; } -int sink_set_alignment_constants(struct sof_sink __sparse_cache *sink, +int sink_set_alignment_constants(struct sof_sink *sink, const uint32_t byte_align, const uint32_t frame_align_req) { @@ -176,12 +176,12 @@ int sink_set_alignment_constants(struct sof_sink __sparse_cache *sink, return 0; } -void sink_set_obs(struct sof_sink __sparse_cache *sink, size_t obs) +void sink_set_min_free_space(struct sof_sink *sink, size_t min_free_space) { - sink->obs = obs; + sink->min_free_space = min_free_space; } -size_t sink_get_obs(struct sof_sink __sparse_cache *sink) +size_t sink_get_min_free_space(struct sof_sink *sink) { - return sink->obs; + return sink->min_free_space; } diff --git a/src/audio/sink_source_utils.c b/src/audio/sink_source_utils.c index 671c1752d544..3b79c8c2d5e1 100644 --- a/src/audio/sink_source_utils.c +++ b/src/audio/sink_source_utils.c @@ -12,12 +12,12 @@ #include #include -int source_to_sink_copy(struct sof_source __sparse_cache *source, - struct sof_sink __sparse_cache *sink, bool free, size_t size) +int source_to_sink_copy(struct sof_source *source, + struct sof_sink *sink, bool free, size_t size) { - uint8_t *src_ptr; - uint8_t *src_begin; - uint8_t *src_end; + uint8_t const *src_ptr; + uint8_t const *src_begin; + uint8_t const *src_end; uint8_t *dst_ptr; uint8_t *dst_begin; uint8_t *dst_end; @@ -32,8 +32,8 @@ int source_to_sink_copy(struct sof_source __sparse_cache *source, return -ENOSPC; ret = source_get_data(source, size, - (void **)&src_ptr, - (void **)&src_begin, + (void const **)&src_ptr, + (void const **)&src_begin, &src_size); if (ret) return ret; diff --git a/src/audio/smart_amp/CMakeLists.txt b/src/audio/smart_amp/CMakeLists.txt index 89048004f16b..387381057804 100644 --- a/src/audio/smart_amp/CMakeLists.txt +++ b/src/audio/smart_amp/CMakeLists.txt @@ -10,4 +10,6 @@ else() sof_add_static_library(dsm ${CMAKE_CURRENT_LIST_DIR}/lib/release/dsm_lib/libdsm.a) endif() target_include_directories(sof PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/dsm_api/inc) +else() +add_local_sources(sof smart_amp_passthru.c) endif() diff --git a/src/audio/smart_amp/Kconfig b/src/audio/smart_amp/Kconfig index 4cbbffbc51d2..02cc6fadc0c5 100644 --- a/src/audio/smart_amp/Kconfig +++ b/src/audio/smart_amp/Kconfig @@ -1,12 +1,30 @@ # SPDX-License-Identifier: BSD-3-Clause -menu "Smart amplifier solutions" - visible if COMP_SMART_AMP +if COMP_SMART_AMP + +choice + prompt "Smart Amplifier solution applied" + default PASSTHRU_AMP + help + The selection for Smart Amplifier component implementation + will depend on the Amplifier solution supplier. It is fair + to treat the supported solutions as mutually exclusive ones. + There should be no more than one solution selected per build + config. When Smart Amplifier is present but no solution is + supported, the passthrough mode will be applied as default. + + config PASSTHRU_AMP + bool "Stream Passthrough" + help + The default option as the passthrough mode while no other + solution is applied. While selected, the feed-forward input + frames will be passed to output after channel remapping. No + gain or latency will be produced. In the meanwhile, the + feedback input frames will be consumed but dropped directly. config MAXIM_DSM bool "Maxim DSM solution" select MAXIM_DSM_STUB if COMP_STUBS - default n help Select to apply Maxim DSM(Dynamic Speaker Management) solution for Smart Amplifier. As the third-party supply, the @@ -14,6 +32,8 @@ menu "Smart amplifier solutions" building the FW binary with this option enabled. The library itself should be statically linked with the SoF FW binary image. +endchoice + config MAXIM_DSM_STUB bool "Maxim DSM solution" depends on MAXIM_DSM @@ -22,5 +42,4 @@ menu "Smart amplifier solutions" Select to build the Maxim DSM adapter with a stub library. This should only be used for CI and testing. -endmenu - +endif diff --git a/src/audio/smart_amp/smart_amp.c b/src/audio/smart_amp/smart_amp.c index d0108aa346c7..ecf0e3a5d7ce 100644 --- a/src/audio/smart_amp/smart_amp.c +++ b/src/audio/smart_amp/smart_amp.c @@ -3,6 +3,12 @@ // Copyright(c) 2020 Maxim Integrated All rights reserved. // // Author: Ryan Lee +// +// Copyright(c) 2023 Google LLC. +// +// Author: Pin-chih Lin + +#include #include #include @@ -14,201 +20,151 @@ static const struct comp_driver comp_smart_amp; +#if CONFIG_MAXIM_DSM /* 0cd84e80-ebd3-11ea-adc1-0242ac120002 */ -DECLARE_SOF_RT_UUID("Maxim DSM", maxim_dsm_comp_uuid, 0x0cd84e80, 0xebd3, +DECLARE_SOF_RT_UUID("Maxim DSM", smart_amp_comp_uuid, 0x0cd84e80, 0xebd3, 0x11ea, 0xad, 0xc1, 0x02, 0x42, 0xac, 0x12, 0x00, 0x02); -DECLARE_TR_CTX(maxim_dsm_comp_tr, SOF_UUID(maxim_dsm_comp_uuid), +#else /* Passthrough */ +/* 64a794f0-55d3-4bca-9d5b-7b588badd037 */ +DECLARE_SOF_RT_UUID("Passthru Amp", smart_amp_comp_uuid, 0x64a794f0, 0x55d3, + 0x4bca, 0x9d, 0x5b, 0x7b, 0x58, 0x8b, 0xad, 0xd0, 0x37); + +#endif +DECLARE_TR_CTX(smart_amp_comp_tr, SOF_UUID(smart_amp_comp_uuid), LOG_LEVEL_INFO); /* Amp configuration & model calibration data for tuning/debug */ #define SOF_SMART_AMP_CONFIG 0 #define SOF_SMART_AMP_MODEL 1 -typedef int(*smart_amp_proc)(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, uint32_t frames, - int8_t *chan_map, bool is_feedback); - struct smart_amp_data { struct sof_smart_amp_config config; struct comp_data_blob_handler *model_handler; struct comp_buffer *source_buf; /**< stream source buffer */ struct comp_buffer *feedback_buf; /**< feedback source buffer */ struct comp_buffer *sink_buf; /**< sink buffer */ - smart_amp_proc process; - uint32_t in_channels; - uint32_t out_channels; - /* module handle for speaker protection algorithm */ - struct smart_amp_mod_struct_t *mod_handle; + struct ipc_config_process ipc_config; + + smart_amp_src_func ff_get_frame; /**< function to get stream source */ + smart_amp_src_func fb_get_frame; /**< function to get feedback source */ + smart_amp_sink_func ff_set_frame; /**< function to set sink */ + struct smart_amp_mod_stream ff_mod; /**< feed-forward buffer for mod */ + struct smart_amp_mod_stream fb_mod; /**< feedback buffer for mod */ + struct smart_amp_mod_stream out_mod; /**< output buffer for mod */ + + struct smart_amp_buf mod_mems[MOD_MEMBLK_MAX]; /**< memory blocks for mod */ + + struct smart_amp_mod_data_base *mod_data; /**< inner model data */ }; -static inline void smart_amp_free_memory(struct smart_amp_data *sad, - struct comp_dev *dev) +/* smart_amp_free_mod_memories will be called promptly once getting error on + * internal functions. That is, it may be called multiple times by the hierarchical + * model when an error occurs in the lower function and propagates level-wise to + * the function on top. Always set the pointer to NULL after freed to avoid the + * double-freeing error. + */ +static inline void smart_amp_free_mod_memories(struct smart_amp_data *sad) { - struct smart_amp_mod_struct_t *hspk = sad->mod_handle; - - /* buffer : sof -> spk protection feed forward process */ - rfree(hspk->buf.frame_in); - /* buffer : sof <- spk protection feed forward process */ - rfree(hspk->buf.frame_out); - /* buffer : sof -> spk protection feedback process */ - rfree(hspk->buf.frame_iv); - /* buffer : feed forward process input */ - rfree(hspk->buf.input); - /* buffer : feed forward process output */ - rfree(hspk->buf.output); - /* buffer : feedback voltage */ - rfree(hspk->buf.voltage); - /* buffer : feedback current */ - rfree(hspk->buf.current); - /* buffer : feed forward variable length -> fixed length */ - rfree(hspk->buf.ff.buf); - /* buffer : feed forward variable length <- fixed length */ - rfree(hspk->buf.ff_out.buf); - /* buffer : feedback variable length -> fixed length */ - rfree(hspk->buf.fb.buf); - /* Module handle release */ - rfree(hspk); + /* sof -> mod feed-forward data re-mapping and format conversion */ + rfree(sad->ff_mod.buf.data); + sad->ff_mod.buf.data = NULL; + /* sof -> mod feedback data re-mapping and format conversion */ + rfree(sad->fb_mod.buf.data); + sad->fb_mod.buf.data = NULL; + /* mod -> sof processed data format conversion */ + rfree(sad->out_mod.buf.data); + sad->out_mod.buf.data = NULL; + + /* mem block for mod private data usage */ + rfree(sad->mod_mems[MOD_MEMBLK_PRIVATE].data); + sad->mod_mems[MOD_MEMBLK_PRIVATE].data = NULL; + /* mem block for mod audio frame data usage */ + rfree(sad->mod_mems[MOD_MEMBLK_FRAME].data); + sad->mod_mems[MOD_MEMBLK_FRAME].data = NULL; + /* mem block for mod parameter blob usage */ + rfree(sad->mod_mems[MOD_MEMBLK_PARAM].data); + sad->mod_mems[MOD_MEMBLK_PARAM].data = NULL; + + /* inner model data struct */ + rfree(sad->mod_data); + sad->mod_data = NULL; } -static inline int smart_amp_alloc_memory(struct smart_amp_data *sad, - struct comp_dev *dev) +static inline int smart_amp_buf_alloc(struct smart_amp_buf *buf, size_t size) { - struct smart_amp_mod_struct_t *hspk; - int mem_sz; - int size; - - /* memory allocation for module handle */ - mem_sz = sizeof(struct smart_amp_mod_struct_t); - sad->mod_handle = rballoc(0, SOF_MEM_CAPS_RAM, mem_sz); - if (!sad->mod_handle) - goto err; - memset(sad->mod_handle, 0, mem_sz); - - hspk = sad->mod_handle; + buf->data = rballoc(0, SOF_MEM_CAPS_RAM, size); + if (!buf->data) + return -ENOMEM; + buf->size = size; + return 0; +} - /* buffer : sof -> spk protection feed forward process */ - size = SMART_AMP_FF_BUF_DB_SZ * sizeof(int32_t); - hspk->buf.frame_in = rballoc(0, SOF_MEM_CAPS_RAM, size); - if (!hspk->buf.frame_in) - goto err; - mem_sz += size; +static ssize_t smart_amp_alloc_mod_memblk(struct smart_amp_data *sad, + enum smart_amp_mod_memblk blk) +{ + struct smart_amp_mod_data_base *mod = sad->mod_data; + int ret; + size_t size; - /* buffer : sof <- spk protection feed forward process */ - size = SMART_AMP_FF_BUF_DB_SZ * sizeof(int32_t); - hspk->buf.frame_out = rballoc(0, SOF_MEM_CAPS_RAM, size); - if (!hspk->buf.frame_out) - goto err; - mem_sz += size; + /* query the required size from inner model. */ + ret = mod->mod_ops->query_memblk_size(mod, blk); + if (ret <= 0) + goto error; - /* buffer : sof -> spk protection feedback process */ - size = SMART_AMP_FB_BUF_DB_SZ * sizeof(int32_t); - hspk->buf.frame_iv = rballoc(0, SOF_MEM_CAPS_RAM, size); - if (!hspk->buf.frame_iv) - goto err; - mem_sz += size; - - /* buffer : feed forward process input */ - size = DSM_FF_BUF_SZ * sizeof(int32_t); - hspk->buf.input = rballoc(0, SOF_MEM_CAPS_RAM, size); - if (!hspk->buf.input) - goto err; - mem_sz += size; - - /* buffer : feed forward process output */ - size = DSM_FF_BUF_SZ * sizeof(int32_t); - hspk->buf.output = rballoc(0, SOF_MEM_CAPS_RAM, size); - if (!hspk->buf.output) - goto err; - mem_sz += size; - - /* buffer : feedback voltage */ - size = DSM_FF_BUF_SZ * sizeof(int32_t); - hspk->buf.voltage = rballoc(0, SOF_MEM_CAPS_RAM, size); - if (!hspk->buf.voltage) - goto err; - mem_sz += size; - - /* buffer : feedback current */ - size = DSM_FF_BUF_SZ * sizeof(int32_t); - hspk->buf.current = rballoc(0, SOF_MEM_CAPS_RAM, size); - if (!hspk->buf.current) - goto err; - mem_sz += size; - - /* buffer : feed forward variable length -> fixed length */ - size = DSM_FF_BUF_DB_SZ * sizeof(int32_t); - hspk->buf.ff.buf = rballoc(0, SOF_MEM_CAPS_RAM, size); - if (!hspk->buf.ff.buf) - goto err; - mem_sz += size; - - /* buffer : feed forward variable length <- fixed length */ - size = DSM_FF_BUF_DB_SZ * sizeof(int32_t); - hspk->buf.ff_out.buf = rballoc(0, SOF_MEM_CAPS_RAM, size); - if (!hspk->buf.ff_out.buf) - goto err; - mem_sz += size; - - /* buffer : feedback variable length -> fixed length */ - size = DSM_FB_BUF_DB_SZ * sizeof(int32_t); - hspk->buf.fb.buf = rballoc(0, SOF_MEM_CAPS_RAM, size); - if (!hspk->buf.fb.buf) - goto err; - mem_sz += size; - - /* memory allocation of DSM handle */ - size = smart_amp_get_memory_size(hspk, dev); - hspk->dsmhandle = rballoc(0, SOF_MEM_CAPS_RAM, size); - if (!hspk->dsmhandle) - goto err; - memset(hspk->dsmhandle, 0, size); - mem_sz += size; - - comp_dbg(dev, "[DSM] module:%p (%d bytes used)", - hspk, mem_sz); + /* allocate the memory block when returned size > 0. */ + size = ret; + ret = smart_amp_buf_alloc(&sad->mod_mems[blk], size); + if (ret < 0) + goto error; - return 0; -err: - smart_amp_free_memory(sad, dev); - return -ENOMEM; -} + /* provide the memory block information to inner model. */ + ret = mod->mod_ops->set_memblk(mod, blk, &sad->mod_mems[blk]); + if (ret < 0) + goto error; -static void smart_amp_free_caldata(struct comp_dev *dev, - struct smart_amp_caldata *caldata) -{ - if (!caldata->data) - return; + return size; - rfree(caldata->data); - caldata->data = NULL; - caldata->data_size = 0; - caldata->data_pos = 0; +error: + smart_amp_free_mod_memories(sad); + return ret; } -static inline int smart_amp_alloc_caldata(struct comp_dev *dev, - struct smart_amp_caldata *caldata, - uint32_t size) +static int smart_amp_alloc_data_buffers(struct comp_dev *dev, + struct smart_amp_data *sad) { - smart_amp_free_caldata(dev, caldata); - - if (!size) - return 0; + size_t total_size; + int ret; + size_t size; - caldata->data = rballoc(0, SOF_MEM_CAPS_RAM, size); + /* sof -> mod feed-forward data re-mapping and format conversion */ + size = SMART_AMP_FF_BUF_DB_SZ * sizeof(int32_t); + ret = smart_amp_buf_alloc(&sad->ff_mod.buf, size); + if (ret < 0) + goto error; + total_size = size; - if (!caldata->data) { - comp_err(dev, "smart_amp_alloc_caldata(): model->data rballoc failed"); - return -ENOMEM; - } + /* sof -> mod feedback data re-mapping and format conversion */ + size = SMART_AMP_FB_BUF_DB_SZ * sizeof(int32_t); + ret = smart_amp_buf_alloc(&sad->fb_mod.buf, size); + if (ret < 0) + goto error; + total_size += size; - bzero(caldata->data, size); - caldata->data_size = size; - caldata->data_pos = 0; + /* mod -> sof processed data format conversion */ + size = SMART_AMP_FF_BUF_DB_SZ * sizeof(int32_t); + ret = smart_amp_buf_alloc(&sad->out_mod.buf, size); + if (ret < 0) + goto error; + total_size += size; + comp_dbg(dev, "smart_amp_alloc(): used data buffer %zu bytes", total_size); return 0; + +error: + smart_amp_free_mod_memories(sad); + return ret; } static struct comp_dev *smart_amp_new(const struct comp_driver *drv, @@ -220,7 +176,6 @@ static struct comp_dev *smart_amp_new(const struct comp_driver *drv, struct smart_amp_data *sad; struct sof_smart_amp_config *cfg; size_t bs; - int sz_caldata; int ret; dev = comp_alloc(drv, sizeof(*dev)); @@ -248,39 +203,57 @@ static struct comp_dev *smart_amp_new(const struct comp_driver *drv, memcpy_s(&sad->config, sizeof(struct sof_smart_amp_config), cfg, bs); - if (smart_amp_alloc_memory(sad, dev) != 0) + /* allocate inner model data struct */ + sad->mod_data = mod_data_create(dev); + if (!sad->mod_data) { + comp_err(dev, "smart_amp_new(): failed to allocate nner model data"); goto error; + } - /* Bitwidth information is not available. Use 16bit as default. - * Re-initialize in the prepare function if ncessary - */ - sad->mod_handle->bitwidth = 16; - if (smart_amp_init(sad->mod_handle, dev)) + /* allocate stream buffers for mod */ + ret = smart_amp_alloc_data_buffers(dev, sad); + if (ret) { + comp_err(dev, "smart_amp_new(): failed to allocate data buffers, ret:%d", ret); goto error; + } - /* Get the max. number of parameter to allocate memory for model data */ - sad->mod_handle->param.max_param = - smart_amp_get_num_param(sad->mod_handle, dev); - sz_caldata = sad->mod_handle->param.max_param * DSM_SINGLE_PARAM_SZ; + /* (before init) allocate mem block for mod private data usage */ + ret = smart_amp_alloc_mod_memblk(sad, MOD_MEMBLK_PRIVATE); + if (ret < 0) { + comp_err(dev, "smart_amp_new(): failed to allocate mod private, ret:%d", ret); + goto error; + } + comp_dbg(dev, "smart_amp_new(): used mod private buffer %d bytes", ret); - if (sz_caldata > 0) { - ret = smart_amp_alloc_caldata(dev, &sad->mod_handle->param.caldata, - sz_caldata * sizeof(int32_t)); - if (ret < 0) { - comp_err(dev, "smart_amp_new(): caldata initial failed"); - goto error; - } + /* init model */ + ret = sad->mod_data->mod_ops->init(sad->mod_data); + if (ret) { + comp_err(dev, "smart_amp_new(): failed to init inner model, ret:%d", ret); + goto error; } - /* update full parameter values */ - if (smart_amp_get_all_param(sad->mod_handle, dev) < 0) + /* (after init) allocate mem block for mod audio frame data usage */ + ret = smart_amp_alloc_mod_memblk(sad, MOD_MEMBLK_FRAME); + if (ret < 0) { + comp_err(dev, "smart_amp_new(): failed to allocate mod buffer, ret:%d", ret); goto error; + } + comp_dbg(dev, "smart_amp_new(): used mod data buffer %d bytes", ret); + + /* (after init) allocate mem block for mod parameter blob usage */ + ret = smart_amp_alloc_mod_memblk(sad, MOD_MEMBLK_PARAM); + if (ret < 0) { + comp_err(dev, "smart_amp_new(): failed to allocate mod config, ret:%d", ret); + goto error; + } + comp_dbg(dev, "smart_amp_new(): used mod config buffer %d bytes", ret); dev->state = COMP_STATE_READY; return dev; error: + smart_amp_free_mod_memories(sad); rfree(sad); rfree(dev); return NULL; @@ -295,14 +268,14 @@ static int smart_amp_set_config(struct comp_dev *dev, /* Copy new config, find size from header */ cfg = (struct sof_smart_amp_config *) - ASSUME_ALIGNED(&cdata->data->data, sizeof(uint32_t)); + ASSUME_ALIGNED(&cdata->data->data, sizeof(uint32_t)); bs = cfg->size; - comp_dbg(dev, "smart_amp_set_config(), actual blob size = %u, expected blob size = %u", + comp_dbg(dev, "smart_amp_set_config(), actual blob size = %zu, expected blob size = %zu", bs, sizeof(struct sof_smart_amp_config)); if (bs != sizeof(struct sof_smart_amp_config)) { - comp_err(dev, "smart_amp_set_config(): invalid blob size, actual blob size = %u, expected blob size = %u", + comp_err(dev, "smart_amp_set_config(): invalid blob size, actual blob size = %zu, expected blob size = %zu", bs, sizeof(struct sof_smart_amp_config)); return -EINVAL; } @@ -323,7 +296,7 @@ static int smart_amp_get_config(struct comp_dev *dev, /* Copy back to user space */ bs = sad->config.size; - comp_dbg(dev, "smart_amp_get_config(), actual blob size = %u, expected blob size = %u", + comp_dbg(dev, "smart_amp_get_config(), actual blob size = %zu, expected blob size = %zu", bs, sizeof(struct sof_smart_amp_config)); if (bs == 0 || bs > size) @@ -343,18 +316,20 @@ static int smart_amp_ctrl_get_bin_data(struct comp_dev *dev, int size) { struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_mod_data_base *mod; int ret = 0; assert(sad); + mod = sad->mod_data; switch (cdata->data->type) { case SOF_SMART_AMP_CONFIG: ret = smart_amp_get_config(dev, cdata, size); break; case SOF_SMART_AMP_MODEL: - ret = maxim_dsm_get_param(sad->mod_handle, dev, cdata, size); + ret = mod->mod_ops->get_config(mod, cdata, size); if (ret < 0) { - comp_err(dev, "smart_amp_ctrl_get_bin_data(): parameter read error!"); + comp_err(dev, "smart_amp_ctrl_get_bin_data(): failed to read inner model!"); return ret; } break; @@ -389,9 +364,11 @@ static int smart_amp_ctrl_set_bin_data(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata) { struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_mod_data_base *mod; int ret = 0; assert(sad); + mod = sad->mod_data; if (dev->state < COMP_STATE_READY) { comp_err(dev, "smart_amp_ctrl_set_bin_data(): driver in init!"); @@ -403,9 +380,9 @@ static int smart_amp_ctrl_set_bin_data(struct comp_dev *dev, ret = smart_amp_set_config(dev, cdata); break; case SOF_SMART_AMP_MODEL: - ret = maxim_dsm_set_param(sad->mod_handle, dev, cdata); + ret = mod->mod_ops->set_config(mod, cdata); if (ret < 0) { - comp_err(dev, "smart_amp_ctrl_set_bin_data(): parameter write error!"); + comp_err(dev, "smart_amp_ctrl_set_bin_data(): failed to write inner model!"); return ret; } break; @@ -466,11 +443,12 @@ static void smart_amp_free(struct comp_dev *dev) comp_dbg(dev, "smart_amp_free()"); - smart_amp_free_caldata(dev, &sad->mod_handle->param.caldata); - smart_amp_free_memory(sad, dev); + smart_amp_free_mod_memories(sad); rfree(sad); + sad = NULL; rfree(dev); + dev = NULL; } static int smart_amp_verify_params(struct comp_dev *dev, @@ -518,9 +496,7 @@ static int smart_amp_trigger(struct comp_dev *dev, int cmd) case COMP_TRIGGER_START: case COMP_TRIGGER_RELEASE: if (sad->feedback_buf) { - struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); - buffer_zero(buf); - buffer_release(buf); + buffer_zero(sad->feedback_buf); } break; case COMP_TRIGGER_PAUSE: @@ -533,52 +509,79 @@ static int smart_amp_trigger(struct comp_dev *dev, int cmd) return ret; } -static int smart_amp_process(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, - uint32_t frames, int8_t *chan_map, - bool is_feedback) +static int smart_amp_ff_process(struct comp_dev *dev, + const struct audio_stream *source, + const struct audio_stream *sink, + uint32_t frames, const int8_t *chan_map) { struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_mod_data_base *mod = sad->mod_data; int ret; - if (!is_feedback) - ret = smart_amp_ff_copy(dev, frames, - source, sink, - chan_map, sad->mod_handle, - sad->in_channels, sad->out_channels); - else - ret = smart_amp_fb_copy(dev, frames, - source, sink, - chan_map, sad->mod_handle, - audio_stream_get_channels(source)); - return ret; + sad->ff_mod.consumed = 0; + sad->out_mod.produced = 0; + + if (frames == 0) { + comp_warn(dev, "smart_amp_copy(): feed forward frame size zero warning."); + return 0; + } + + if (frames > SMART_AMP_FF_BUF_DB_SZ) { + comp_err(dev, "smart_amp_copy(): feed forward frame size overflow: %u", frames); + sad->ff_mod.consumed = frames; + return -EINVAL; + } + + sad->ff_get_frame(&sad->ff_mod, frames, source, chan_map); + + ret = mod->mod_ops->ff_proc(mod, frames, &sad->ff_mod, &sad->out_mod); + if (ret) { + comp_err(dev, "smart_amp_copy(): feed forward inner model process error"); + return ret; + } + + sad->ff_set_frame(&sad->out_mod, sad->out_mod.produced, sink); + + return 0; } -static smart_amp_proc get_smart_amp_process(struct comp_dev *dev) +static int smart_amp_fb_process(struct comp_dev *dev, + const struct audio_stream *source, + uint32_t frames, const int8_t *chan_map) { struct smart_amp_data *sad = comp_get_drvdata(dev); - struct comp_buffer __sparse_cache *source_buf = buffer_acquire(sad->source_buf); - enum sof_ipc_frame fmt = audio_stream_get_frm_fmt(&source_buf->stream); + struct smart_amp_mod_data_base *mod = sad->mod_data; + int ret; - buffer_release(source_buf); + sad->fb_mod.consumed = 0; - switch (fmt) { - case SOF_IPC_FRAME_S16_LE: - case SOF_IPC_FRAME_S24_4LE: - case SOF_IPC_FRAME_S32_LE: - return smart_amp_process; - default: - comp_err(dev, "smart_amp_process() error: not supported frame format"); - return NULL; + if (frames == 0) { + comp_warn(dev, "smart_amp_copy(): feedback frame size zero warning."); + return 0; } + + if (frames > SMART_AMP_FB_BUF_DB_SZ) { + comp_err(dev, "smart_amp_copy(): feedback frame size overflow: %u", frames); + sad->fb_mod.consumed = frames; + return -EINVAL; + } + + sad->fb_get_frame(&sad->fb_mod, frames, source, chan_map); + + ret = mod->mod_ops->fb_proc(mod, frames, &sad->fb_mod); + if (ret) { + comp_err(dev, "smart_amp_copy(): feedback inner model process error"); + return ret; + } + + return 0; } static int smart_amp_copy(struct comp_dev *dev) { struct smart_amp_data *sad = comp_get_drvdata(dev); - struct comp_buffer __sparse_cache *source_buf = buffer_acquire(sad->source_buf); - struct comp_buffer __sparse_cache *sink_buf = buffer_acquire(sad->sink_buf); + struct comp_buffer *source_buf = sad->source_buf; + struct comp_buffer *sink_buf = sad->sink_buf; uint32_t avail_passthrough_frames; uint32_t avail_feedback_frames; uint32_t avail_frames; @@ -595,7 +598,7 @@ static int smart_amp_copy(struct comp_dev *dev) avail_frames = avail_passthrough_frames; if (sad->feedback_buf) { - struct comp_buffer __sparse_cache *feedback_buf = buffer_acquire(sad->feedback_buf); + struct comp_buffer *feedback_buf = sad->feedback_buf; if (comp_get_state(dev, feedback_buf->source) == dev->state) { /* feedback */ @@ -608,63 +611,124 @@ static int smart_amp_copy(struct comp_dev *dev) feedback_bytes = avail_feedback_frames * audio_stream_frame_bytes(&feedback_buf->stream); - comp_dbg(dev, "smart_amp_copy(): processing %d feedback frames (avail_passthrough_frames: %d)", + comp_dbg(dev, "smart_amp_copy(): processing %u feedback frames (avail_passthrough_frames: %u)", avail_feedback_frames, avail_passthrough_frames); /* perform buffer writeback after source_buf process */ buffer_stream_invalidate(feedback_buf, feedback_bytes); - sad->process(dev, &feedback_buf->stream, - &sink_buf->stream, avail_feedback_frames, - sad->config.feedback_ch_map, true); + smart_amp_fb_process(dev, &feedback_buf->stream, + avail_feedback_frames, + sad->config.feedback_ch_map); + + comp_dbg(dev, "smart_amp_copy(): consumed %u feedback frames", + sad->fb_mod.consumed); + if (sad->fb_mod.consumed < avail_feedback_frames) { + feedback_bytes = sad->fb_mod.consumed * + audio_stream_frame_bytes(&feedback_buf->stream); + } comp_update_buffer_consume(feedback_buf, feedback_bytes); } - - buffer_release(feedback_buf); } - /* bytes calculation */ + /* process data */ source_bytes = avail_frames * audio_stream_frame_bytes(&source_buf->stream); - sink_bytes = avail_frames * audio_stream_frame_bytes(&sink_buf->stream); - /* process data */ buffer_stream_invalidate(source_buf, source_bytes); - sad->process(dev, &source_buf->stream, &sink_buf->stream, - avail_frames, sad->config.source_ch_map, false); + smart_amp_ff_process(dev, &source_buf->stream, &sink_buf->stream, + avail_frames, sad->config.source_ch_map); + + comp_dbg(dev, "smart_amp_copy(): processing %u feed forward frames (consumed: %u, produced: %u)", + avail_frames, sad->ff_mod.consumed, sad->out_mod.produced); + if (sad->ff_mod.consumed < avail_frames) + source_bytes = sad->ff_mod.consumed * audio_stream_frame_bytes(&source_buf->stream); + + sink_bytes = sad->out_mod.produced * audio_stream_frame_bytes(&sink_buf->stream); buffer_stream_writeback(sink_buf, sink_bytes); /* source/sink buffer pointers update */ comp_update_buffer_consume(source_buf, source_bytes); comp_update_buffer_produce(sink_buf, sink_bytes); - buffer_release(sink_buf); - buffer_release(source_buf); - return 0; } static int smart_amp_reset(struct comp_dev *dev) { struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_mod_data_base *mod = sad->mod_data; + int ret; comp_dbg(dev, "smart_amp_reset()"); - sad->process = NULL; - sad->in_channels = 0; - sad->out_channels = 0; + sad->ff_get_frame = NULL; + sad->fb_get_frame = NULL; + sad->ff_set_frame = NULL; + + /* reset inner model */ + ret = mod->mod_ops->reset(mod); + if (ret) + return ret; comp_set_state(dev, COMP_TRIGGER_RESET); return 0; } +/* supported formats: {SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE} + * which are enumerated as 0, 1, and 2. Simply check if supported while fmt <= 2. + */ +static inline bool is_supported_fmt(uint16_t fmt) +{ + return fmt <= SOF_IPC_FRAME_S32_LE; +} + +static int smart_amp_resolve_mod_fmt(struct comp_dev *dev, uint32_t least_req_depth) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + struct smart_amp_mod_data_base *mod = sad->mod_data; + const uint16_t *mod_fmts; + int num_mod_fmts; + int ret; + int i; + + /* get supported formats from mod */ + ret = mod->mod_ops->get_supported_fmts(mod, &mod_fmts, &num_mod_fmts); + if (ret) { + comp_err(dev, "smart_amp_resolve_mod_fmt(): failed to get supported formats"); + return ret; + } + + for (i = 0; i < num_mod_fmts; i++) { + if (get_sample_bitdepth(mod_fmts[i]) >= least_req_depth && + is_supported_fmt(mod_fmts[i])) { + /* set frame format to inner model */ + comp_dbg(dev, "smart_amp_resolve_mod_fmt(): set mod format to %u", + mod_fmts[i]); + ret = mod->mod_ops->set_fmt(mod, mod_fmts[i]); + if (ret) { + comp_err(dev, + "smart_amp_resolve_mod_fmt(): failed setting format %u", + mod_fmts[i]); + return ret; + } + /* return the resolved format for later settings. */ + return mod_fmts[i]; + } + } + + comp_err(dev, "smart_amp_resolve_mod_fmt(): failed to resolve the frame format for mod"); + return -EINVAL; +} + static int smart_amp_prepare(struct comp_dev *dev) { struct smart_amp_data *sad = comp_get_drvdata(dev); - struct comp_buffer __sparse_cache *source_c, *buf_c; struct list_item *blist; + uint16_t ff_src_fmt, fb_src_fmt, resolved_mod_fmt; + uint32_t least_req_depth; + uint32_t rate; int ret; - int bitwidth; comp_dbg(dev, "smart_amp_prepare()"); @@ -676,91 +740,76 @@ static int smart_amp_prepare(struct comp_dev *dev) list_for_item(blist, &dev->bsource_list) { struct comp_buffer *source_buffer = container_of(blist, struct comp_buffer, sink_list); - source_c = buffer_acquire(source_buffer); - if (source_c->source->ipc_config.type == SOF_COMP_DEMUX) { + if (source_buffer->source->ipc_config.type == SOF_COMP_DEMUX) { sad->feedback_buf = source_buffer; } else { sad->source_buf = source_buffer; - sad->in_channels = audio_stream_get_channels(&source_c->stream); + sad->in_channels = audio_stream_get_channels(&source_buffer->stream); } - - buffer_release(source_c); } + /* sink buffer */ sad->sink_buf = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - buf_c = buffer_acquire(sad->sink_buf); - sad->out_channels = audio_stream_get_channels(&buf_c->stream); - buffer_release(buf_c); - - source_c = buffer_acquire(sad->source_buf); + /* get frame format and channels param of stream and feedback source */ + ff_src_fmt = audio_stream_get_frm_fmt(&sad->source_buf->stream); + sad->ff_mod.channels = MIN(SMART_AMP_FF_MAX_CH_NUM, + audio_stream_get_channels(&sad->source_buf->stream)); + sad->out_mod.channels = sad->ff_mod.channels; + /* the least bitdepth required for inner model, which should not be lower than the bitdepth + * for input samples of feed-forward, and feedback if exists. + */ + least_req_depth = get_sample_bitdepth(ff_src_fmt); if (sad->feedback_buf) { - buf_c = buffer_acquire(sad->feedback_buf); - - audio_stream_set_channels(&buf_c->stream, sad->config.feedback_channels); - audio_stream_set_rate(&buf_c->stream, audio_stream_get_rate(&source_c->stream)); - buffer_release(buf_c); - - ret = smart_amp_check_audio_fmt(audio_stream_get_rate(&source_c->stream), - audio_stream_get_channels(&source_c->stream)); - if (ret) { - comp_err(dev, "[DSM] Format not supported, sample rate: %d, ch: %d", - audio_stream_get_rate(&source_c->stream), - audio_stream_get_channels(&source_c->stream)); - goto error; - } + /* forward set channels and rate param to feedback source */ + audio_stream_set_channels(&sad->feedback_buf->stream, + sad->config.feedback_channels); + audio_stream_set_rate(&sad->feedback_buf->stream, + audio_stream_get_rate(&sad->source_buf->stream)); + fb_src_fmt = audio_stream_get_frm_fmt(&sad->feedback_buf->stream); + sad->fb_mod.channels = MIN(SMART_AMP_FB_MAX_CH_NUM, + audio_stream_get_channels(&sad->feedback_buf->stream)); + + least_req_depth = MAX(least_req_depth, get_sample_bitdepth(fb_src_fmt)); } - switch (audio_stream_get_frm_fmt(&source_c->stream)) { - case SOF_IPC_FRAME_S16_LE: - bitwidth = 16; - break; - case SOF_IPC_FRAME_S24_4LE: - bitwidth = 24; - break; - case SOF_IPC_FRAME_S32_LE: - bitwidth = 32; - break; - default: - comp_err(dev, "[DSM] smart_amp_process() error: not supported frame format %d", - audio_stream_get_frm_fmt(&source_c->stream)); - goto error; - } + /* resolve the frame format for inner model. The return value will be the applied format + * or the negative error code. + */ + ret = smart_amp_resolve_mod_fmt(dev, least_req_depth); + if (ret < 0) + return ret; - sad->mod_handle->bitwidth = bitwidth; - comp_info(dev, "[DSM] Re-initialized for %d bit processing", bitwidth); + resolved_mod_fmt = ret; - ret = smart_amp_init(sad->mod_handle, dev); - if (ret) { - comp_err(dev, "[DSM] Re-initialization error."); - goto error; - } - ret = maxim_dsm_restore_param(sad->mod_handle, dev); - if (ret) { - comp_err(dev, "[DSM] Restoration error."); - goto error; - } + /* set format to mod buffers and get the corresponding src/sink function of channel + * remapping and format conversion. + */ + sad->ff_mod.frame_fmt = resolved_mod_fmt; + sad->out_mod.frame_fmt = resolved_mod_fmt; + sad->ff_get_frame = smart_amp_get_src_func(ff_src_fmt, sad->ff_mod.frame_fmt); + sad->ff_set_frame = smart_amp_get_sink_func(ff_src_fmt, sad->out_mod.frame_fmt); + comp_dbg(dev, "smart_amp_prepare(): ff mod buffer channels:%u fmt_conv:%u -> %u", + sad->ff_mod.channels, ff_src_fmt, sad->ff_mod.frame_fmt); + comp_dbg(dev, "smart_amp_prepare(): output mod buffer channels:%u fmt_conv:%u -> %u", + sad->out_mod.channels, sad->out_mod.frame_fmt, ff_src_fmt); - sad->process = get_smart_amp_process(dev); - if (!sad->process) { - comp_err(dev, "smart_amp_prepare(): get_smart_amp_process failed"); - ret = -EINVAL; + if (sad->feedback_buf) { + sad->fb_mod.frame_fmt = resolved_mod_fmt; + sad->fb_get_frame = smart_amp_get_src_func(fb_src_fmt, sad->fb_mod.frame_fmt); + comp_dbg(dev, "smart_amp_prepare(): fb mod buffer channels:%u fmt_conv:%u -> %u", + sad->fb_mod.channels, fb_src_fmt, sad->fb_mod.frame_fmt); } - -error: - buffer_release(source_c); - - smart_amp_flush(sad->mod_handle, dev); - return ret; + return 0; } static const struct comp_driver comp_smart_amp = { .type = SOF_COMP_SMART_AMP, - .uid = SOF_RT_UUID(maxim_dsm_comp_uuid), - .tctx = &maxim_dsm_comp_tr, + .uid = SOF_RT_UUID(smart_amp_comp_uuid), + .tctx = &smart_amp_comp_tr, .ops = { .create = smart_amp_new, .free = smart_amp_free, diff --git a/src/audio/smart_amp/smart_amp_generic.c b/src/audio/smart_amp/smart_amp_generic.c index 3ad4c1ce28de..5f6a1698d16b 100644 --- a/src/audio/smart_amp/smart_amp_generic.c +++ b/src/audio/smart_amp/smart_amp_generic.c @@ -3,200 +3,357 @@ // Copyright(c) 2020 Maxim Integrated All rights reserved. // // Author: Ryan Lee +// +// Copyright(c) 2023 Google LLC. +// +// Author: Pin-chih Lin #include #include #include #include -#ifdef CONFIG_GENERIC - -static int32_t smart_amp_ff_generic(int32_t x) +static void remap_s32_to_s32(struct smart_amp_mod_stream *src_mod, uint32_t frames, + const struct audio_stream __sparse_cache *src, + const int8_t *chan_map) { - /* Add speaker protection feed forward process here */ - return x; + int num_samples_remaining; + int nmax, n, ch, i; + int n_mod = 0; + int src_ch = audio_stream_get_channels(src); + int32_t *src_ptr_base = audio_stream_get_rptr(src); + int32_t *mod_ptr_base = (int32_t *)src_mod->buf.data; + int32_t *src_ptr; + int32_t *mod_ptr; + + /* clean up dst buffer to make sure all 0s on the unmapped channel */ + bzero(mod_ptr_base, src_mod->buf.size); + + num_samples_remaining = frames * src_ch; + while (num_samples_remaining) { + nmax = audio_stream_samples_without_wrap_s32(src, src_ptr_base); + n = MIN(num_samples_remaining, nmax); + + for (ch = 0; ch < src_mod->channels; ch++) { + if (chan_map[ch] == -1) + continue; + + mod_ptr = mod_ptr_base + ch; + src_ptr = src_ptr_base + chan_map[ch]; + n_mod = 0; + for (i = 0; i < n; i += src_ch) { + *mod_ptr = *src_ptr; + mod_ptr += src_mod->channels; + src_ptr += src_ch; + n_mod += src_mod->channels; + } + } + /* update base pointers by forwarding (n / src_ch) frames */ + mod_ptr_base += n_mod; + src_ptr_base += n; + + num_samples_remaining -= n; + src_ptr_base = audio_stream_wrap(src, src_ptr_base); + } } -static void smart_amp_fb_generic(int32_t x) +static void remap_s24_to_s24(struct smart_amp_mod_stream *src_mod, uint32_t frames, + const struct audio_stream __sparse_cache *src, + const int8_t *chan_map) { - /* Add speaker protection feedback process here */ + remap_s32_to_s32(src_mod, frames, src, chan_map); } -#if CONFIG_FORMAT_S16LE -static void smart_amp_s16_ff_default(const struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *feedback, - uint32_t frames) -{ - int16_t *x; - int16_t *y; - int32_t tmp; - int idx; - int ch; +static void remap_s24_to_s32(struct smart_amp_mod_stream *src_mod, uint32_t frames, + const struct audio_stream __sparse_cache *src, + const int8_t *chan_map) +{ int i; - int nch = audio_stream_get_channels(source); - - for (ch = 0; ch < nch; ch++) { - idx = ch; - for (i = 0; i < frames; i++) { - x = audio_stream_read_frag_s16(source, idx); - y = audio_stream_read_frag_s16(sink, idx); - tmp = smart_amp_ff_generic(*x << 16); - *y = sat_int16(Q_SHIFT_RND(tmp, 31, 15)); - idx += nch; - } + int n_mod = frames * src_mod->channels; + int32_t *mod_ptr = (int32_t *)src_mod->buf.data; + + remap_s32_to_s32(src_mod, frames, src, chan_map); + + /* one loop for in-place lshift (s24-to-s32) after remapping */ + for (i = 0; i < n_mod; i++) { + *mod_ptr = *mod_ptr << 8; + mod_ptr++; } } -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S24LE -static void smart_amp_s24_ff_default(const struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *feedback, - uint32_t frames) -{ - int32_t *x; - int32_t *y; - int32_t tmp; - int idx; - int ch; - int i; - int nch = audio_stream_get_channels(source); - - for (ch = 0; ch < nch; ch++) { - idx = ch; - for (i = 0; i < frames; i++) { - x = audio_stream_read_frag_s32(source, idx); - y = audio_stream_read_frag_s32(sink, idx); - tmp = smart_amp_ff_generic(*x << 8); - *y = sat_int24(Q_SHIFT_RND(tmp, 31, 23)); - idx += nch; +static void remap_s16_to_s16(struct smart_amp_mod_stream *src_mod, uint32_t frames, + const struct audio_stream __sparse_cache *src, + const int8_t *chan_map) +{ + int num_samples_remaining; + int nmax, n, ch, i; + int n_mod = 0; + int src_ch = audio_stream_get_channels(src); + int16_t *src_ptr_base = audio_stream_get_rptr(src); + int16_t *mod_ptr_base = (int16_t *)src_mod->buf.data; + int16_t *src_ptr; + int16_t *mod_ptr; + + /* clean up mod buffer (dst) to keep all-0 data on the unmapped channel */ + bzero(mod_ptr_base, src_mod->buf.size); + + num_samples_remaining = frames * src_ch; + while (num_samples_remaining) { + nmax = audio_stream_samples_without_wrap_s16(src, src_ptr_base); + n = MIN(num_samples_remaining, nmax); + + for (ch = 0; ch < src_mod->channels; ch++) { + if (chan_map[ch] == -1) + continue; + + mod_ptr = mod_ptr_base + ch; + src_ptr = src_ptr_base + chan_map[ch]; + n_mod = 0; + for (i = 0; i < n; i += src_ch) { + *mod_ptr = *src_ptr; + mod_ptr += src_mod->channels; + src_ptr += src_ch; + n_mod += src_mod->channels; + } } + /* update base pointers by forwarding (n / src_ch) frames */ + mod_ptr_base += n_mod; + src_ptr_base += n; + + num_samples_remaining -= n; + src_ptr_base = audio_stream_wrap(src, src_ptr_base); } } -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S32LE -static void smart_amp_s32_ff_default(const struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *feedback, - uint32_t frames) -{ - int32_t *x; - int32_t *y; - int idx; - int ch; - int i; - int nch = audio_stream_get_channels(source); - - for (ch = 0; ch < nch; ch++) { - idx = ch; - for (i = 0; i < frames; i++) { - x = audio_stream_read_frag_s32(source, idx); - y = audio_stream_read_frag_s32(sink, idx); - *y = smart_amp_ff_generic(*x); - idx += nch; +static void remap_s16_to_b32(struct smart_amp_mod_stream *src_mod, uint32_t frames, + const struct audio_stream __sparse_cache *src, + const int8_t *chan_map, int lshift) +{ + int num_samples_remaining; + int nmax, n, ch, i; + int n_mod = 0; + int src_ch = audio_stream_get_channels(src); + int16_t *src_ptr_base = audio_stream_get_rptr(src); + int32_t *mod_ptr_base = (int32_t *)src_mod->buf.data; + int16_t *src_ptr; + int32_t *mod_ptr; + + /* clean up dst buffer to make sure all 0s on the unmapped channel */ + bzero(mod_ptr_base, src_mod->buf.size); + + num_samples_remaining = frames * src_ch; + while (num_samples_remaining) { + nmax = audio_stream_samples_without_wrap_s16(src, src_ptr_base); + n = MIN(num_samples_remaining, nmax); + + for (ch = 0; ch < src_mod->channels; ch++) { + if (chan_map[ch] == -1) + continue; + + mod_ptr = mod_ptr_base + ch; + src_ptr = src_ptr_base + chan_map[ch]; + n_mod = 0; + for (i = 0; i < n; i += src_ch) { + *mod_ptr = (int32_t)*src_ptr << lshift; + mod_ptr += src_mod->channels; + src_ptr += src_ch; + n_mod += src_mod->channels; + } } + /* update base pointers by forwarding (n / src_ch) frames */ + mod_ptr_base += n_mod; + src_ptr_base += n; + + num_samples_remaining -= n; + src_ptr_base = audio_stream_wrap(src, src_ptr_base); } } -#endif /* CONFIG_FORMAT_S32LE */ -#if CONFIG_FORMAT_S16LE -static void smart_amp_s16_fb_default(const struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *feedback, - uint32_t frames) -{ - int16_t *x; - int idx; - int ch; - int i; - int nch = audio_stream_get_channels(source); - - for (ch = 0; ch < nch; ch++) { - idx = ch; - for (i = 0; i < frames; i++) { - x = audio_stream_read_frag_s16(feedback, idx); - smart_amp_fb_generic(*x << 16); - idx += nch; +static void remap_s16_to_s24(struct smart_amp_mod_stream *src_mod, uint32_t frames, + const struct audio_stream __sparse_cache *src, + const int8_t *chan_map) +{ + remap_s16_to_b32(src_mod, frames, src, chan_map, 8 /* lshift */); +} + +static void remap_s16_to_s32(struct smart_amp_mod_stream *src_mod, uint32_t frames, + const struct audio_stream __sparse_cache *src, + const int8_t *chan_map) +{ + remap_s16_to_b32(src_mod, frames, src, chan_map, 16 /* lshift */); +} + +static void feed_s32_to_s32(const struct smart_amp_mod_stream *sink_mod, uint32_t frames, + const struct audio_stream __sparse_cache *sink) +{ + int num_samples_remaining; + int nmax, n, ch, i; + int sink_ch = audio_stream_get_channels(sink); + int feed_channels = MIN(sink_ch, sink_mod->channels); + int32_t *sink_ptr = audio_stream_get_wptr(sink); + int32_t *mod_ptr = (int32_t *)sink_mod->buf.data; + + num_samples_remaining = frames * sink_ch; + while (num_samples_remaining) { + nmax = audio_stream_samples_without_wrap_s32(sink, sink_ptr); + n = MIN(num_samples_remaining, nmax); + + for (i = 0; i < n; i += sink_ch) { + for (ch = 0; ch < feed_channels; ch++) + *(sink_ptr + ch) = *(mod_ptr + ch); + + sink_ptr += sink_ch; + mod_ptr += sink_mod->channels; } + + num_samples_remaining -= n; + sink_ptr = audio_stream_wrap(sink, sink_ptr); } } -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S24LE -static void smart_amp_s24_fb_default(const struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *feedback, - uint32_t frames) -{ - int32_t *x; - int idx; - int ch; +static void feed_s24_to_s24(const struct smart_amp_mod_stream *sink_mod, uint32_t frames, + const struct audio_stream __sparse_cache *sink) +{ + feed_s32_to_s32(sink_mod, frames, sink); +} + +static void feed_s32_to_s24(const struct smart_amp_mod_stream *sink_mod, uint32_t frames, + const struct audio_stream __sparse_cache *sink) +{ int i; - int nch = audio_stream_get_channels(source); - - for (ch = 0; ch < nch; ch++) { - idx = ch; - for (i = 0; i < frames; i++) { - x = audio_stream_read_frag_s32(feedback, idx); - smart_amp_fb_generic(*x << 8); - idx += nch; + int sink_ch = audio_stream_get_channels(sink); + int n_mod = frames * sink_mod->channels; + int32_t *mod_ptr = (int32_t *)sink_mod->buf.data; + + /* one loop for in-place rshift (s32-to-s24) before feeding */ + for (i = 0; i < n_mod; i++) { + *mod_ptr = sat_int24(Q_SHIFT_RND(*mod_ptr, 31, 23)); + mod_ptr++; + } + + feed_s32_to_s32(sink_mod, frames, sink); +} + +static void feed_s16_to_s16(const struct smart_amp_mod_stream *sink_mod, uint32_t frames, + const struct audio_stream __sparse_cache *sink) +{ + int num_samples_remaining; + int nmax, n, ch, i; + int sink_ch = audio_stream_get_channels(sink); + int feed_channels = MIN(sink_ch, sink_mod->channels); + int16_t *sink_ptr = audio_stream_get_wptr(sink); + int16_t *mod_ptr = (int16_t *)sink_mod->buf.data; + + num_samples_remaining = frames * sink_ch; + while (num_samples_remaining) { + nmax = audio_stream_samples_without_wrap_s16(sink, sink_ptr); + n = MIN(num_samples_remaining, nmax); + + for (i = 0; i < n; i += sink_ch) { + for (ch = 0; ch < feed_channels; ch++) + *(sink_ptr + ch) = *(mod_ptr + ch); + + sink_ptr += sink_ch; + mod_ptr += sink_mod->channels; } + + num_samples_remaining -= n; + sink_ptr = audio_stream_wrap(sink, sink_ptr); } } -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S32LE -static void smart_amp_s32_fb_default(const struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *feedback, - uint32_t frames) -{ - int32_t *x; - int idx; - int ch; - int i; - int nch = audio_stream_get_channels(source); - - for (ch = 0; ch < nch; ch++) { - idx = ch; - for (i = 0; i < frames; i++) { - x = audio_stream_read_frag_s32(feedback, idx); - smart_amp_ff_generic(*x); - idx += nch; +static void feed_b32_to_s16(const struct smart_amp_mod_stream *sink_mod, uint32_t frames, + const struct audio_stream __sparse_cache *sink, int mod_fbits) +{ + int num_samples_remaining; + int nmax, n, ch, i; + int sink_ch = audio_stream_get_channels(sink); + int feed_channels = MIN(sink_ch, sink_mod->channels); + int16_t *sink_ptr = audio_stream_get_wptr(sink); + int32_t *mod_ptr = (int32_t *)sink_mod->buf.data; + + num_samples_remaining = frames * sink_ch; + while (num_samples_remaining) { + nmax = audio_stream_samples_without_wrap_s16(sink, sink_ptr); + n = MIN(num_samples_remaining, nmax); + + for (i = 0; i < n; i += sink_ch) { + for (ch = 0; ch < feed_channels; ch++) { + *(sink_ptr + ch) = sat_int16(Q_SHIFT_RND(*(mod_ptr + ch), + mod_fbits, 15)); + } + sink_ptr += sink_ch; + mod_ptr += sink_mod->channels; } + + num_samples_remaining -= n; + sink_ptr = audio_stream_wrap(sink, sink_ptr); } } -#endif /* CONFIG_FORMAT_S32LE */ -const struct smart_amp_func_map smart_amp_function_map[] = { -/* { SOURCE_FORMAT , PROCESSING FUNCTION } */ +static void feed_s24_to_s16(const struct smart_amp_mod_stream *sink_mod, uint32_t frames, + const struct audio_stream __sparse_cache *sink) +{ + feed_b32_to_s16(sink_mod, frames, sink, 23 /* mod_fbits */); +} + +static void feed_s32_to_s16(const struct smart_amp_mod_stream *sink_mod, uint32_t frames, + const struct audio_stream __sparse_cache *sink) +{ + feed_b32_to_s16(sink_mod, frames, sink, 31 /* mod_fbits */); +} + +const struct smart_amp_func_map src_sink_func_map[] = { + /* { comp_fmt, mod_fmt, src_func, sink_func } + * cases are valid only if comp_fmt <= mod_fmt + */ #if CONFIG_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, smart_amp_s16_ff_default }, -#endif /* CONFIG_FORMAT_S16LE */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, &remap_s16_to_s16, &feed_s16_to_s16 }, + #if CONFIG_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, smart_amp_s24_ff_default }, -#endif /* CONFIG_FORMAT_S24LE */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, &remap_s16_to_s24, &feed_s24_to_s16 }, +#endif /* CONFIG_FORMAT_S24LE */ + #if CONFIG_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, smart_amp_s32_ff_default }, -#endif /* CONFIG_FORMAT_S32LE */ -#if CONFIG_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, smart_amp_s16_fb_default }, -#endif /* CONFIG_FORMAT_S16LE */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, &remap_s16_to_s32, &feed_s32_to_s16 }, +#endif /* CONFIG_FORMAT_S32LE */ +#endif /* CONFIG_FORMAT_S16LE */ + #if CONFIG_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, smart_amp_s24_fb_default }, -#endif /* CONFIG_FORMAT_S24LE */ + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, &remap_s24_to_s24, &feed_s24_to_s24 }, + +#if CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, &remap_s24_to_s32, &feed_s32_to_s24 }, +#endif /* CONFIG_FORMAT_S32LE */ +#endif /* CONFIG_FORMAT_S24LE */ + #if CONFIG_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, smart_amp_s32_fb_default }, -#endif /* CONFIG_FORMAT_S32LE */ + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, &remap_s32_to_s32, &feed_s32_to_s32 }, +#endif /* CONFIG_FORMAT_S32LE */ }; -const size_t smart_amp_func_count = ARRAY_SIZE(smart_amp_function_map); -#endif +smart_amp_src_func smart_amp_get_src_func(uint16_t comp_fmt, uint16_t mod_fmt) +{ + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(src_sink_func_map); i++) { + if (comp_fmt == src_sink_func_map[i].comp_fmt && + mod_fmt == src_sink_func_map[i].mod_fmt) + return src_sink_func_map[i].src_func; + } + + return NULL; +} + +smart_amp_sink_func smart_amp_get_sink_func(uint16_t comp_fmt, uint16_t mod_fmt) +{ + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(src_sink_func_map); i++) { + if (comp_fmt == src_sink_func_map[i].comp_fmt && + mod_fmt == src_sink_func_map[i].mod_fmt) + return src_sink_func_map[i].sink_func; + } + + return NULL; +} diff --git a/src/audio/smart_amp/smart_amp_maxim_dsm.c b/src/audio/smart_amp/smart_amp_maxim_dsm.c index ed6b5a218511..e45620248dd4 100644 --- a/src/audio/smart_amp/smart_amp_maxim_dsm.c +++ b/src/audio/smart_amp/smart_amp_maxim_dsm.c @@ -20,8 +20,119 @@ #include #include "dsm_api_public.h" -static int maxim_dsm_init(struct smart_amp_mod_struct_t *hspk, struct comp_dev *dev) +/* Maxim DSM(Dynamic Speaker Management) process buffer size */ +#define DSM_FRM_SZ 48 +#define DSM_FF_BUF_SZ (DSM_FRM_SZ * SMART_AMP_FF_MAX_CH_NUM) +#define DSM_FB_BUF_SZ (DSM_FRM_SZ * SMART_AMP_FB_MAX_CH_NUM) + +#define DSM_FF_BUF_DB_SZ (DSM_FF_BUF_SZ * SMART_AMP_FF_MAX_CH_NUM) +#define DSM_FB_BUF_DB_SZ (DSM_FB_BUF_SZ * SMART_AMP_FB_MAX_CH_NUM) + +/* DSM parameter table structure + * +--------------+-----------------+---------------------------------+ + * | ID (4 bytes) | VALUE (4 bytes) | 1st channel : | + * | | | 8 bytes per single parameter | + * +--------------+-----------------+---------------------------------+ + * | ... | ... | Repeat N times for N parameters | + * +--------------+-----------------+---------------------------------+ + * | ID (4 bytes) | VALUE (4 bytes) | 2nd channel : | + * | | | 8 bytes per single parameter | + * +--------------+-----------------+---------------------------------+ + * | ... | ... | Repeat N times for N parameters | + * +--------------+-----------------+---------------------------------+ + */ +enum dsm_param { + DSM_PARAM_ID = 0, + DSM_PARAM_VALUE, + DSM_PARAM_MAX +}; + +#define DSM_SINGLE_PARAM_SZ (DSM_PARAM_MAX * SMART_AMP_FF_MAX_CH_NUM) + +static const int supported_fmt_count = 3; +static const uint16_t supported_fmts[] = { + SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE +}; + +union maxim_dsm_buf { + int16_t *buf16; + int32_t *buf32; +}; + +struct maxim_dsm_ff_buf_struct_t { + int32_t *buf; + int avail; +}; + +struct maxim_dsm_fb_buf_struct_t { + int32_t *buf; + int avail; + int rdy; +}; + +struct smart_amp_buf_struct_t { + /* buffer : feed forward process input */ + int32_t *input; + /* buffer : feed forward process output */ + int32_t *output; + /* buffer : feedback voltage */ + int32_t *voltage; + /* buffer : feedback current */ + int32_t *current; + /* buffer : feed forward variable length -> fixed length */ + struct maxim_dsm_ff_buf_struct_t ff; + /* buffer : feed forward variable length <- fixed length */ + struct maxim_dsm_ff_buf_struct_t ff_out; + /* buffer : feedback variable length -> fixed length */ + struct maxim_dsm_fb_buf_struct_t fb; +}; + +struct param_buf_struct_t { + int id; + int value; +}; + +struct smart_amp_caldata { + uint32_t data_size; /* size of component's model data */ + void *data; /* model data pointer */ + uint32_t data_pos; /* data position for read/write */ +}; + +struct smart_amp_param_struct_t { + struct param_buf_struct_t param; /* variable to keep last parameter ID/value */ + struct smart_amp_caldata caldata; /* model data buffer */ + int pos; /* data position for read/write */ + int max_param; /* keep max number of DSM parameters */ +}; + +/* self-declared inner model data struct */ +struct smart_amp_mod_struct_t { + struct smart_amp_mod_data_base base; + struct smart_amp_buf_struct_t buf; + void *dsmhandle; + /* DSM variables for the initialization */ + int delayedsamples[SMART_AMP_FF_MAX_CH_NUM << 2]; + int circularbuffersize[SMART_AMP_FF_MAX_CH_NUM << 2]; + /* Number of samples of feed forward and feedback frame */ + int ff_fr_sz_samples; + int fb_fr_sz_samples; + int channelmask; + /* Number of channels of DSM */ + int nchannels; + /* Number of samples of feed forward channel */ + int ifsamples; + /* Number of samples of feedback channel */ + int ibsamples; + /* Number of processed samples */ + int ofsamples; + /* Channel bit dempth */ + int bitwidth; + struct smart_amp_param_struct_t param; +}; + +static int maxim_dsm_init(struct smart_amp_mod_struct_t *hspk) { + const struct comp_dev *dev = hspk->base.dev; int *circularbuffersize = hspk->circularbuffersize; int *delayedsamples = hspk->delayedsamples; struct dsm_api_init_ext_t initparam; @@ -33,11 +144,16 @@ static int maxim_dsm_init(struct smart_amp_mod_struct_t *hspk, struct comp_dev * initparam.ipdelayedsamples = delayedsamples; initparam.isamplingrate = DSM_DEFAULT_SAMPLE_RATE; + if (!hspk->dsmhandle) { + comp_err(dev, "[DSM] Initialization failed: dsmhandle not allocated"); + return -EINVAL; + } + retcode = dsm_api_init(hspk->dsmhandle, &initparam, sizeof(struct dsm_api_init_ext_t)); if (retcode != DSM_API_OK) { goto exit; - } else { + } else { hspk->ff_fr_sz_samples = initparam.off_framesizesamples; hspk->fb_fr_sz_samples = @@ -60,8 +176,62 @@ static int maxim_dsm_init(struct smart_amp_mod_struct_t *hspk, struct comp_dev * return (int)retcode; } -static int maxim_dsm_get_all_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev) +static int maxim_dsm_get_num_param(struct smart_amp_mod_struct_t *hspk) +{ + enum DSM_API_MESSAGE retcode; + int cmdblock[DSM_GET_PARAM_SZ_PAYLOAD]; + + /* Get number of parameters */ + cmdblock[DSM_GET_ID_IDX] = DSM_SET_CMD_ID(DSM_API_GET_MAXIMUM_CMD_ID); + retcode = dsm_api_get_params(hspk->dsmhandle, 1, (void *)cmdblock); + if (retcode != DSM_API_OK) + return 0; + + return MIN(DSM_DEFAULT_MAX_NUM_PARAM, cmdblock[DSM_GET_CH1_IDX]); +} + +static int maxim_dsm_get_handle_size(struct smart_amp_mod_struct_t *hspk) +{ + enum DSM_API_MESSAGE retcode; + struct dsm_api_memory_size_ext_t memsize; + int *circularbuffersize = hspk->circularbuffersize; + + memsize.ichannels = DSM_DEFAULT_NUM_CHANNEL; + memsize.ipcircbuffersizebytes = circularbuffersize; + memsize.isamplingrate = DSM_DEFAULT_SAMPLE_RATE; + memsize.omemsizerequestedbytes = 0; + memsize.numeqfilters = DSM_DEFAULT_NUM_EQ; + retcode = dsm_api_get_mem(&memsize, + sizeof(struct dsm_api_memory_size_ext_t)); + if (retcode != DSM_API_OK) + return 0; + + return memsize.omemsizerequestedbytes; +} + +static int maxim_dsm_flush(struct smart_amp_mod_struct_t *hspk) +{ + const struct comp_dev *dev = hspk->base.dev; + + memset(hspk->buf.input, 0, DSM_FF_BUF_SZ * sizeof(int32_t)); + memset(hspk->buf.output, 0, DSM_FF_BUF_SZ * sizeof(int32_t)); + memset(hspk->buf.voltage, 0, DSM_FF_BUF_SZ * sizeof(int32_t)); + memset(hspk->buf.current, 0, DSM_FF_BUF_SZ * sizeof(int32_t)); + + memset(hspk->buf.ff.buf, 0, DSM_FF_BUF_DB_SZ * sizeof(int32_t)); + memset(hspk->buf.ff_out.buf, 0, DSM_FF_BUF_DB_SZ * sizeof(int32_t)); + memset(hspk->buf.fb.buf, 0, DSM_FB_BUF_DB_SZ * sizeof(int32_t)); + + hspk->buf.ff.avail = DSM_FF_BUF_SZ; + hspk->buf.ff_out.avail = 0; + hspk->buf.fb.avail = 0; + + comp_dbg(dev, "[DSM] Reset (handle:%p)", hspk); + + return 0; +} + +static int maxim_dsm_get_all_param(struct smart_amp_mod_struct_t *hspk) { struct smart_amp_caldata *caldata = &hspk->param.caldata; int32_t *db = (int32_t *)caldata->data; @@ -96,7 +266,7 @@ static int maxim_dsm_get_all_param(struct smart_amp_mod_struct_t *hspk, } static int maxim_dsm_get_volatile_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev) + const struct comp_dev *dev) { struct smart_amp_caldata *caldata = &hspk->param.caldata; int32_t *db = (int32_t *)caldata->data; @@ -125,42 +295,10 @@ static int maxim_dsm_get_volatile_param(struct smart_amp_mod_struct_t *hspk, return 0; } -int maxim_dsm_get_param_forced(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev) -{ - struct smart_amp_caldata *caldata = &hspk->param.caldata; - int32_t *db = (int32_t *)caldata->data; - enum DSM_API_MESSAGE retcode; - int cmdblock[DSM_GET_PARAM_SZ_PAYLOAD]; - int num_param = hspk->param.max_param; - int idx; - - /* Update all parameter values from the DSM component */ - for (idx = 0 ; idx <= num_param ; idx++) { - cmdblock[0] = DSM_SET_CMD_ID(idx); - retcode = dsm_api_get_params(hspk->dsmhandle, 1, (void *)cmdblock); - if (retcode != DSM_API_OK) { - /* set zero if the parameter is not readable */ - cmdblock[DSM_GET_CH1_IDX] = 0; - cmdblock[DSM_GET_CH2_IDX] = 0; - } - /* fill the data for the 1st channel 4 byte ID + 4 byte value */ - db[idx * DSM_PARAM_MAX + DSM_PARAM_ID] = DSM_CH1_BITMASK | idx; - db[idx * DSM_PARAM_MAX + DSM_PARAM_VALUE] = cmdblock[DSM_GET_CH1_IDX]; - /* fill the data for the 2nd channel 4 byte ID + 4 byte value - * 2nd channel data have offset for num_param * DSM_PARAM_MAX - */ - db[(idx + num_param) * DSM_PARAM_MAX + DSM_PARAM_ID] = DSM_CH2_BITMASK | idx; - db[(idx + num_param) * DSM_PARAM_MAX + DSM_PARAM_VALUE] = cmdblock[DSM_GET_CH2_IDX]; - } - - return 0; -} - -int maxim_dsm_get_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata, int size) +static int maxim_dsm_get_param(struct smart_amp_mod_struct_t *hspk, + struct sof_ipc_ctrl_data *cdata, int size) { + const struct comp_dev *dev = hspk->base.dev; struct smart_amp_caldata *caldata = &hspk->param.caldata; size_t bs; int ret; @@ -203,10 +341,10 @@ int maxim_dsm_get_param(struct smart_amp_mod_struct_t *hspk, return 0; } -int maxim_dsm_set_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata) +static int maxim_dsm_set_param(struct smart_amp_mod_struct_t *hspk, + struct sof_ipc_ctrl_data *cdata) { + const struct comp_dev *dev = hspk->base.dev; struct smart_amp_param_struct_t *param = &hspk->param; struct smart_amp_caldata *caldata = &hspk->param.caldata; /* Model database */ @@ -265,9 +403,9 @@ int maxim_dsm_set_param(struct smart_amp_mod_struct_t *hspk, return 0; } -int maxim_dsm_restore_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev) +static int maxim_dsm_restore_param(struct smart_amp_mod_struct_t *hspk) { + const struct comp_dev *dev = hspk->base.dev; struct smart_amp_caldata *caldata = &hspk->param.caldata; int32_t *db = (int32_t *)caldata->data; int num_param = hspk->param.max_param; @@ -290,42 +428,74 @@ int maxim_dsm_restore_param(struct smart_amp_mod_struct_t *hspk, return 0; } -static void maxim_dsm_ff_proc(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev, void *in, void *out, - int nsamples, int szsample) +/** + * mod_ops implementation. + */ + +static int maxim_dsm_get_config(struct smart_amp_mod_data_base *mod, + struct sof_ipc_ctrl_data *cdata, uint32_t size) { - union smart_amp_buf buf, buf_out; + struct smart_amp_mod_struct_t *hspk = (struct smart_amp_mod_struct_t *)mod; + + return maxim_dsm_get_param(hspk, cdata, size); +} + +static int maxim_dsm_set_config(struct smart_amp_mod_data_base *mod, + struct sof_ipc_ctrl_data *cdata) +{ + struct smart_amp_mod_struct_t *hspk = (struct smart_amp_mod_struct_t *)mod; + + return maxim_dsm_set_param(hspk, cdata); +} + +static int maxim_dsm_ff_proc(struct smart_amp_mod_data_base *mod, + uint32_t frames, + struct smart_amp_mod_stream *in, + struct smart_amp_mod_stream *out) +{ + struct smart_amp_mod_struct_t *hspk = (struct smart_amp_mod_struct_t *)mod; + union maxim_dsm_buf buf, buf_out; int16_t *input = (int16_t *)hspk->buf.input; int16_t *output = (int16_t *)hspk->buf.output; int32_t *input32 = hspk->buf.input; int32_t *output32 = hspk->buf.output; int *w_ptr = &hspk->buf.ff.avail; int *r_ptr = &hspk->buf.ff_out.avail; - bool is_16bit = szsample == 2 ? true : false; + bool is_16bit = (in->frame_fmt == SOF_IPC_FRAME_S16_LE); + int szsample = (is_16bit ? 2 : 4); + int nsamples = frames * in->channels; int remain; int idx; + int ret = 0; buf.buf16 = (int16_t *)hspk->buf.ff.buf; buf.buf32 = (int32_t *)hspk->buf.ff.buf; buf_out.buf16 = (int16_t *)hspk->buf.ff_out.buf; buf_out.buf32 = (int32_t *)hspk->buf.ff_out.buf; + /* Report all frames consumed even if buffer overflow to prevent source + * congestion. Same for frames produced to keep the stream rolling. + */ + in->consumed = frames; + out->produced = frames; + /* Current pointer(w_ptr) + number of input frames(nsamples) * must be smaller than buffer size limit */ if (*w_ptr + nsamples <= DSM_FF_BUF_DB_SZ) { if (is_16bit) memcpy_s(&buf.buf16[*w_ptr], nsamples * szsample, - in, nsamples * szsample); + in->buf.data, nsamples * szsample); else memcpy_s(&buf.buf32[*w_ptr], nsamples * szsample, - in, nsamples * szsample); + in->buf.data, nsamples * szsample); *w_ptr += nsamples; } else { - comp_warn(dev, + comp_warn(mod->dev, "[DSM] Feed Forward buffer overflow. (w_ptr : %d + %d > %d)", *w_ptr, nsamples, DSM_FF_BUF_DB_SZ); - return; + ret = -EOVERFLOW; + goto error; } /* Run DSM Feedforward process if the buffer is ready */ @@ -387,10 +557,10 @@ static void maxim_dsm_ff_proc(struct smart_amp_mod_struct_t *hspk, /* Output buffer preparation */ if (*r_ptr >= nsamples) { if (is_16bit) - memcpy_s(out, nsamples * szsample, + memcpy_s(out->buf.data, nsamples * szsample, buf_out.buf16, nsamples * szsample); else - memcpy_s(out, nsamples * szsample, + memcpy_s(out->buf.data, nsamples * szsample, buf_out.buf32, nsamples * szsample); remain = (*r_ptr - nsamples); @@ -405,47 +575,65 @@ static void maxim_dsm_ff_proc(struct smart_amp_mod_struct_t *hspk, remain * szsample); } *r_ptr -= nsamples; - } else { - memset(out, 0, nsamples * szsample); - comp_err(dev, - "[DSM] DSM FF process underrun. r_ptr : %d", - *r_ptr); + return ret; } + /* else { */ + comp_err(mod->dev, "[DSM] DSM FF process underrun. r_ptr : %d", *r_ptr); + ret = -ENODATA; + +error: + /* TODO(Maxim): undefined behavior when buffer overflow in previous code. + * It leads to early return and no sample written to output + * buffer. However the sink buffer will still writeback + * avail_frames data copied from output buffer. + */ + /* set all-zero output when buffer overflow or process underrun. */ + memset_s(out->buf.data, out->buf.size, 0, nsamples * szsample); + return ret; } -static void maxim_dsm_fb_proc(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev, void *in, - int nsamples, int szsample) +static int maxim_dsm_fb_proc(struct smart_amp_mod_data_base *mod, + uint32_t frames, + struct smart_amp_mod_stream *in) { - union smart_amp_buf buf; + struct smart_amp_mod_struct_t *hspk = (struct smart_amp_mod_struct_t *)mod; + union maxim_dsm_buf buf; int *w_ptr = &hspk->buf.fb.avail; int16_t *v = (int16_t *)hspk->buf.voltage; int16_t *i = (int16_t *)hspk->buf.current; int32_t *v32 = hspk->buf.voltage; int32_t *i32 = hspk->buf.current; - bool is_16bit = szsample == 2 ? true : false; + bool is_16bit = (in->frame_fmt == SOF_IPC_FRAME_S16_LE); + int szsample = (is_16bit ? 2 : 4); + int nsamples = frames * in->channels; int remain; int idx; buf.buf16 = (int16_t *)hspk->buf.fb.buf; buf.buf32 = hspk->buf.fb.buf; + /* Set all frames consumed even if buffer overflow to prevent source + * congestion. + */ + in->consumed = frames; + /* Current pointer(w_ptr) + number of input frames(nsamples) * must be smaller than buffer size limit */ if (*w_ptr + nsamples <= DSM_FB_BUF_DB_SZ) { if (is_16bit) memcpy_s(&buf.buf16[*w_ptr], nsamples * szsample, - in, nsamples * szsample); + in->buf.data, nsamples * szsample); else memcpy_s(&buf.buf32[*w_ptr], nsamples * szsample, - in, nsamples * szsample); + in->buf.data, nsamples * szsample); *w_ptr += nsamples; } else { - comp_warn(dev, "[DSM] Feedback buffer overflow. w_ptr : %d", + comp_warn(mod->dev, "[DSM] Feedback buffer overflow. w_ptr : %d", *w_ptr); - return; + return -EOVERFLOW; } + /* Run DSM Feedback process if the buffer is ready */ if (*w_ptr >= DSM_FB_BUF_SZ) { if (is_16bit) { @@ -490,189 +678,99 @@ static void maxim_dsm_fb_proc(struct smart_amp_mod_struct_t *hspk, hspk->channelmask, (short *)i32, (short *)v32, &hspk->ibsamples); } -} - -int smart_amp_flush(struct smart_amp_mod_struct_t *hspk, struct comp_dev *dev) -{ - memset(hspk->buf.frame_in, 0, - SMART_AMP_FF_BUF_DB_SZ * sizeof(int32_t)); - memset(hspk->buf.frame_out, 0, - SMART_AMP_FF_BUF_DB_SZ * sizeof(int32_t)); - memset(hspk->buf.frame_iv, 0, - SMART_AMP_FB_BUF_DB_SZ * sizeof(int32_t)); - - memset(hspk->buf.input, 0, DSM_FF_BUF_SZ * sizeof(int16_t)); - memset(hspk->buf.output, 0, DSM_FF_BUF_SZ * sizeof(int16_t)); - memset(hspk->buf.voltage, 0, DSM_FF_BUF_SZ * sizeof(int16_t)); - memset(hspk->buf.current, 0, DSM_FF_BUF_SZ * sizeof(int16_t)); - - memset(hspk->buf.ff.buf, 0, DSM_FF_BUF_DB_SZ * sizeof(int32_t)); - memset(hspk->buf.ff_out.buf, 0, DSM_FF_BUF_DB_SZ * sizeof(int32_t)); - memset(hspk->buf.fb.buf, 0, DSM_FB_BUF_DB_SZ * sizeof(int32_t)); - - hspk->buf.ff.avail = DSM_FF_BUF_SZ; - hspk->buf.ff_out.avail = 0; - hspk->buf.fb.avail = 0; - - comp_dbg(dev, "[DSM] Reset (handle:%p)", hspk); - - return 0; -} - -int smart_amp_init(struct smart_amp_mod_struct_t *hspk, struct comp_dev *dev) -{ - return maxim_dsm_init(hspk, dev); -} - -int smart_amp_get_all_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev) -{ - if (maxim_dsm_get_all_param(hspk, dev) < 0) - return -EINVAL; return 0; } -int smart_amp_get_num_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev) +static int maxim_dsm_preinit(struct smart_amp_mod_data_base *mod) { - enum DSM_API_MESSAGE retcode; - int cmdblock[DSM_GET_PARAM_SZ_PAYLOAD]; + struct smart_amp_mod_struct_t *hspk = (struct smart_amp_mod_struct_t *)mod; - /* Get number of parameters */ - cmdblock[DSM_GET_ID_IDX] = DSM_SET_CMD_ID(DSM_API_GET_MAXIMUM_CMD_ID); - retcode = dsm_api_get_params(hspk->dsmhandle, 1, (void *)cmdblock); - if (retcode != DSM_API_OK) - return 0; - - return MIN(DSM_DEFAULT_MAX_NUM_PARAM, cmdblock[DSM_GET_CH1_IDX]); -} - -int smart_amp_get_memory_size(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev) -{ - enum DSM_API_MESSAGE retcode; - struct dsm_api_memory_size_ext_t memsize; - int *circularbuffersize = hspk->circularbuffersize; - - memsize.ichannels = DSM_DEFAULT_NUM_CHANNEL; - memsize.ipcircbuffersizebytes = circularbuffersize; - memsize.isamplingrate = DSM_DEFAULT_SAMPLE_RATE; - memsize.omemsizerequestedbytes = 0; - memsize.numeqfilters = DSM_DEFAULT_NUM_EQ; - retcode = dsm_api_get_mem(&memsize, - sizeof(struct dsm_api_memory_size_ext_t)); - if (retcode != DSM_API_OK) - return 0; - - return memsize.omemsizerequestedbytes; + /* Bitwidth information is not available. Use 16bit as default. + * Re-initialize in the prepare function if ncessary + */ + hspk->bitwidth = 16; + return maxim_dsm_init(hspk); } -int smart_amp_check_audio_fmt(int sample_rate, int ch_num) +static int maxim_dsm_query_memblk_size(struct smart_amp_mod_data_base *mod, + enum smart_amp_mod_memblk blk) { - /* Return error if the format is not supported by DSM component */ - if (sample_rate != DSM_DEFAULT_SAMPLE_RATE) - return -EINVAL; - if (ch_num > DSM_DEFAULT_NUM_CHANNEL) - return -EINVAL; - - return 0; -} + struct smart_amp_mod_struct_t *hspk = (struct smart_amp_mod_struct_t *)mod; + int ret; -static int smart_amp_get_buffer(int32_t *buf, uint32_t frames, - const struct audio_stream __sparse_cache *stream, - int8_t *chan_map, uint32_t num_ch) -{ - int idx, ch; - uint32_t in_frag = 0; - union smart_amp_buf input, output; - int index; - - input.buf16 = audio_stream_get_rptr(stream); - input.buf32 = audio_stream_get_rptr(stream); - output.buf16 = (int16_t *)buf; - output.buf32 = (int32_t *)buf; - - switch (audio_stream_get_frm_fmt(stream)) { - case SOF_IPC_FRAME_S16_LE: - for (idx = 0 ; idx < frames ; idx++) { - for (ch = 0 ; ch < num_ch; ch++) { - if (chan_map[ch] == -1) - continue; - index = in_frag + chan_map[ch]; - input.buf16 = - audio_stream_read_frag_s16(stream, - index); - output.buf16[num_ch * idx + ch] = *input.buf16; - } - in_frag += audio_stream_get_channels(stream); - } + switch (blk) { + case MOD_MEMBLK_PRIVATE: + /* Memory size for private data block - dsmhandle */ + ret = maxim_dsm_get_handle_size(hspk); + if (ret <= 0) + comp_err(mod->dev, "[DSM] Get handle size error"); break; - case SOF_IPC_FRAME_S24_4LE: - case SOF_IPC_FRAME_S32_LE: - for (idx = 0 ; idx < frames ; idx++) { - for (ch = 0 ; ch < num_ch ; ch++) { - if (chan_map[ch] == -1) - continue; - index = in_frag + chan_map[ch]; - input.buf32 = - audio_stream_read_frag_s32(stream, - index); - output.buf32[num_ch * idx + ch] = *input.buf32; - } - in_frag += audio_stream_get_channels(stream); + case MOD_MEMBLK_FRAME: + /* Memory size for frame buffer block - smart_amp_buf_struct_t */ + /* smart_amp_buf_struct_t -> input, output, voltage, current */ + ret = 4 * DSM_FF_BUF_SZ * sizeof(int32_t); + /* smart_amp_buf_struct_t -> ff, ff_out, fb */ + ret += 2 * DSM_FF_BUF_DB_SZ * sizeof(int32_t) + DSM_FB_BUF_DB_SZ * sizeof(int32_t); + break; + case MOD_MEMBLK_PARAM: + /* Memory size for param blob block - caldata */ + /* Get the max. number of parameter to allocate memory for model data */ + ret = maxim_dsm_get_num_param(hspk); + if (ret < 0) { + comp_err(mod->dev, "[DSM] Get parameter size error"); + return -EINVAL; } + hspk->param.max_param = ret; + ret = hspk->param.max_param * DSM_SINGLE_PARAM_SZ * sizeof(int32_t); break; default: - return -EINVAL; + ret = -EINVAL; + break; } - return 0; + + return ret; } -static int smart_amp_put_buffer(int32_t *buf, uint32_t frames, - const struct audio_stream __sparse_cache *stream, - int8_t *chan_map, uint32_t num_ch_in, - uint32_t num_ch_out) +static int maxim_dsm_set_memblk(struct smart_amp_mod_data_base *mod, + enum smart_amp_mod_memblk blk, + struct smart_amp_buf *buf) { - union smart_amp_buf input, output; - uint32_t out_frag = 0; - int idx, ch; - - input.buf16 = (int16_t *)buf; - input.buf32 = (int32_t *)buf; - output.buf16 = audio_stream_get_wptr(stream); - output.buf32 = audio_stream_get_wptr(stream); - - switch (audio_stream_get_frm_fmt(stream)) { - case SOF_IPC_FRAME_S16_LE: - for (idx = 0 ; idx < frames ; idx++) { - for (ch = 0 ; ch < num_ch_out; ch++) { - if (chan_map[ch] == -1) { - out_frag++; - continue; - } - output.buf16 = - audio_stream_write_frag_s16(stream, - out_frag); - *output.buf16 = input.buf16[num_ch_in * idx + ch]; - out_frag++; - } - } + struct smart_amp_mod_struct_t *hspk = (struct smart_amp_mod_struct_t *)mod; + int32_t *mem_ptr; + + switch (blk) { + case MOD_MEMBLK_PRIVATE: + /* Assign memory to private data */ + hspk->dsmhandle = buf->data; + bzero(hspk->dsmhandle, buf->size); break; - case SOF_IPC_FRAME_S24_4LE: - case SOF_IPC_FRAME_S32_LE: - for (idx = 0 ; idx < frames ; idx++) { - for (ch = 0 ; ch < num_ch_out; ch++) { - if (chan_map[ch] == -1) { - out_frag++; - continue; - } - output.buf32 = - audio_stream_write_frag_s32(stream, - out_frag); - *output.buf32 = input.buf32[num_ch_in * idx + ch]; - out_frag++; - } - } + case MOD_MEMBLK_FRAME: + /* Assign memory to frame buffers */ + mem_ptr = (int32_t *)buf->data; + hspk->buf.input = mem_ptr; + mem_ptr += DSM_FF_BUF_SZ; + hspk->buf.output = mem_ptr; + mem_ptr += DSM_FF_BUF_SZ; + hspk->buf.voltage = mem_ptr; + mem_ptr += DSM_FF_BUF_SZ; + hspk->buf.current = mem_ptr; + mem_ptr += DSM_FF_BUF_SZ; + hspk->buf.ff.buf = mem_ptr; + mem_ptr += DSM_FF_BUF_DB_SZ; + hspk->buf.ff_out.buf = mem_ptr; + mem_ptr += DSM_FF_BUF_DB_SZ; + hspk->buf.fb.buf = mem_ptr; + break; + case MOD_MEMBLK_PARAM: + /* Assign memory to config caldata */ + hspk->param.caldata.data = buf->data; + hspk->param.caldata.data_size = buf->size; + bzero(hspk->param.caldata.data, hspk->param.caldata.data_size); + hspk->param.caldata.data_pos = 0; + + /* update full parameter values */ + if (maxim_dsm_get_all_param(hspk) < 0) + return -EINVAL; break; default: return -EINVAL; @@ -680,110 +778,71 @@ static int smart_amp_put_buffer(int32_t *buf, uint32_t frames, return 0; } -int smart_amp_ff_copy(struct comp_dev *dev, uint32_t frames, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, int8_t *chan_map, - struct smart_amp_mod_struct_t *hspk, - uint32_t num_ch_in, uint32_t num_ch_out) +static int maxim_dsm_get_supported_fmts(struct smart_amp_mod_data_base *mod, + const uint16_t **mod_fmts, int *num_mod_fmts) +{ + *num_mod_fmts = supported_fmt_count; + *mod_fmts = supported_fmts; + return 0; +} + +static int maxim_dsm_set_fmt(struct smart_amp_mod_data_base *mod, uint16_t mod_fmt) { + struct smart_amp_mod_struct_t *hspk = (struct smart_amp_mod_struct_t *)mod; int ret; - if (frames == 0) { - comp_warn(dev, "[DSM] feed forward frame size zero warning."); - return 0; - } + comp_dbg(mod->dev, "[DSM] smart_amp_mod_set_fmt(): %u", mod_fmt); - if (frames > SMART_AMP_FF_BUF_DB_SZ) { - comp_err(dev, "[DSM] feed forward frame size overflow : %d", - frames); - return -EINVAL; - } + hspk->bitwidth = get_sample_bitdepth(mod_fmt); - num_ch_in = MIN(num_ch_in, SMART_AMP_FF_MAX_CH_NUM); - num_ch_out = MIN(num_ch_out, SMART_AMP_FF_OUT_MAX_CH_NUM); - - ret = smart_amp_get_buffer(hspk->buf.frame_in, - frames, source, chan_map, - num_ch_in); - if (ret) - goto err; - - switch (audio_stream_get_frm_fmt(source)) { - case SOF_IPC_FRAME_S16_LE: - maxim_dsm_ff_proc(hspk, dev, - hspk->buf.frame_in, - hspk->buf.frame_out, - frames * num_ch_in, sizeof(int16_t)); - break; - case SOF_IPC_FRAME_S24_4LE: - case SOF_IPC_FRAME_S32_LE: - maxim_dsm_ff_proc(hspk, dev, - hspk->buf.frame_in, - hspk->buf.frame_out, - frames * num_ch_in, sizeof(int32_t)); - break; - default: - ret = -EINVAL; - goto err; + ret = maxim_dsm_init(hspk); + if (ret) { + comp_err(mod->dev, "[DSM] Re-initialization error."); + goto error; + } + ret = maxim_dsm_restore_param(hspk); + if (ret) { + comp_err(mod->dev, "[DSM] Restoration error."); + goto error; } - ret = smart_amp_put_buffer(hspk->buf.frame_out, - frames, sink, chan_map, - MIN(num_ch_in, SMART_AMP_FF_MAX_CH_NUM), - MIN(num_ch_out, SMART_AMP_FF_OUT_MAX_CH_NUM)); - if (ret) - goto err; - - return 0; -err: - comp_err(dev, "[DSM] Not supported frame format"); +error: + maxim_dsm_flush(hspk); return ret; } -int smart_amp_fb_copy(struct comp_dev *dev, uint32_t frames, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, int8_t *chan_map, - struct smart_amp_mod_struct_t *hspk, - uint32_t num_ch) +static int maxim_dsm_reset(struct smart_amp_mod_data_base *mod) { - int ret; - - if (frames == 0) { - comp_warn(dev, "[DSM] feedback frame size zero warning."); - return 0; - } - - if (frames > SMART_AMP_FB_BUF_DB_SZ) { - comp_err(dev, "[DSM] feedback frame size overflow : %d", - frames); - return -EINVAL; - } + /* no-op for reset */ + return 0; +} - num_ch = MIN(num_ch, SMART_AMP_FB_MAX_CH_NUM); +static const struct inner_model_ops maxim_dsm_ops = { + .init = maxim_dsm_preinit, + .query_memblk_size = maxim_dsm_query_memblk_size, + .set_memblk = maxim_dsm_set_memblk, + .get_supported_fmts = maxim_dsm_get_supported_fmts, + .set_fmt = maxim_dsm_set_fmt, + .ff_proc = maxim_dsm_ff_proc, + .fb_proc = maxim_dsm_fb_proc, + .set_config = maxim_dsm_set_config, + .get_config = maxim_dsm_get_config, + .reset = maxim_dsm_reset +}; + +/** + * mod_data_create() implementation. + */ + +struct smart_amp_mod_data_base *mod_data_create(const struct comp_dev *dev) +{ + struct smart_amp_mod_struct_t *hspk; - ret = smart_amp_get_buffer(hspk->buf.frame_iv, - frames, source, - chan_map, num_ch); - if (ret) - goto err; + hspk = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*hspk)); + if (!hspk) + return NULL; - switch (audio_stream_get_frm_fmt(source)) { - case SOF_IPC_FRAME_S16_LE: - maxim_dsm_fb_proc(hspk, dev, hspk->buf.frame_iv, - frames * num_ch, sizeof(int16_t)); - break; - case SOF_IPC_FRAME_S24_4LE: - case SOF_IPC_FRAME_S32_LE: - maxim_dsm_fb_proc(hspk, dev, hspk->buf.frame_iv, - frames * num_ch, sizeof(int32_t)); - break; - default: - ret = -EINVAL; - goto err; - } - return 0; -err: - comp_err(dev, "[DSM] Not supported frame format : %d", - audio_stream_get_frm_fmt(source)); - return ret; + hspk->base.dev = dev; + hspk->base.mod_ops = &maxim_dsm_ops; + return &hspk->base; } diff --git a/src/audio/smart_amp/smart_amp_passthru.c b/src/audio/smart_amp/smart_amp_passthru.c new file mode 100644 index 000000000000..dd5c2fe3d789 --- /dev/null +++ b/src/audio/smart_amp/smart_amp_passthru.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2023 Google LLC. +// +// Author: Pin-chih Lin + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* self-declared inner model data struct */ +struct passthru_mod_data { + struct smart_amp_mod_data_base base; + uint16_t ff_fmt; + uint16_t fb_fmt; +}; + +static const int supported_fmt_count = 3; +static const uint16_t supported_fmts[] = { + SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE +}; + +/** + * mod ops implementation. + */ + +static int passthru_mod_init(struct smart_amp_mod_data_base *mod) +{ + comp_info(mod->dev, "[PassThru Amp] init"); + return 0; +} + +static int passthru_mod_query_memblk_size(struct smart_amp_mod_data_base *mod, + enum smart_amp_mod_memblk blk) +{ + return 0; +} + +static int passthru_mod_set_memblk(struct smart_amp_mod_data_base *mod, + enum smart_amp_mod_memblk blk, + struct smart_amp_buf *buf) +{ + return 0; +} + +static int passthru_mod_get_supported_fmts(struct smart_amp_mod_data_base *mod, + const uint16_t **mod_fmts, int *num_mod_fmts) +{ + *num_mod_fmts = supported_fmt_count; + *mod_fmts = supported_fmts; + return 0; +} + +static int passthru_mod_set_fmt(struct smart_amp_mod_data_base *mod, uint16_t mod_fmt) +{ + struct passthru_mod_data *pmd = (struct passthru_mod_data *)mod; + + comp_info(mod->dev, "[PassThru Amp] set fmt:%u", mod_fmt); + pmd->ff_fmt = mod_fmt; + pmd->fb_fmt = mod_fmt; + return 0; +} + +static int passthru_mod_ff_proc(struct smart_amp_mod_data_base *mod, + uint32_t frames, + struct smart_amp_mod_stream *in, + struct smart_amp_mod_stream *out) +{ + struct passthru_mod_data *pmd = (struct passthru_mod_data *)mod; + bool is_16bit = (pmd->ff_fmt == SOF_IPC_FRAME_S16_LE); + uint32_t szsample = (is_16bit ? 2 : 4); + uint32_t size = frames * in->channels * szsample; + + comp_dbg(mod->dev, "[PassThru Amp] bypass %u frames", frames); + + /* passthrough all frames */ + memcpy_s(out->buf.data, out->buf.size, in->buf.data, size); + in->consumed = frames; + out->produced = frames; + return 0; +} + +static int passthru_mod_fb_proc(struct smart_amp_mod_data_base *mod, + uint32_t frames, + struct smart_amp_mod_stream *in) +{ + in->consumed = frames; + return 0; +} + +static int passthru_mod_get_config(struct smart_amp_mod_data_base *mod, + struct sof_ipc_ctrl_data *cdata, uint32_t size) +{ + cdata->data->abi = SOF_ABI_VERSION; + cdata->data->size = 0; + return 0; +} + +static int passthru_mod_set_config(struct smart_amp_mod_data_base *mod, + struct sof_ipc_ctrl_data *cdata) +{ + return 0; +} + +static int passthru_mod_reset(struct smart_amp_mod_data_base *mod) +{ + comp_info(mod->dev, "[PassThru Amp] reset"); + return 0; +} + +static const struct inner_model_ops passthru_mod_ops = { + .init = passthru_mod_init, + .query_memblk_size = passthru_mod_query_memblk_size, + .set_memblk = passthru_mod_set_memblk, + .get_supported_fmts = passthru_mod_get_supported_fmts, + .set_fmt = passthru_mod_set_fmt, + .ff_proc = passthru_mod_ff_proc, + .fb_proc = passthru_mod_fb_proc, + .set_config = passthru_mod_set_config, + .get_config = passthru_mod_get_config, + .reset = passthru_mod_reset +}; + +/** + * mod_data_create() implementation. + */ + +struct smart_amp_mod_data_base *mod_data_create(const struct comp_dev *dev) +{ + struct passthru_mod_data *mod; + + mod = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*mod)); + if (!mod) + return NULL; + + mod->base.dev = dev; + mod->base.mod_ops = &passthru_mod_ops; + return &mod->base; +} diff --git a/src/audio/source_api_helper.c b/src/audio/source_api_helper.c index 91985aeed969..91eb026812a9 100644 --- a/src/audio/source_api_helper.c +++ b/src/audio/source_api_helper.c @@ -7,7 +7,7 @@ #include #include -void source_init(struct sof_source __sparse_cache *source, const struct source_ops *ops, +void source_init(struct sof_source *source, const struct source_ops *ops, struct sof_audio_stream_params *audio_stream_params) { source->ops = ops; @@ -15,13 +15,13 @@ void source_init(struct sof_source __sparse_cache *source, const struct source_o source->audio_stream_params = audio_stream_params; } -size_t source_get_data_available(struct sof_source __sparse_cache *source) +size_t source_get_data_available(struct sof_source *source) { return source->ops->get_data_available(source); } -int source_get_data(struct sof_source __sparse_cache *source, size_t req_size, - void **data_ptr, void **buffer_start, size_t *buffer_size) +int source_get_data(struct sof_source *source, size_t req_size, + void const **data_ptr, void const **buffer_start, size_t *buffer_size) { int ret; @@ -35,7 +35,7 @@ int source_get_data(struct sof_source __sparse_cache *source, size_t req_size, return ret; } -int source_release_data(struct sof_source __sparse_cache *source, size_t free_size) +int source_release_data(struct sof_source *source, size_t free_size) { int ret; @@ -56,47 +56,47 @@ int source_release_data(struct sof_source __sparse_cache *source, size_t free_si return ret; } -size_t source_get_num_of_processed_bytes(struct sof_source __sparse_cache *source) +size_t source_get_num_of_processed_bytes(struct sof_source *source) { return source->num_of_bytes_processed; } -void source_reset_num_of_processed_bytes(struct sof_source __sparse_cache *source) +void source_reset_num_of_processed_bytes(struct sof_source *source) { source->num_of_bytes_processed = 0; } -enum sof_ipc_frame source_get_frm_fmt(struct sof_source __sparse_cache *source) +enum sof_ipc_frame source_get_frm_fmt(struct sof_source *source) { return source->audio_stream_params->frame_fmt; } -enum sof_ipc_frame source_get_valid_fmt(struct sof_source __sparse_cache *source) +enum sof_ipc_frame source_get_valid_fmt(struct sof_source *source) { return source->audio_stream_params->valid_sample_fmt; } -unsigned int source_get_rate(struct sof_source __sparse_cache *source) +unsigned int source_get_rate(struct sof_source *source) { return source->audio_stream_params->rate; } -unsigned int source_get_channels(struct sof_source __sparse_cache *source) +unsigned int source_get_channels(struct sof_source *source) { return source->audio_stream_params->channels; } -uint32_t source_get_buffer_fmt(struct sof_source __sparse_cache *source) +uint32_t source_get_buffer_fmt(struct sof_source *source) { return source->audio_stream_params->buffer_fmt; } -bool source_get_underrun(struct sof_source __sparse_cache *source) +bool source_get_underrun(struct sof_source *source) { return source->audio_stream_params->underrun_permitted; } -int source_set_valid_fmt(struct sof_source __sparse_cache *source, +int source_set_valid_fmt(struct sof_source *source, enum sof_ipc_frame valid_sample_fmt) { source->audio_stream_params->valid_sample_fmt = valid_sample_fmt; @@ -105,7 +105,7 @@ int source_set_valid_fmt(struct sof_source __sparse_cache *source, return 0; } -int source_set_rate(struct sof_source __sparse_cache *source, unsigned int rate) +int source_set_rate(struct sof_source *source, unsigned int rate) { source->audio_stream_params->rate = rate; if (source->ops->on_audio_format_set) @@ -113,7 +113,7 @@ int source_set_rate(struct sof_source __sparse_cache *source, unsigned int rate) return 0; } -int source_set_channels(struct sof_source __sparse_cache *source, unsigned int channels) +int source_set_channels(struct sof_source *source, unsigned int channels) { source->audio_stream_params->channels = channels; if (source->ops->on_audio_format_set) @@ -121,7 +121,7 @@ int source_set_channels(struct sof_source __sparse_cache *source, unsigned int c return 0; } -int source_set_buffer_fmt(struct sof_source __sparse_cache *source, uint32_t buffer_fmt) +int source_set_buffer_fmt(struct sof_source *source, uint32_t buffer_fmt) { source->audio_stream_params->buffer_fmt = buffer_fmt; if (source->ops->on_audio_format_set) @@ -129,7 +129,7 @@ int source_set_buffer_fmt(struct sof_source __sparse_cache *source, uint32_t buf return 0; } -int source_set_underrun(struct sof_source __sparse_cache *source, bool underrun_permitted) +int source_set_underrun(struct sof_source *source, bool underrun_permitted) { source->audio_stream_params->underrun_permitted = underrun_permitted; if (source->ops->on_audio_format_set) @@ -137,19 +137,19 @@ int source_set_underrun(struct sof_source __sparse_cache *source, bool underrun_ return 0; } -size_t source_get_frame_bytes(struct sof_source __sparse_cache *source) +size_t source_get_frame_bytes(struct sof_source *source) { return get_frame_bytes(source_get_frm_fmt(source), source_get_channels(source)); } -size_t source_get_data_frames_available(struct sof_source __sparse_cache *source) +size_t source_get_data_frames_available(struct sof_source *source) { return source_get_data_available(source) / source_get_frame_bytes(source); } -int source_set_params(struct sof_source __sparse_cache *source, +int source_set_params(struct sof_source *source, struct sof_ipc_stream_params *params, bool force_update) { if (source->ops->audio_set_ipc_params) @@ -157,7 +157,7 @@ int source_set_params(struct sof_source __sparse_cache *source, return 0; } -int source_set_alignment_constants(struct sof_source __sparse_cache *source, +int source_set_alignment_constants(struct sof_source *source, const uint32_t byte_align, const uint32_t frame_align_req) { @@ -166,12 +166,12 @@ int source_set_alignment_constants(struct sof_source __sparse_cache *source, return 0; } -void source_set_ibs(struct sof_source __sparse_cache *source, size_t ibs) +void source_set_min_available(struct sof_source *source, size_t min_available) { - source->ibs = ibs; + source->min_available = min_available; } -size_t source_get_ibs(struct sof_source __sparse_cache *source) +size_t source_get_min_available(struct sof_source *source) { - return source->ibs; + return source->min_available; } diff --git a/src/audio/src/CMakeLists.txt b/src/audio/src/CMakeLists.txt index 1884f44ffd6f..2f3d2d561822 100644 --- a/src/audio/src/CMakeLists.txt +++ b/src/audio/src/CMakeLists.txt @@ -1,3 +1,9 @@ # SPDX-License-Identifier: BSD-3-Clause add_local_sources(sof src_generic.c src_hifi2ep.c src_hifi3.c src_hifi4.c src.c) + +if(CONFIG_IPC_MAJOR_3) + add_local_sources(sof src_ipc3.c) +elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof src_ipc4.c) +endif() diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_10_21_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_10_21_2500_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_10_21_2500_5000.h rename to src/audio/src/coef/src_ipc4_int32_10_21_2500_5000.h index 065a4222779b..d1d115ee44a0 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_10_21_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_10_21_2500_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_10_21_2500_5000_fir[480] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_10_21_3455_5000.h b/src/audio/src/coef/src_ipc4_int32_10_21_3455_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_10_21_3455_5000.h rename to src/audio/src/coef/src_ipc4_int32_10_21_3455_5000.h index a3e3c6314cdf..18c85e663503 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_10_21_3455_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_10_21_3455_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_10_21_3455_5000_fir[640] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_10_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_10_21_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_10_21_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_10_21_4535_5000.h index c683105b3be0..44548957393b 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_10_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_10_21_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_10_21_4535_5000_fir[2320] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_10_9_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_10_9_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_10_9_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_10_9_4535_5000.h index ad3b67a7d7ca..25cc0225e3be 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_10_9_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_10_9_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_10_9_4535_5000_fir[1080] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_16_21_4319_5000.h b/src/audio/src/coef/src_ipc4_int32_16_21_4319_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_16_21_4319_5000.h rename to src/audio/src/coef/src_ipc4_int32_16_21_4319_5000.h index 0fdff4295a78..337160da937f 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_16_21_4319_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_16_21_4319_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_16_21_4319_5000_fir[1472] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_16_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_16_21_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_16_21_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_16_21_4535_5000.h index 0a7175e0512e..e3c61b76f695 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_16_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_16_21_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_16_21_4535_5000_fir[2048] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_16_7_4082_5000.h b/src/audio/src/coef/src_ipc4_int32_16_7_4082_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_16_7_4082_5000.h rename to src/audio/src/coef/src_ipc4_int32_16_7_4082_5000.h index 4daec91d4e62..43805148096f 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_16_7_4082_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_16_7_4082_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_16_7_4082_5000_fir[896] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_2268_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_2268_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_2_2268_5000.h index c6406b56dfe8..be58891825a2 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_2268_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_2_2268_5000_fir[36] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_2500_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_2500_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_2_2500_5000.h index 15192f4b0f73..969ee2727761 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_2500_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_2_2500_5000_fir[40] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_2721_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_2721_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_2721_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_2_2721_5000.h index 685fdf20490d..92d3ee21d921 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_2721_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_2721_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_2_2721_5000_fir[44] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_3401_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_3401_5000.h similarity index 97% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_3401_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_2_3401_5000.h index e8573294477c..e3556ed816c1 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_3401_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_3401_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_2_3401_5000_fir[60] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_3887_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_3887_5000.h similarity index 97% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_3887_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_2_3887_5000.h index 9884373e089e..369c861cd598 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_3887_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_3887_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_2_3887_5000_fir[84] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_1_2_4535_5000.h similarity index 98% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_2_4535_5000.h index b06b5a258f83..c5221b373733 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_2_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_2_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_2_4535_5000_fir[192] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_3_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_1_3_2268_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_3_2268_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_3_2268_5000.h index 6da1f70dc034..51c259bc7617 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_3_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_3_2268_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_3_2268_5000_fir[52] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_3_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_1_3_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_3_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_3_4535_5000.h index 8e45ac26f184..1f717019d9ea 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_3_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_3_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_3_4535_5000_fir[260] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_4_1512_5000.h b/src/audio/src/coef/src_ipc4_int32_1_4_1512_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_4_1512_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_4_1512_5000.h index f98ba0f9be7c..fcf3ba774765 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_4_1512_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_4_1512_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_4_1512_5000_fir[52] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_4_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_1_4_2268_5000.h similarity index 97% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_4_2268_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_4_2268_5000.h index 8df1653d8afd..b2f84d157233 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_4_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_4_2268_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_4_2268_5000_fir[60] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_4_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_1_4_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_4_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_4_4535_5000.h index bab9a1df434b..b33697aedb89 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_4_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_4_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_4_4535_5000_fir[332] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_6_1134_5000.h b/src/audio/src/coef/src_ipc4_int32_1_6_1134_5000.h similarity index 97% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_1_6_1134_5000.h rename to src/audio/src/coef/src_ipc4_int32_1_6_1134_5000.h index 7342c541f490..6cc06424de00 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_1_6_1134_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_1_6_1134_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_1_6_1134_5000_fir[68] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_1250_5000.h b/src/audio/src/coef/src_ipc4_int32_20_21_1250_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_1250_5000.h rename to src/audio/src/coef/src_ipc4_int32_20_21_1250_5000.h index 0bda24345ace..b50d11408430 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_1250_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_21_1250_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_20_21_1250_5000_fir[320] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_20_21_2500_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_2500_5000.h rename to src/audio/src/coef/src_ipc4_int32_20_21_2500_5000.h index 1624d3b5d039..5828ac080c60 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_21_2500_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_20_21_2500_5000_fir[560] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_3125_5000.h b/src/audio/src/coef/src_ipc4_int32_20_21_3125_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_3125_5000.h rename to src/audio/src/coef/src_ipc4_int32_20_21_3125_5000.h index 3063a4cb793b..c34349e9e25e 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_3125_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_21_3125_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_20_21_3125_5000_fir[640] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_4167_5000.h b/src/audio/src/coef/src_ipc4_int32_20_21_4167_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_4167_5000.h rename to src/audio/src/coef/src_ipc4_int32_20_21_4167_5000.h index 4b83c9f4e32a..521d2f244aa2 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_4167_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_21_4167_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_20_21_4167_5000_fir[1200] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_20_21_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_20_21_4535_5000.h index 2ebde5a89b7c..0a1677d6f277 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_21_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_20_21_4535_5000_fir[2080] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_7_2976_5000.h b/src/audio/src/coef/src_ipc4_int32_20_7_2976_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_20_7_2976_5000.h rename to src/audio/src/coef/src_ipc4_int32_20_7_2976_5000.h index ffb4fbf6abbf..a16d7b713113 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_20_7_2976_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_20_7_2976_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_20_7_2976_5000_fir[560] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_10_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_21_10_2500_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_10_2500_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_10_2500_5000.h index 0f2abed0ca46..e58dddfb028a 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_10_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_10_2500_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_10_2500_5000_fir[504] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_10_3455_5000.h b/src/audio/src/coef/src_ipc4_int32_21_10_3455_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_10_3455_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_10_3455_5000.h index 9b1bcf324af2..ec2fef3d8cd7 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_10_3455_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_10_3455_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_10_3455_5000_fir[756] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_10_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_10_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_10_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_10_4535_5000.h index 35f53ab94add..f24f635f1ac5 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_10_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_10_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_10_4535_5000_fir[2520] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_16_4319_5000.h b/src/audio/src/coef/src_ipc4_int32_21_16_4319_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_16_4319_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_16_4319_5000.h index a51f25af699b..aab03d7e8db5 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_16_4319_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_16_4319_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_16_4319_5000_fir[1596] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_16_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_16_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_16_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_16_4535_5000.h index 2c82d535369f..924268316718 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_16_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_16_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_16_4535_5000_fir[2436] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_1250_5000.h b/src/audio/src/coef/src_ipc4_int32_21_20_1250_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_1250_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_20_1250_5000.h index 1c952f207c14..a4c08f30e549 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_1250_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_20_1250_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_20_1250_5000_fir[420] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_21_20_2500_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_2500_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_20_2500_5000.h index d5e0479f2c3b..356e9539e193 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_20_2500_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_20_2500_5000_fir[504] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_3125_5000.h b/src/audio/src/coef/src_ipc4_int32_21_20_3125_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_3125_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_20_3125_5000.h index 24d8d957b490..fa68cd2fe43a 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_3125_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_20_3125_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_20_3125_5000_fir[672] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_4167_5000.h b/src/audio/src/coef/src_ipc4_int32_21_20_4167_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_4167_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_20_4167_5000.h index 1511079ef865..e1476e94177a 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_4167_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_20_4167_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_20_4167_5000_fir[1260] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_20_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_20_4535_5000.h index 2a9cc7a4bdaf..603779985693 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_20_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_20_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_20_4535_5000_fir[2268] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_2_3239_5000.h b/src/audio/src/coef/src_ipc4_int32_21_2_3239_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_2_3239_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_2_3239_5000.h index f64f91cda9b6..0dec16ed1041 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_2_3239_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_2_3239_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_2_3239_5000_fir[672] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_32_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_32_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_32_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_32_4535_5000.h index a8f8d8a032c8..445cba531dbd 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_32_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_32_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_32_4535_5000_fir[3612] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_40_2381_5000.h b/src/audio/src/coef/src_ipc4_int32_21_40_2381_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_40_2381_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_40_2381_5000.h index 41bbf11c3a08..654a37afa02a 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_40_2381_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_40_2381_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_40_2381_5000_fir[924] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_40_3968_5000.h b/src/audio/src/coef/src_ipc4_int32_21_40_3968_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_40_3968_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_40_3968_5000.h index 66b78a30d922..63b0727e24c5 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_40_3968_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_40_3968_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_40_3968_5000_fir[1680] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_4_1080_5000.h b/src/audio/src/coef/src_ipc4_int32_21_4_1080_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_4_1080_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_4_1080_5000.h index 6b183e05633f..f22d15eca1bf 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_4_1080_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_4_1080_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_4_1080_5000_fir[336] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_4_3239_5000.h b/src/audio/src/coef/src_ipc4_int32_21_4_3239_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_4_3239_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_4_3239_5000.h index 18b2cb0702e6..6c4d3524e4dc 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_4_3239_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_4_3239_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_4_3239_5000_fir[672] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_5_1728_5000.h b/src/audio/src/coef/src_ipc4_int32_21_5_1728_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_5_1728_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_5_1728_5000.h index 95cdfda00bdf..8d5e1920f9c1 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_5_1728_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_5_1728_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_5_1728_5000_fir[420] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_5_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_5_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_5_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_5_4535_5000.h index ae1996ab8df3..4f4d101eb8e4 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_5_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_5_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_5_4535_5000_fir[2184] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_80_3968_5000.h b/src/audio/src/coef/src_ipc4_int32_21_80_3968_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_80_3968_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_80_3968_5000.h index 4d20797dfb87..e2a51e917c54 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_80_3968_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_80_3968_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_80_3968_5000_fir[3360] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_8_2160_5000.h b/src/audio/src/coef/src_ipc4_int32_21_8_2160_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_8_2160_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_8_2160_5000.h index da333448465a..860c7d00c3b5 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_8_2160_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_8_2160_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_8_2160_5000_fir[420] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_8_3239_5000.h b/src/audio/src/coef/src_ipc4_int32_21_8_3239_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_8_3239_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_8_3239_5000.h index 748d19d4df8e..b6568d54b125 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_8_3239_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_8_3239_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_8_3239_5000_fir[672] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_8_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_21_8_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_21_8_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_21_8_4535_5000.h index 43c10ee4f0b5..d2d853e7af50 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_21_8_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_21_8_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_21_8_4535_5000_fir[2436] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_2_1_2268_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_2268_5000.h rename to src/audio/src/coef/src_ipc4_int32_2_1_2268_5000.h index bce5bd4c6c05..09c3bff531dd 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_1_2268_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_2_1_2268_5000_fir[48] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_2500_5000.h b/src/audio/src/coef/src_ipc4_int32_2_1_2500_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_2500_5000.h rename to src/audio/src/coef/src_ipc4_int32_2_1_2500_5000.h index 021876ed8312..83488544fdf0 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_2500_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_1_2500_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_2_1_2500_5000_fir[40] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_2721_5000.h b/src/audio/src/coef/src_ipc4_int32_2_1_2721_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_2721_5000.h rename to src/audio/src/coef/src_ipc4_int32_2_1_2721_5000.h index 693de6c34e28..20de3bfeb5a3 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_2721_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_1_2721_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_2_1_2721_5000_fir[48] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_3401_5000.h b/src/audio/src/coef/src_ipc4_int32_2_1_3401_5000.h similarity index 97% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_3401_5000.h rename to src/audio/src/coef/src_ipc4_int32_2_1_3401_5000.h index cbf4b40708e5..9dd605d6e52a 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_3401_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_1_3401_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_2_1_3401_5000_fir[72] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_2_1_4535_5000.h similarity index 98% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_2_1_4535_5000.h index ec672dfd00be..732ef897a283 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_1_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_1_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_2_1_4535_5000_fir[240] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_3_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_2_3_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_2_3_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_2_3_4535_5000.h index 513075e3ff2e..79eb8611a146 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_2_3_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_2_3_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_2_3_4535_5000_fir[264] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_32_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_32_21_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_32_21_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_32_21_4535_5000.h index 92ab6b6e75e9..df6eef20aeae 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_32_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_32_21_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_32_21_4535_5000_fir[3840] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_3_1_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_3_1_2268_5000.h similarity index 97% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_3_1_2268_5000.h rename to src/audio/src/coef/src_ipc4_int32_3_1_2268_5000.h index dec77767fb6f..5edce0ac9d2d 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_3_1_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_3_1_2268_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_3_1_2268_5000_fir[72] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_3_1_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_3_1_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_3_1_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_3_1_4535_5000.h index 488055f17f1d..eee1b3a17b92 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_3_1_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_3_1_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_3_1_4535_5000_fir[336] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_3_2_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_3_2_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_3_2_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_3_2_4535_5000.h index e1beb7178778..815f41b7bc60 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_3_2_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_3_2_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_3_2_4535_5000_fir[324] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_3_4_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_3_4_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_3_4_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_3_4_4535_5000.h index 9be2b9b6a3f4..1c4a33a25539 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_3_4_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_3_4_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_3_4_4535_5000_fir[360] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_40_21_2381_5000.h b/src/audio/src/coef/src_ipc4_int32_40_21_2381_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_40_21_2381_5000.h rename to src/audio/src/coef/src_ipc4_int32_40_21_2381_5000.h index 757fee8933dc..cec8b5f212fe 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_40_21_2381_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_40_21_2381_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_40_21_2381_5000_fir[960] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_40_21_2976_5000.h b/src/audio/src/coef/src_ipc4_int32_40_21_2976_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_40_21_2976_5000.h rename to src/audio/src/coef/src_ipc4_int32_40_21_2976_5000.h index 9fbb7a8f57de..df32a455a27c 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_40_21_2976_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_40_21_2976_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_40_21_2976_5000_fir[1120] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_40_21_3968_5000.h b/src/audio/src/coef/src_ipc4_int32_40_21_3968_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_40_21_3968_5000.h rename to src/audio/src/coef/src_ipc4_int32_40_21_3968_5000.h index 021b6075ac39..31d57d112ddc 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_40_21_3968_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_40_21_3968_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_40_21_3968_5000_fir[2080] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_40_7_2976_5000.h b/src/audio/src/coef/src_ipc4_int32_40_7_2976_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_40_7_2976_5000.h rename to src/audio/src/coef/src_ipc4_int32_40_7_2976_5000.h index 5058110df7be..da0467c3c147 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_40_7_2976_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_40_7_2976_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_40_7_2976_5000_fir[1120] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_1134_5000.h b/src/audio/src/coef/src_ipc4_int32_4_1_1134_5000.h similarity index 97% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_1134_5000.h rename to src/audio/src/coef/src_ipc4_int32_4_1_1134_5000.h index 45dfaa500a92..a6698dac6739 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_1134_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_1_1134_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_4_1_1134_5000_fir[64] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_1512_5000.h b/src/audio/src/coef/src_ipc4_int32_4_1_1512_5000.h similarity index 97% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_1512_5000.h rename to src/audio/src/coef/src_ipc4_int32_4_1_1512_5000.h index 67a6f4e65363..0f5b9d267505 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_1512_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_1_1512_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_4_1_1512_5000_fir[64] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_2268_5000.h b/src/audio/src/coef/src_ipc4_int32_4_1_2268_5000.h similarity index 97% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_2268_5000.h rename to src/audio/src/coef/src_ipc4_int32_4_1_2268_5000.h index fa992ea0fc89..2caa64654899 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_2268_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_1_2268_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_4_1_2268_5000_fir[80] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_4_1_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_4_1_4535_5000.h index db0a1f73fbae..efb70988f749 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_1_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_1_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_4_1_4535_5000_fir[416] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_21_1080_5000.h b/src/audio/src/coef/src_ipc4_int32_4_21_1080_5000.h similarity index 98% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_4_21_1080_5000.h rename to src/audio/src/coef/src_ipc4_int32_4_21_1080_5000.h index 85e550434456..7b5a30d154b2 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_21_1080_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_21_1080_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_4_21_1080_5000_fir[224] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_21_3239_5000.h b/src/audio/src/coef/src_ipc4_int32_4_21_3239_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_4_21_3239_5000.h rename to src/audio/src/coef/src_ipc4_int32_4_21_3239_5000.h index 06b3e92c97da..1b876606df53 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_21_3239_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_21_3239_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_4_21_3239_5000_fir[512] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_3_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_4_3_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_4_3_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_4_3_4535_5000.h index 472e6cb9b2ce..84ab1b359e7b 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_4_3_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_4_3_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_4_3_4535_5000_fir[432] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_5_21_1728_5000.h b/src/audio/src/coef/src_ipc4_int32_5_21_1728_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_5_21_1728_5000.h rename to src/audio/src/coef/src_ipc4_int32_5_21_1728_5000.h index dc6d468dd22f..226e1a6216af 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_5_21_1728_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_5_21_1728_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_5_21_1728_5000_fir[320] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_5_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_5_21_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_5_21_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_5_21_4535_5000.h index e7b58e37f993..290d409fd00d 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_5_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_5_21_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_5_21_4535_5000_fir[1740] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_5_7_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_5_7_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_5_7_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_5_7_4535_5000.h index 271b6d9e8e28..f8314556a665 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_5_7_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_5_7_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_5_7_4535_5000_fir[680] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_6_1_1134_5000.h b/src/audio/src/coef/src_ipc4_int32_6_1_1134_5000.h similarity index 97% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_6_1_1134_5000.h rename to src/audio/src/coef/src_ipc4_int32_6_1_1134_5000.h index 006678f426a8..ddf6e0c51bde 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_6_1_1134_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_6_1_1134_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_6_1_1134_5000_fir[96] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_3_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_7_3_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_7_3_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_7_3_4535_5000.h index 33a58e2228ec..1b40753e77d7 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_3_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_3_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_7_3_4535_5000_fir[728] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_5_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_7_5_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_7_5_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_7_5_4535_5000.h index 3704f52287df..0e7ecf543842 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_5_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_5_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_7_5_4535_5000_fir[812] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_1361_5000.h b/src/audio/src/coef/src_ipc4_int32_7_8_1361_5000.h similarity index 98% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_1361_5000.h rename to src/audio/src/coef/src_ipc4_int32_7_8_1361_5000.h index b21195f8e7d8..d5a31e8fa3d4 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_1361_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_8_1361_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_7_8_1361_5000_fir[140] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_2468_5000.h b/src/audio/src/coef/src_ipc4_int32_7_8_2468_5000.h similarity index 98% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_2468_5000.h rename to src/audio/src/coef/src_ipc4_int32_7_8_2468_5000.h index 5dc8df90db50..c68546b258d9 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_2468_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_8_2468_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_7_8_2468_5000_fir[196] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_2721_5000.h b/src/audio/src/coef/src_ipc4_int32_7_8_2721_5000.h similarity index 98% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_2721_5000.h rename to src/audio/src/coef/src_ipc4_int32_7_8_2721_5000.h index 3bbf0802f8ed..3c7c02ecbc3d 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_2721_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_8_2721_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_7_8_2721_5000_fir[224] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_7_8_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_7_8_4535_5000.h index 05b14977a701..3037d3dd258e 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_7_8_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_7_8_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_7_8_4535_5000_fir[840] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_21_2160_5000.h b/src/audio/src/coef/src_ipc4_int32_8_21_2160_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_8_21_2160_5000.h rename to src/audio/src/coef/src_ipc4_int32_8_21_2160_5000.h index 09735d1a5eff..c687495d433d 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_21_2160_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_21_2160_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_8_21_2160_5000_fir[384] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_21_3239_5000.h b/src/audio/src/coef/src_ipc4_int32_8_21_3239_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_8_21_3239_5000.h rename to src/audio/src/coef/src_ipc4_int32_8_21_3239_5000.h index 34df502e0431..4bc6f351e350 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_21_3239_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_21_3239_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_8_21_3239_5000_fir[544] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_21_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_8_21_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_8_21_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_8_21_4535_5000.h index 1e923f32b334..d61a7d09d215 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_21_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_21_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_8_21_4535_5000_fir[1984] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_1361_5000.h b/src/audio/src/coef/src_ipc4_int32_8_7_1361_5000.h similarity index 98% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_1361_5000.h rename to src/audio/src/coef/src_ipc4_int32_8_7_1361_5000.h index 2ac3837f35a3..a0746b412434 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_1361_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_7_1361_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_8_7_1361_5000_fir[160] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_2468_5000.h b/src/audio/src/coef/src_ipc4_int32_8_7_2468_5000.h similarity index 98% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_2468_5000.h rename to src/audio/src/coef/src_ipc4_int32_8_7_2468_5000.h index 9e04cea51d53..01b479c08705 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_2468_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_7_2468_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_8_7_2468_5000_fir[192] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_2721_5000.h b/src/audio/src/coef/src_ipc4_int32_8_7_2721_5000.h similarity index 98% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_2721_5000.h rename to src/audio/src/coef/src_ipc4_int32_8_7_2721_5000.h index 40ff2e3b153e..921abdb6b94d 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_2721_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_7_2721_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_8_7_2721_5000_fir[192] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_4082_5000.h b/src/audio/src/coef/src_ipc4_int32_8_7_4082_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_4082_5000.h rename to src/audio/src/coef/src_ipc4_int32_8_7_4082_5000.h index 6d58cd3f2a4c..7a5b0ec6b469 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_4082_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_7_4082_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_8_7_4082_5000_fir[480] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_4535_5000.h b/src/audio/src/coef/src_ipc4_int32_8_7_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_4535_5000.h rename to src/audio/src/coef/src_ipc4_int32_8_7_4535_5000.h index b5d8f6e0dec5..51b0c1dc13df 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_8_7_4535_5000.h +++ b/src/audio/src/coef/src_ipc4_int32_8_7_4535_5000.h @@ -5,7 +5,7 @@ */ /** \cond GENERATED_BY_TOOLS_TUNE_SRC */ -#include +#include "../src.h" #include const int32_t src_int32_8_7_4535_5000_fir[896] = { diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_define.h b/src/audio/src/coef/src_ipc4_int32_define.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_define.h rename to src/audio/src/coef/src_ipc4_int32_define.h diff --git a/src/include/sof/audio/coefficients/src/src_ipc4_int32_table.h b/src/audio/src/coef/src_ipc4_int32_table.h similarity index 60% rename from src/include/sof/audio/coefficients/src/src_ipc4_int32_table.h rename to src/audio/src/coef/src_ipc4_int32_table.h index 1530b9f9d442..23a470ad7025 100644 --- a/src/include/sof/audio/coefficients/src/src_ipc4_int32_table.h +++ b/src/audio/src/coef/src_ipc4_int32_table.h @@ -10,94 +10,94 @@ #define __SOF_AUDIO_COEFFICIENTS_SRC_SRC_IPC4_INT32_TABLE_H__ /* SRC conversions */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "src_ipc4_int32_1_2_2268_5000.h" +#include "src_ipc4_int32_1_2_2500_5000.h" +#include "src_ipc4_int32_1_2_2721_5000.h" +#include "src_ipc4_int32_1_2_3401_5000.h" +#include "src_ipc4_int32_1_2_3887_5000.h" +#include "src_ipc4_int32_1_2_4535_5000.h" +#include "src_ipc4_int32_1_3_2268_5000.h" +#include "src_ipc4_int32_1_3_4535_5000.h" +#include "src_ipc4_int32_1_4_1512_5000.h" +#include "src_ipc4_int32_1_4_2268_5000.h" +#include "src_ipc4_int32_1_4_4535_5000.h" +#include "src_ipc4_int32_1_6_1134_5000.h" +#include "src_ipc4_int32_2_1_2268_5000.h" +#include "src_ipc4_int32_2_1_2500_5000.h" +#include "src_ipc4_int32_2_1_2721_5000.h" +#include "src_ipc4_int32_2_1_3401_5000.h" +#include "src_ipc4_int32_2_1_4535_5000.h" +#include "src_ipc4_int32_2_3_4535_5000.h" +#include "src_ipc4_int32_3_1_2268_5000.h" +#include "src_ipc4_int32_3_1_4535_5000.h" +#include "src_ipc4_int32_3_2_4535_5000.h" +#include "src_ipc4_int32_3_4_4535_5000.h" +#include "src_ipc4_int32_4_1_1134_5000.h" +#include "src_ipc4_int32_4_1_1512_5000.h" +#include "src_ipc4_int32_4_1_2268_5000.h" +#include "src_ipc4_int32_4_1_4535_5000.h" +#include "src_ipc4_int32_4_3_4535_5000.h" +#include "src_ipc4_int32_4_21_1080_5000.h" +#include "src_ipc4_int32_4_21_3239_5000.h" +#include "src_ipc4_int32_5_7_4535_5000.h" +#include "src_ipc4_int32_5_21_1728_5000.h" +#include "src_ipc4_int32_5_21_4535_5000.h" +#include "src_ipc4_int32_6_1_1134_5000.h" +#include "src_ipc4_int32_7_3_4535_5000.h" +#include "src_ipc4_int32_7_5_4535_5000.h" +#include "src_ipc4_int32_7_8_1361_5000.h" +#include "src_ipc4_int32_7_8_2468_5000.h" +#include "src_ipc4_int32_7_8_2721_5000.h" +#include "src_ipc4_int32_7_8_4535_5000.h" +#include "src_ipc4_int32_8_7_1361_5000.h" +#include "src_ipc4_int32_8_7_2468_5000.h" +#include "src_ipc4_int32_8_7_2721_5000.h" +#include "src_ipc4_int32_8_7_4082_5000.h" +#include "src_ipc4_int32_8_7_4535_5000.h" +#include "src_ipc4_int32_8_21_2160_5000.h" +#include "src_ipc4_int32_8_21_3239_5000.h" +#include "src_ipc4_int32_8_21_4535_5000.h" +#include "src_ipc4_int32_10_9_4535_5000.h" +#include "src_ipc4_int32_10_21_2500_5000.h" +#include "src_ipc4_int32_10_21_3455_5000.h" +#include "src_ipc4_int32_10_21_4535_5000.h" +#include "src_ipc4_int32_16_7_4082_5000.h" +#include "src_ipc4_int32_16_21_4319_5000.h" +#include "src_ipc4_int32_16_21_4535_5000.h" +#include "src_ipc4_int32_20_7_2976_5000.h" +#include "src_ipc4_int32_20_21_1250_5000.h" +#include "src_ipc4_int32_20_21_2500_5000.h" +#include "src_ipc4_int32_20_21_3125_5000.h" +#include "src_ipc4_int32_20_21_4167_5000.h" +#include "src_ipc4_int32_20_21_4535_5000.h" +#include "src_ipc4_int32_21_2_3239_5000.h" +#include "src_ipc4_int32_21_4_1080_5000.h" +#include "src_ipc4_int32_21_4_3239_5000.h" +#include "src_ipc4_int32_21_5_1728_5000.h" +#include "src_ipc4_int32_21_5_4535_5000.h" +#include "src_ipc4_int32_21_8_2160_5000.h" +#include "src_ipc4_int32_21_8_3239_5000.h" +#include "src_ipc4_int32_21_8_4535_5000.h" +#include "src_ipc4_int32_21_10_2500_5000.h" +#include "src_ipc4_int32_21_10_3455_5000.h" +#include "src_ipc4_int32_21_10_4535_5000.h" +#include "src_ipc4_int32_21_16_4319_5000.h" +#include "src_ipc4_int32_21_16_4535_5000.h" +#include "src_ipc4_int32_21_20_1250_5000.h" +#include "src_ipc4_int32_21_20_2500_5000.h" +#include "src_ipc4_int32_21_20_3125_5000.h" +#include "src_ipc4_int32_21_20_4167_5000.h" +#include "src_ipc4_int32_21_20_4535_5000.h" +#include "src_ipc4_int32_21_32_4535_5000.h" +#include "src_ipc4_int32_21_40_2381_5000.h" +#include "src_ipc4_int32_21_40_3968_5000.h" +#include "src_ipc4_int32_21_80_3968_5000.h" +#include "src_ipc4_int32_32_21_4535_5000.h" +#include "src_ipc4_int32_40_7_2976_5000.h" +#include "src_ipc4_int32_40_21_2381_5000.h" +#include "src_ipc4_int32_40_21_2976_5000.h" +#include "src_ipc4_int32_40_21_3968_5000.h" +#include "../src.h" #include /* SRC table */ diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_1_2_2268_5000.h b/src/audio/src/coef/src_small_int32_1_2_2268_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_small_int32_1_2_2268_5000.h rename to src/audio/src/coef/src_small_int32_1_2_2268_5000.h index 303d9f2520fc..e71ef83a079e 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_1_2_2268_5000.h +++ b/src/audio/src/coef/src_small_int32_1_2_2268_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_1_2_2268_5000_fir[40] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_1_2_4535_5000.h b/src/audio/src/coef/src_small_int32_1_2_4535_5000.h similarity index 98% rename from src/include/sof/audio/coefficients/src/src_small_int32_1_2_4535_5000.h rename to src/audio/src/coef/src_small_int32_1_2_4535_5000.h index 928e3448d58a..9a207cfc4a78 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_1_2_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_1_2_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_1_2_4535_5000_fir[200] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_1_3_2268_5000.h b/src/audio/src/coef/src_small_int32_1_3_2268_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_small_int32_1_3_2268_5000.h rename to src/audio/src/coef/src_small_int32_1_3_2268_5000.h index f85f893ff16b..22114da5f961 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_1_3_2268_5000.h +++ b/src/audio/src/coef/src_small_int32_1_3_2268_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_1_3_2268_5000_fir[56] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_1_3_4535_5000.h b/src/audio/src/coef/src_small_int32_1_3_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_1_3_4535_5000.h rename to src/audio/src/coef/src_small_int32_1_3_4535_5000.h index 972926179ed2..40d2c1d57b00 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_1_3_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_1_3_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_1_3_4535_5000_fir[268] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_20_21_4167_5000.h b/src/audio/src/coef/src_small_int32_20_21_4167_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_20_21_4167_5000.h rename to src/audio/src/coef/src_small_int32_20_21_4167_5000.h index 4d674379a2f3..5ba424809efe 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_20_21_4167_5000.h +++ b/src/audio/src/coef/src_small_int32_20_21_4167_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_20_21_4167_5000_fir[1120] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_21_20_4167_5000.h b/src/audio/src/coef/src_small_int32_21_20_4167_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_21_20_4167_5000.h rename to src/audio/src/coef/src_small_int32_21_20_4167_5000.h index e952c70e4a01..5280f529fb30 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_21_20_4167_5000.h +++ b/src/audio/src/coef/src_small_int32_21_20_4167_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_21_20_4167_5000_fir[1092] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_2_1_2268_5000.h b/src/audio/src/coef/src_small_int32_2_1_2268_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_small_int32_2_1_2268_5000.h rename to src/audio/src/coef/src_small_int32_2_1_2268_5000.h index 494c2e75676a..3b727a0d782b 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_2_1_2268_5000.h +++ b/src/audio/src/coef/src_small_int32_2_1_2268_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_2_1_2268_5000_fir[40] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_2_1_4535_5000.h b/src/audio/src/coef/src_small_int32_2_1_4535_5000.h similarity index 98% rename from src/include/sof/audio/coefficients/src/src_small_int32_2_1_4535_5000.h rename to src/audio/src/coef/src_small_int32_2_1_4535_5000.h index 200de76bf2b1..4d2d75ec328b 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_2_1_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_2_1_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_2_1_4535_5000_fir[200] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_2_3_4535_5000.h b/src/audio/src/coef/src_small_int32_2_3_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_2_3_4535_5000.h rename to src/audio/src/coef/src_small_int32_2_3_4535_5000.h index 206f0a03a635..b6b464f6b4bf 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_2_3_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_2_3_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_2_3_4535_5000_fir[272] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_3_1_2268_5000.h b/src/audio/src/coef/src_small_int32_3_1_2268_5000.h similarity index 96% rename from src/include/sof/audio/coefficients/src/src_small_int32_3_1_2268_5000.h rename to src/audio/src/coef/src_small_int32_3_1_2268_5000.h index e6f4bc6216ea..8b79acf94a6e 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_3_1_2268_5000.h +++ b/src/audio/src/coef/src_small_int32_3_1_2268_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_3_1_2268_5000_fir[60] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_3_1_4535_5000.h b/src/audio/src/coef/src_small_int32_3_1_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_3_1_4535_5000.h rename to src/audio/src/coef/src_small_int32_3_1_4535_5000.h index 306409d4d04e..33ebefc04653 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_3_1_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_3_1_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_3_1_4535_5000_fir[276] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_3_2_4535_5000.h b/src/audio/src/coef/src_small_int32_3_2_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_3_2_4535_5000.h rename to src/audio/src/coef/src_small_int32_3_2_4535_5000.h index 42f56dd77c6c..668947ceb7e6 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_3_2_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_3_2_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_3_2_4535_5000_fir[276] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_3_4_4535_5000.h b/src/audio/src/coef/src_small_int32_3_4_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_3_4_4535_5000.h rename to src/audio/src/coef/src_small_int32_3_4_4535_5000.h index f930daf54992..b6527580c8f2 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_3_4_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_3_4_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_3_4_4535_5000_fir[348] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_4_3_4535_5000.h b/src/audio/src/coef/src_small_int32_4_3_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_4_3_4535_5000.h rename to src/audio/src/coef/src_small_int32_4_3_4535_5000.h index 3505f63d196b..5266ca1448c9 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_4_3_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_4_3_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_4_3_4535_5000_fir[352] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_4_5_4535_5000.h b/src/audio/src/coef/src_small_int32_4_5_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_4_5_4535_5000.h rename to src/audio/src/coef/src_small_int32_4_5_4535_5000.h index 9af3feb400ec..4eca45e3d5f8 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_4_5_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_4_5_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_4_5_4535_5000_fir[448] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_5_4_4535_5000.h b/src/audio/src/coef/src_small_int32_5_4_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_5_4_4535_5000.h rename to src/audio/src/coef/src_small_int32_5_4_4535_5000.h index d608c8f5c0e1..79240798db05 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_5_4_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_5_4_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_5_4_4535_5000_fir[440] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_5_6_4354_5000.h b/src/audio/src/coef/src_small_int32_5_6_4354_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_5_6_4354_5000.h rename to src/audio/src/coef/src_small_int32_5_6_4354_5000.h index 51a71506d803..a34c3d2d7c1f 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_5_6_4354_5000.h +++ b/src/audio/src/coef/src_small_int32_5_6_4354_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_5_6_4354_5000_fir[380] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_6_5_4354_5000.h b/src/audio/src/coef/src_small_int32_6_5_4354_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_6_5_4354_5000.h rename to src/audio/src/coef/src_small_int32_6_5_4354_5000.h index 3ebd2e13b4c3..1cb91867ff13 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_6_5_4354_5000.h +++ b/src/audio/src/coef/src_small_int32_6_5_4354_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_6_5_4354_5000_fir[384] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_7_8_4535_5000.h b/src/audio/src/coef/src_small_int32_7_8_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_7_8_4535_5000.h rename to src/audio/src/coef/src_small_int32_7_8_4535_5000.h index 5dd8e49e4e59..537a4e1d63ca 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_7_8_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_7_8_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_7_8_4535_5000_fir[644] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_8_7_4535_5000.h b/src/audio/src/coef/src_small_int32_8_7_4535_5000.h similarity index 99% rename from src/include/sof/audio/coefficients/src/src_small_int32_8_7_4535_5000.h rename to src/audio/src/coef/src_small_int32_8_7_4535_5000.h index ed965a4e762d..fda7bb6c4e41 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_8_7_4535_5000.h +++ b/src/audio/src/coef/src_small_int32_8_7_4535_5000.h @@ -4,7 +4,7 @@ * */ -#include +#include "../src.h" #include const int32_t src_int32_8_7_4535_5000_fir[640] = { diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_define.h b/src/audio/src/coef/src_small_int32_define.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_small_int32_define.h rename to src/audio/src/coef/src_small_int32_define.h diff --git a/src/include/sof/audio/coefficients/src/src_small_int32_table.h b/src/audio/src/coef/src_small_int32_table.h similarity index 68% rename from src/include/sof/audio/coefficients/src/src_small_int32_table.h rename to src/audio/src/coef/src_small_int32_table.h index 57af8877185c..2fd22a6372f3 100644 --- a/src/include/sof/audio/coefficients/src/src_small_int32_table.h +++ b/src/audio/src/coef/src_small_int32_table.h @@ -8,27 +8,27 @@ #define __SOF_AUDIO_COEFFICIENTS_SRC_SRC_SMALL_INT32_TABLE_H__ /* SRC conversions */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "src_small_int32_1_2_2268_5000.h" +#include "src_small_int32_1_2_4535_5000.h" +#include "src_small_int32_1_3_2268_5000.h" +#include "src_small_int32_1_3_4535_5000.h" +#include "src_small_int32_2_1_2268_5000.h" +#include "src_small_int32_2_1_4535_5000.h" +#include "src_small_int32_2_3_4535_5000.h" +#include "src_small_int32_3_1_2268_5000.h" +#include "src_small_int32_3_1_4535_5000.h" +#include "src_small_int32_3_2_4535_5000.h" +#include "src_small_int32_3_4_4535_5000.h" +#include "src_small_int32_4_3_4535_5000.h" +#include "src_small_int32_4_5_4535_5000.h" +#include "src_small_int32_5_4_4535_5000.h" +#include "src_small_int32_5_6_4354_5000.h" +#include "src_small_int32_6_5_4354_5000.h" +#include "src_small_int32_7_8_4535_5000.h" +#include "src_small_int32_8_7_4535_5000.h" +#include "src_small_int32_20_21_4167_5000.h" +#include "src_small_int32_21_20_4167_5000.h" +#include "../src.h" #include /* SRC table */ diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_10_21_4535_5000.h b/src/audio/src/coef/src_std_int32_10_21_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_10_21_4535_5000.h rename to src/audio/src/coef/src_std_int32_10_21_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_1_2_2268_5000.h b/src/audio/src/coef/src_std_int32_1_2_2268_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_1_2_2268_5000.h rename to src/audio/src/coef/src_std_int32_1_2_2268_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_1_2_4535_5000.h b/src/audio/src/coef/src_std_int32_1_2_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_1_2_4535_5000.h rename to src/audio/src/coef/src_std_int32_1_2_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_1_3_2268_5000.h b/src/audio/src/coef/src_std_int32_1_3_2268_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_1_3_2268_5000.h rename to src/audio/src/coef/src_std_int32_1_3_2268_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_1_3_4535_5000.h b/src/audio/src/coef/src_std_int32_1_3_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_1_3_4535_5000.h rename to src/audio/src/coef/src_std_int32_1_3_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_20_21_4167_5000.h b/src/audio/src/coef/src_std_int32_20_21_4167_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_20_21_4167_5000.h rename to src/audio/src/coef/src_std_int32_20_21_4167_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_20_7_2976_5000.h b/src/audio/src/coef/src_std_int32_20_7_2976_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_20_7_2976_5000.h rename to src/audio/src/coef/src_std_int32_20_7_2976_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_21_20_4167_5000.h b/src/audio/src/coef/src_std_int32_21_20_4167_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_21_20_4167_5000.h rename to src/audio/src/coef/src_std_int32_21_20_4167_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_21_40_3968_5000.h b/src/audio/src/coef/src_std_int32_21_40_3968_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_21_40_3968_5000.h rename to src/audio/src/coef/src_std_int32_21_40_3968_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_21_80_3968_5000.h b/src/audio/src/coef/src_std_int32_21_80_3968_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_21_80_3968_5000.h rename to src/audio/src/coef/src_std_int32_21_80_3968_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_2_1_2268_5000.h b/src/audio/src/coef/src_std_int32_2_1_2268_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_2_1_2268_5000.h rename to src/audio/src/coef/src_std_int32_2_1_2268_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_2_1_4535_5000.h b/src/audio/src/coef/src_std_int32_2_1_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_2_1_4535_5000.h rename to src/audio/src/coef/src_std_int32_2_1_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_2_3_4535_5000.h b/src/audio/src/coef/src_std_int32_2_3_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_2_3_4535_5000.h rename to src/audio/src/coef/src_std_int32_2_3_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_32_21_4535_5000.h b/src/audio/src/coef/src_std_int32_32_21_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_32_21_4535_5000.h rename to src/audio/src/coef/src_std_int32_32_21_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_3_1_2268_5000.h b/src/audio/src/coef/src_std_int32_3_1_2268_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_3_1_2268_5000.h rename to src/audio/src/coef/src_std_int32_3_1_2268_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_3_1_4535_5000.h b/src/audio/src/coef/src_std_int32_3_1_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_3_1_4535_5000.h rename to src/audio/src/coef/src_std_int32_3_1_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_3_2_4535_5000.h b/src/audio/src/coef/src_std_int32_3_2_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_3_2_4535_5000.h rename to src/audio/src/coef/src_std_int32_3_2_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_3_4_4535_5000.h b/src/audio/src/coef/src_std_int32_3_4_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_3_4_4535_5000.h rename to src/audio/src/coef/src_std_int32_3_4_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_40_21_3968_5000.h b/src/audio/src/coef/src_std_int32_40_21_3968_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_40_21_3968_5000.h rename to src/audio/src/coef/src_std_int32_40_21_3968_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_4_3_4535_5000.h b/src/audio/src/coef/src_std_int32_4_3_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_4_3_4535_5000.h rename to src/audio/src/coef/src_std_int32_4_3_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_4_5_4535_5000.h b/src/audio/src/coef/src_std_int32_4_5_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_4_5_4535_5000.h rename to src/audio/src/coef/src_std_int32_4_5_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_5_4_4535_5000.h b/src/audio/src/coef/src_std_int32_5_4_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_5_4_4535_5000.h rename to src/audio/src/coef/src_std_int32_5_4_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_5_6_4354_5000.h b/src/audio/src/coef/src_std_int32_5_6_4354_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_5_6_4354_5000.h rename to src/audio/src/coef/src_std_int32_5_6_4354_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_5_7_4535_5000.h b/src/audio/src/coef/src_std_int32_5_7_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_5_7_4535_5000.h rename to src/audio/src/coef/src_std_int32_5_7_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_6_5_4354_5000.h b/src/audio/src/coef/src_std_int32_6_5_4354_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_6_5_4354_5000.h rename to src/audio/src/coef/src_std_int32_6_5_4354_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_7_8_4535_5000.h b/src/audio/src/coef/src_std_int32_7_8_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_7_8_4535_5000.h rename to src/audio/src/coef/src_std_int32_7_8_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_8_21_3239_5000.h b/src/audio/src/coef/src_std_int32_8_21_3239_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_8_21_3239_5000.h rename to src/audio/src/coef/src_std_int32_8_21_3239_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_8_7_2468_5000.h b/src/audio/src/coef/src_std_int32_8_7_2468_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_8_7_2468_5000.h rename to src/audio/src/coef/src_std_int32_8_7_2468_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_8_7_4535_5000.h b/src/audio/src/coef/src_std_int32_8_7_4535_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_8_7_4535_5000.h rename to src/audio/src/coef/src_std_int32_8_7_4535_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_define.h b/src/audio/src/coef/src_std_int32_define.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_std_int32_define.h rename to src/audio/src/coef/src_std_int32_define.h diff --git a/src/include/sof/audio/coefficients/src/src_std_int32_table.h b/src/audio/src/coef/src_std_int32_table.h similarity index 79% rename from src/include/sof/audio/coefficients/src/src_std_int32_table.h rename to src/audio/src/coef/src_std_int32_table.h index 06a7965a382c..7905e3a88745 100644 --- a/src/include/sof/audio/coefficients/src/src_std_int32_table.h +++ b/src/audio/src/coef/src_std_int32_table.h @@ -9,36 +9,36 @@ #define __SOF_AUDIO_COEFFICIENTS_SRC_SRC_STD_INT32_TABLE_H__ /* SRC conversions */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "src_std_int32_1_2_2268_5000.h" +#include "src_std_int32_1_2_4535_5000.h" +#include "src_std_int32_1_3_2268_5000.h" +#include "src_std_int32_1_3_4535_5000.h" +#include "src_std_int32_2_1_2268_5000.h" +#include "src_std_int32_2_1_4535_5000.h" +#include "src_std_int32_2_3_4535_5000.h" +#include "src_std_int32_3_1_2268_5000.h" +#include "src_std_int32_3_1_4535_5000.h" +#include "src_std_int32_3_2_4535_5000.h" +#include "src_std_int32_3_4_4535_5000.h" +#include "src_std_int32_4_3_4535_5000.h" +#include "src_std_int32_4_5_4535_5000.h" +#include "src_std_int32_5_4_4535_5000.h" +#include "src_std_int32_5_6_4354_5000.h" +#include "src_std_int32_5_7_4535_5000.h" +#include "src_std_int32_6_5_4354_5000.h" +#include "src_std_int32_7_8_4535_5000.h" +#include "src_std_int32_8_7_2468_5000.h" +#include "src_std_int32_8_7_4535_5000.h" +#include "src_std_int32_8_21_3239_5000.h" +#include "src_std_int32_10_21_4535_5000.h" +#include "src_std_int32_20_7_2976_5000.h" +#include "src_std_int32_20_21_4167_5000.h" +#include "src_std_int32_21_20_4167_5000.h" +#include "src_std_int32_21_40_3968_5000.h" +#include "src_std_int32_21_80_3968_5000.h" +#include "src_std_int32_32_21_4535_5000.h" +#include "src_std_int32_40_21_3968_5000.h" +#include "../src.h" #include /* SRC table */ diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_1_2_1814_5000.h b/src/audio/src/coef/src_tiny_int16_1_2_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_1_2_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_1_2_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_1_3_1814_5000.h b/src/audio/src/coef/src_tiny_int16_1_3_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_1_3_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_1_3_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_1_6_1814_5000.h b/src/audio/src/coef/src_tiny_int16_1_6_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_1_6_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_1_6_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_20_21_1667_5000.h b/src/audio/src/coef/src_tiny_int16_20_21_1667_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_20_21_1667_5000.h rename to src/audio/src/coef/src_tiny_int16_20_21_1667_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_21_20_1667_5000.h b/src/audio/src/coef/src_tiny_int16_21_20_1667_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_21_20_1667_5000.h rename to src/audio/src/coef/src_tiny_int16_21_20_1667_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_24_25_1814_5000.h b/src/audio/src/coef/src_tiny_int16_24_25_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_24_25_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_24_25_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_25_24_1814_5000.h b/src/audio/src/coef/src_tiny_int16_25_24_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_25_24_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_25_24_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_2_1_1814_5000.h b/src/audio/src/coef/src_tiny_int16_2_1_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_2_1_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_2_1_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_2_3_1814_5000.h b/src/audio/src/coef/src_tiny_int16_2_3_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_2_3_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_2_3_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_3_1_1814_5000.h b/src/audio/src/coef/src_tiny_int16_3_1_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_3_1_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_3_1_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_3_2_1814_5000.h b/src/audio/src/coef/src_tiny_int16_3_2_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_3_2_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_3_2_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_6_1_1814_5000.h b/src/audio/src/coef/src_tiny_int16_6_1_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_6_1_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_6_1_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_7_8_1814_5000.h b/src/audio/src/coef/src_tiny_int16_7_8_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_7_8_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_7_8_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_8_7_1814_5000.h b/src/audio/src/coef/src_tiny_int16_8_7_1814_5000.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_8_7_1814_5000.h rename to src/audio/src/coef/src_tiny_int16_8_7_1814_5000.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_define.h b/src/audio/src/coef/src_tiny_int16_define.h similarity index 100% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_define.h rename to src/audio/src/coef/src_tiny_int16_define.h diff --git a/src/include/sof/audio/coefficients/src/src_tiny_int16_table.h b/src/audio/src/coef/src_tiny_int16_table.h similarity index 75% rename from src/include/sof/audio/coefficients/src/src_tiny_int16_table.h rename to src/audio/src/coef/src_tiny_int16_table.h index 4da547757cb5..f4b7b790ca24 100644 --- a/src/include/sof/audio/coefficients/src/src_tiny_int16_table.h +++ b/src/audio/src/coef/src_tiny_int16_table.h @@ -9,21 +9,21 @@ #define __SOF_AUDIO_COEFFICIENTS_SRC_SRC_TINY_INT16_TABLE_H__ /* SRC conversions */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "src_tiny_int16_1_2_1814_5000.h" +#include "src_tiny_int16_1_3_1814_5000.h" +#include "src_tiny_int16_1_6_1814_5000.h" +#include "src_tiny_int16_2_1_1814_5000.h" +#include "src_tiny_int16_2_3_1814_5000.h" +#include "src_tiny_int16_3_1_1814_5000.h" +#include "src_tiny_int16_3_2_1814_5000.h" +#include "src_tiny_int16_6_1_1814_5000.h" +#include "src_tiny_int16_7_8_1814_5000.h" +#include "src_tiny_int16_8_7_1814_5000.h" +#include "src_tiny_int16_20_21_1667_5000.h" +#include "src_tiny_int16_21_20_1667_5000.h" +#include "src_tiny_int16_24_25_1814_5000.h" +#include "src_tiny_int16_25_24_1814_5000.h" +#include "../src.h" #include /* SRC table */ diff --git a/src/audio/src/src.c b/src/audio/src/src.c index 82501728c59c..d1966efe5e4e 100644 --- a/src/audio/src/src.c +++ b/src/audio/src/src.c @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include #include #include @@ -40,18 +38,21 @@ #include #include +#include "src.h" +#include "src_config.h" + #if SRC_SHORT || CONFIG_COMP_SRC_TINY -#include -#include +#include "coef/src_tiny_int16_define.h" +#include "coef/src_tiny_int16_table.h" #elif CONFIG_COMP_SRC_SMALL -#include -#include +#include "coef/src_small_int32_define.h" +#include "coef/src_small_int32_table.h" #elif CONFIG_COMP_SRC_STD -#include -#include +#include "coef/src_std_int32_define.h" +#include "coef/src_std_int32_table.h" #elif CONFIG_COMP_SRC_IPC4_FULL_MATRIX -#include -#include +#include "coef/src_ipc4_int32_define.h" +#include "coef/src_ipc4_int32_table.h" #else #error "No valid configuration selected for SRC" #endif @@ -62,50 +63,6 @@ LOG_MODULE_REGISTER(src, CONFIG_SOF_LOG_LEVEL); -#if CONFIG_IPC_MAJOR_4 -/* src component private data */ -struct ipc4_config_src { - struct ipc4_base_module_cfg base; - uint32_t sink_rate; -}; - -/* e61bb28d-149a-4c1f-b709-46823ef5f5a3 */ -DECLARE_SOF_RT_UUID("src", src_uuid, 0xe61bb28d, 0x149a, 0x4c1f, - 0xb7, 0x09, 0x46, 0x82, 0x3e, 0xf5, 0xf5, 0xae); -#elif CONFIG_IPC_MAJOR_3 -/* c1c5326d-8390-46b4-aa47-95c3beca6550 */ -DECLARE_SOF_RT_UUID("src", src_uuid, 0xc1c5326d, 0x8390, 0x46b4, - 0xaa, 0x47, 0x95, 0xc3, 0xbe, 0xca, 0x65, 0x50); -#else -#error "No or invalid IPC MAJOR version selected." -#endif /* CONFIG_IPC_MAJOR_4 */ - -DECLARE_TR_CTX(src_tr, SOF_UUID(src_uuid), LOG_LEVEL_INFO); - -struct comp_data { -#if CONFIG_IPC_MAJOR_4 - struct ipc4_config_src ipc_config; -#else - struct ipc_config_src ipc_config; -#endif /* CONFIG_IPC_MAJOR_4 */ - struct polyphase_src src; - struct src_param param; - int32_t *delay_lines; - uint32_t sink_rate; - uint32_t source_rate; - int32_t *sbuf_w_ptr; - int32_t *sbuf_r_ptr; - int sbuf_avail; - int data_shift; - int source_frames; - int sink_frames; - int sample_container_bytes; - int channels_count; - int (*src_func)(struct comp_data *cd, struct sof_source __sparse_cache *source, - struct sof_sink __sparse_cache *sink); - void (*polyphase_func)(struct src_stage_prm *s); -}; - /* Calculates the needed FIR delay line length */ static int src_fir_delay_length(struct src_stage *s) { @@ -335,15 +292,15 @@ int src_polyphase_init(struct polyphase_src *src, struct src_param *p, } /* Fallback function */ -static int src_fallback(struct comp_data *cd, struct sof_source __sparse_cache *source, - struct sof_sink __sparse_cache *sink) +int src_fallback(struct comp_data *cd, struct sof_source *source, + struct sof_sink *sink) { return 0; } /* Normal 2 stage SRC */ static int src_2s(struct comp_data *cd, - struct sof_source __sparse_cache *source, struct sof_sink __sparse_cache *sink) + struct sof_source *source, struct sof_sink *sink) { struct src_stage_prm s1; struct src_stage_prm s2; @@ -353,7 +310,8 @@ static int src_2s(struct comp_data *cd, int s2_blk_out; uint32_t n_read = 0, n_written = 0; int ret; - uint8_t *buffer_start; + uint8_t const *source_buffer_start; + uint8_t *sink_buffer_start; void *sbuf_end_addr = &cd->delay_lines[cd->param.sbuf_length]; size_t sbuf_size = cd->param.sbuf_length * sizeof(int32_t); /* chan sink == chan src therefore we only need to use one*/ @@ -366,18 +324,18 @@ static int src_2s(struct comp_data *cd, uint32_t sink_frag_size = cd->param.blk_out * sink_get_frame_bytes(sink); ret = source_get_data(source, source_frag_size, - &s1.x_rptr, (void **)&buffer_start, &s1.x_size); + &s1.x_rptr, (void const **)&source_buffer_start, &s1.x_size); if (ret) return ret; - s1.x_end_addr = buffer_start + s1.x_size; + s1.x_end_addr = source_buffer_start + s1.x_size; ret = sink_get_buffer(sink, sink_frag_size, - &s2.y_wptr, (void **)&buffer_start, &s2.y_size); + &s2.y_wptr, (void **)&sink_buffer_start, &s2.y_size); if (ret) { source_release_data(source, 0); return ret; } - s2.y_end_addr = buffer_start + s2.y_size; + s2.y_end_addr = sink_buffer_start + s2.y_size; s1.y_end_addr = sbuf_end_addr; s1.y_size = sbuf_size; @@ -443,28 +401,29 @@ static int src_2s(struct comp_data *cd, } /* 1 stage SRC for simple conversions */ -static int src_1s(struct comp_data *cd, struct sof_source __sparse_cache *source, - struct sof_sink __sparse_cache *sink) +static int src_1s(struct comp_data *cd, struct sof_source *source, + struct sof_sink *sink) { struct src_stage_prm s1; int ret; - uint8_t *buffer_start; + uint8_t const *source_buffer_start; + uint8_t *sink_buffer_start; uint32_t source_frag_size = cd->param.blk_in * source_get_frame_bytes(source); uint32_t sink_frag_size = cd->param.blk_out * sink_get_frame_bytes(sink); ret = source_get_data(source, source_frag_size, - &s1.x_rptr, (void **)&buffer_start, &s1.x_size); + &s1.x_rptr, (void const **)&source_buffer_start, &s1.x_size); if (ret) return ret; - s1.x_end_addr = buffer_start + s1.x_size; + s1.x_end_addr = source_buffer_start + s1.x_size; ret = sink_get_buffer(sink, sink_frag_size, - &s1.y_wptr, (void **)&buffer_start, &s1.y_size); + &s1.y_wptr, (void **)&sink_buffer_start, &s1.y_size); if (ret) { source_release_data(source, 0); return ret; } - s1.y_end_addr = buffer_start + s1.y_size; + s1.y_end_addr = sink_buffer_start + s1.y_size; s1.times = cd->param.stage1_times; s1.state = &cd->src.state1; @@ -482,8 +441,8 @@ static int src_1s(struct comp_data *cd, struct sof_source __sparse_cache *source } /* A fast copy function for same in and out rate */ -static int src_copy_sxx(struct comp_data *cd, struct sof_source __sparse_cache *source, - struct sof_sink __sparse_cache *sink) +static int src_copy_sxx(struct comp_data *cd, struct sof_source *source, + struct sof_sink *sink) { int frames = cd->param.blk_in; @@ -500,132 +459,7 @@ static int src_copy_sxx(struct comp_data *cd, struct sof_source __sparse_cache * return -ENOTSUP; } -#if CONFIG_IPC_MAJOR_4 -static int src_rate_check(const void *spec) -{ - const struct ipc4_config_src *ipc_src = spec; - - if (ipc_src->base.audio_fmt.sampling_frequency == 0 || ipc_src->sink_rate == 0) - return -EINVAL; - - return 0; -} - -static int src_stream_pcm_source_rate_check(struct ipc4_config_src cfg, - struct sof_ipc_stream_params *params) -{ - /* Nothing to check */ - return 0; -} - -static int src_stream_pcm_sink_rate_check(struct ipc4_config_src cfg, - struct sof_ipc_stream_params *params) -{ - if (cfg.sink_rate && params->rate != cfg.sink_rate) - return -EINVAL; - - return 0; -} - -/* In ipc4 case param is figured out by module config so we need to first - * set up param then verify param. BTW for IPC3 path, the param is sent by - * host driver. - */ -static int src_set_params(struct processing_module *mod, struct sof_sink __sparse_cache *sink) -{ - struct sof_ipc_stream_params src_params; - struct sof_ipc_stream_params *params = mod->stream_params; - struct comp_data *cd = module_get_private_data(mod); - enum sof_ipc_frame frame_fmt, valid_fmt; - struct comp_dev *dev = mod->dev; - int ret; - - src_params = *params; - src_params.channels = mod->priv.cfg.base_cfg.audio_fmt.channels_count; - src_params.buffer_fmt = mod->priv.cfg.base_cfg.audio_fmt.interleaving_style; - src_params.rate = cd->ipc_config.sink_rate; - - /* Get frame_fmt and valid_fmt */ - audio_stream_fmt_conversion(mod->priv.cfg.base_cfg.audio_fmt.depth, - mod->priv.cfg.base_cfg.audio_fmt.valid_bit_depth, - &frame_fmt, &valid_fmt, - mod->priv.cfg.base_cfg.audio_fmt.s_type); - - src_params.frame_fmt = valid_fmt; - component_set_nearest_period_frames(dev, src_params.rate); - - ret = sink_set_params(sink, &src_params, true); - - /* Update module stream_params */ - params->rate = cd->ipc_config.sink_rate; - return ret; -} - -static void src_set_sink_params(struct comp_dev *dev, struct sof_sink __sparse_cache *sink) -{ - struct processing_module *mod = comp_get_drvdata(dev); - struct comp_data *cd = module_get_private_data(mod); - enum sof_ipc_frame frame_fmt, valid_fmt; - - /* convert IPC4 config to format used by the module */ - audio_stream_fmt_conversion(cd->ipc_config.base.audio_fmt.depth, - cd->ipc_config.base.audio_fmt.valid_bit_depth, - &frame_fmt, &valid_fmt, - cd->ipc_config.base.audio_fmt.s_type); - sink_set_frm_fmt(sink, frame_fmt); - sink_set_valid_fmt(sink, valid_fmt); - sink_set_channels(sink, cd->ipc_config.base.audio_fmt.channels_count); - sink_set_buffer_fmt(sink, cd->ipc_config.base.audio_fmt.interleaving_style); - sink_set_rate(sink, cd->ipc_config.sink_rate); -} - -#elif CONFIG_IPC_MAJOR_3 -static int src_rate_check(const void *spec) -{ - const struct ipc_config_src *ipc_src = spec; - - if (ipc_src->source_rate == 0 && ipc_src->sink_rate == 0) - return -EINVAL; - - return 0; -} - -static int src_stream_pcm_sink_rate_check(struct ipc_config_src cfg, - struct sof_ipc_stream_params *params) -{ - /* In playback, module adapter mod->stream_params from prepare() is for sink side */ - if (cfg.sink_rate && params->rate != cfg.sink_rate) - return -EINVAL; - - return 0; -} - -static int src_stream_pcm_source_rate_check(struct ipc_config_src cfg, - struct sof_ipc_stream_params *params) -{ - /* In capture, module adapter mod->stream_params from prepare() is for source side */ - if (cfg.source_rate && params->rate != cfg.source_rate) - return -EINVAL; - - return 0; -} - -static int src_set_params(struct processing_module *mod, struct sof_sink __sparse_cache *sink) -{ - return 0; -} - -static void src_set_sink_params(struct comp_dev *dev, struct sof_sink __sparse_cache *sink) -{ - /* empty */ -} - -#else -#error "No or invalid IPC MAJOR version selected." -#endif /* CONFIG_IPC_MAJOR_4 */ - -static void src_set_alignment(struct sof_source __sparse_cache *source, - struct sof_sink __sparse_cache *sink) +void src_set_alignment(struct sof_source *source, struct sof_sink *sink) { const uint32_t byte_align = 1; const uint32_t frame_align_req = 1; @@ -672,8 +506,8 @@ static int src_verify_params(struct processing_module *mod) } static bool src_get_copy_limits(struct comp_data *cd, - struct sof_source __sparse_cache *source, - struct sof_sink __sparse_cache *sink) + struct sof_source *source, + struct sof_sink *sink) { struct src_param *sp; struct src_stage *s1; @@ -716,8 +550,8 @@ static bool src_get_copy_limits(struct comp_data *cd, } static int src_params_general(struct processing_module *mod, - struct sof_source __sparse_cache *source, - struct sof_sink __sparse_cache *sink) + struct sof_source *source, + struct sof_sink *sink) { struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; @@ -740,15 +574,8 @@ static int src_params_general(struct processing_module *mod, return err; } - src_set_sink_params(dev, sink); + src_get_source_sink_params(dev, source, sink); -#if CONFIG_IPC_MAJOR_3 - /* Set source/sink_rate/frames */ - cd->channels_count = source_get_channels(source); - cd->source_rate = source_get_rate(source); - cd->sink_rate = sink_get_rate(sink); - cd->sample_container_bytes = mod->stream_params->sample_container_bytes; -#endif comp_info(dev, "src_params(), source_rate = %u, sink_rate = %u", cd->source_rate, cd->sink_rate); comp_dbg(dev, "src_params(), sample_container_bytes = %d, channels = %u, dev->frames = %u", @@ -825,166 +652,9 @@ static int src_params_general(struct processing_module *mod, return 0; } -static int src_prepare_general(struct processing_module *mod, - struct sof_source __sparse_cache *source, - struct sof_sink __sparse_cache *sink) -{ - struct comp_data *cd = module_get_private_data(mod); - struct comp_dev *dev = mod->dev; - int ret = 0; -#if CONFIG_IPC_MAJOR_3 - enum sof_ipc_frame source_format; - enum sof_ipc_frame sink_format; -#endif - - - /* set align requirements */ - src_set_alignment(source, sink); - -#if CONFIG_IPC_MAJOR_4 - switch (cd->ipc_config.base.audio_fmt.depth) { -#if CONFIG_FORMAT_S16LE - case IPC4_DEPTH_16BIT: - cd->data_shift = 0; - cd->polyphase_func = src_polyphase_stage_cir_s16; - break; -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S24LE - case IPC4_DEPTH_24BIT: - cd->data_shift = 8; - cd->polyphase_func = src_polyphase_stage_cir; - break; -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S32LE - case IPC4_DEPTH_32BIT: - cd->data_shift = 0; - cd->polyphase_func = src_polyphase_stage_cir; - break; -#endif /* CONFIG_FORMAT_S32LE */ - default: - comp_err(dev, "src_prepare(): Invalid depth %d", - cd->ipc_config.base.audio_fmt.depth); - ret = -EINVAL; - goto out; - } -#elif CONFIG_IPC_MAJOR_3 - /* get source/sink data format */ - source_format = source_get_frm_fmt(source); - sink_format = sink_get_frm_fmt(sink); - - /* SRC supports S16_LE, S24_4LE and S32_LE formats */ - if (source_format != sink_format) { - comp_err(dev, "src_prepare(): Source fmt %d and sink fmt %d are different.", - source_format, sink_format); - ret = -EINVAL; - goto out; - } - - switch (source_format) { -#if CONFIG_FORMAT_S16LE - case SOF_IPC_FRAME_S16_LE: - cd->data_shift = 0; - cd->polyphase_func = src_polyphase_stage_cir_s16; - break; -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S24LE - case SOF_IPC_FRAME_S24_4LE: - cd->data_shift = 8; - cd->polyphase_func = src_polyphase_stage_cir; - break; -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S32LE - case SOF_IPC_FRAME_S32_LE: - cd->data_shift = 0; - cd->polyphase_func = src_polyphase_stage_cir; - break; -#endif /* CONFIG_FORMAT_S32LE */ - default: - comp_err(dev, "src_prepare(): invalid format %d", source_format); - ret = -EINVAL; - goto out; - } -#endif /* CONFIG_IPC_MAJOR_3 */ - -out: - if (ret < 0) - comp_set_state(dev, COMP_TRIGGER_RESET); - - return ret; -} - -static int src_init(struct processing_module *mod) -{ - struct module_data *md = &mod->priv; - struct module_config *cfg = &md->cfg; - struct comp_dev *dev = mod->dev; - struct comp_data *cd = NULL; - - comp_dbg(dev, "src_init()"); -#if CONFIG_IPC_MAJOR_3 - if (dev->ipc_config.type != SOF_COMP_SRC) { - comp_err(dev, "src_init(): Wrong IPC config type %u", - dev->ipc_config.type); - return -EINVAL; - } -#endif - if (!cfg->init_data || cfg->size != sizeof(cd->ipc_config)) { - comp_err(dev, "src_init(): Missing or bad size (%u) init data", - cfg->size); - return -EINVAL; - } - - /* validate init data - either SRC sink or source rate must be set */ - if (src_rate_check(cfg->init_data) < 0) { - comp_err(dev, "src_init(): SRC sink and source rate are not set"); - return -EINVAL; - } - - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); - if (!cd) - return -ENOMEM; - - md->private = cd; - memcpy_s(&cd->ipc_config, sizeof(cd->ipc_config), cfg->init_data, sizeof(cd->ipc_config)); - - cd->delay_lines = NULL; - cd->src_func = src_fallback; - cd->polyphase_func = NULL; - src_polyphase_reset(&cd->src); - -#if CONFIG_IPC_MAJOR_4 - comp_dbg(dev, "src_init(), channels_count = %d, depth = %d", - cd->ipc_config.base.audio_fmt.channels_count, - cd->ipc_config.base.audio_fmt.depth); - comp_dbg(dev, "src_init(), sampling frequency = %d, sink rate = %d", - cd->ipc_config.base.audio_fmt.sampling_frequency, cd->ipc_config.sink_rate); - cd->source_rate = cd->ipc_config.base.audio_fmt.sampling_frequency; - cd->sink_rate = cd->ipc_config.sink_rate; - cd->channels_count = cd->ipc_config.base.audio_fmt.channels_count; - switch (cd->ipc_config.base.audio_fmt.depth) { - case IPC4_DEPTH_16BIT: - cd->sample_container_bytes = sizeof(int16_t); - break; - case IPC4_DEPTH_24BIT: - case IPC4_DEPTH_32BIT: - cd->sample_container_bytes = sizeof(int32_t); - break; - default: - comp_err(dev, "src_init(): Illegal sample depth %d", - cd->ipc_config.base.audio_fmt.depth); - rfree(cd); - return -EINVAL; - } -#elif CONFIG_IPC_MAJOR_3 - mod->verify_params_flags = BUFF_PARAMS_RATE; -#endif - - return 0; -} - static int src_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { int ret; @@ -1002,8 +672,8 @@ static int src_prepare(struct processing_module *mod, static bool src_is_ready_to_process(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_data *cd = module_get_private_data(mod); @@ -1011,8 +681,8 @@ static bool src_is_ready_to_process(struct processing_module *mod, } static int src_process(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_data *cd = module_get_private_data(mod); @@ -1066,8 +736,8 @@ static int src_free(struct processing_module *mod) return 0; } -static struct module_interface src_interface = { - .init = src_init, +static const struct module_interface src_interface = { + .init = src_init, .prepare = src_prepare, .process = src_process, .is_ready_to_process = src_is_ready_to_process, diff --git a/src/include/sof/audio/src/src.h b/src/audio/src/src.h similarity index 55% rename from src/include/sof/audio/src/src.h rename to src/audio/src/src.h index 6fa936fc74eb..fe2170ab1714 100644 --- a/src/include/sof/audio/src/src.h +++ b/src/audio/src/src.h @@ -10,6 +10,11 @@ #include #include +#include +#include +#include +#include +#include struct src_param { int fir_s1; @@ -61,8 +66,8 @@ struct polyphase_src { struct src_stage_prm { int nch; int times; - void *x_rptr; - void *x_end_addr; + void const *x_rptr; + void const *x_end_addr; size_t x_size; void *y_wptr; void *y_addr; @@ -119,4 +124,67 @@ int32_t src_input_rates(void); int32_t src_output_rates(void); +void src_set_alignment(struct sof_source *source, struct sof_sink *sink); + +#if CONFIG_IPC_MAJOR_4 +/* src component private data */ +struct ipc4_config_src { + struct ipc4_base_module_cfg base; + uint32_t sink_rate; +}; +#endif + +struct comp_data { +#if CONFIG_IPC_MAJOR_4 + struct ipc4_config_src ipc_config; +#else + struct ipc_config_src ipc_config; +#endif /* CONFIG_IPC_MAJOR_4 */ + struct polyphase_src src; + struct src_param param; + int32_t *delay_lines; + uint32_t sink_rate; + uint32_t source_rate; + int32_t *sbuf_w_ptr; + int32_t const *sbuf_r_ptr; + int sbuf_avail; + int data_shift; + int source_frames; + int sink_frames; + int sample_container_bytes; + int channels_count; + int (*src_func)(struct comp_data *cd, struct sof_source *source, + struct sof_sink *sink); + void (*polyphase_func)(struct src_stage_prm *s); +}; + #endif /* __SOF_AUDIO_SRC_SRC_H__ */ + +#if CONFIG_IPC_MAJOR_4 + +int src_stream_pcm_source_rate_check(struct ipc4_config_src cfg, + struct sof_ipc_stream_params *params); +int src_stream_pcm_sink_rate_check(struct ipc4_config_src cfg, + struct sof_ipc_stream_params *params); +#elif CONFIG_IPC_MAJOR_3 +int src_stream_pcm_sink_rate_check(struct ipc_config_src cfg, + struct sof_ipc_stream_params *params); +int src_stream_pcm_source_rate_check(struct ipc_config_src cfg, + struct sof_ipc_stream_params *params); +#endif /* CONFIG_IPC_MAJOR_4 */ + +int src_rate_check(const void *spec); +int src_set_params(struct processing_module *mod, struct sof_sink *sink); + +void src_get_source_sink_params(struct comp_dev *dev, struct sof_source *source, + struct sof_sink *sink); +int src_prepare_general(struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink); +int src_init(struct processing_module *mod); +int src_fallback(struct comp_data *cd, struct sof_source *source, + struct sof_sink *sink); + +extern const struct sof_uuid src_uuid; +extern struct tr_ctx src_tr; + diff --git a/src/include/sof/audio/src/src_config.h b/src/audio/src/src_config.h similarity index 100% rename from src/include/sof/audio/src/src_config.h rename to src/audio/src/src_config.h diff --git a/src/audio/src/src_generic.c b/src/audio/src/src_generic.c index 745afc16c025..6b6661d02c66 100644 --- a/src/audio/src/src_generic.c +++ b/src/audio/src/src_generic.c @@ -8,15 +8,16 @@ * architecture. */ -#include +#include "src_config.h" #if SRC_GENERIC #include -#include #include #include +#include "src.h" + #if SRC_SHORT /* 16 bit coefficients version */ static inline void fir_filter_generic(int32_t *rp, const void *cp, int32_t *wp0, diff --git a/src/audio/src/src_hifi2ep.c b/src/audio/src/src_hifi2ep.c index b426c622cafb..6c1e06b23d96 100644 --- a/src/audio/src/src_hifi2ep.c +++ b/src/audio/src/src_hifi2ep.c @@ -6,11 +6,12 @@ /* HiFi EP optimized code parts for SRC */ -#include +#include "src_config.h" #if SRC_HIFIEP -#include +#include "src.h" + #include #include #include diff --git a/src/audio/src/src_hifi3.c b/src/audio/src/src_hifi3.c index 2811a422c05d..bd419fdbfbb1 100644 --- a/src/audio/src/src_hifi3.c +++ b/src/audio/src/src_hifi3.c @@ -6,11 +6,12 @@ /* HiFi3 optimized code parts for SRC */ -#include +#include "src_config.h" #if SRC_HIFI3 -#include +#include "src.h" + #include #include #include diff --git a/src/audio/src/src_hifi4.c b/src/audio/src/src_hifi4.c index a2d2cd313a5e..9e011bf800f3 100644 --- a/src/audio/src/src_hifi4.c +++ b/src/audio/src/src_hifi4.c @@ -6,12 +6,13 @@ /* HiFi4 optimized code parts for SRC */ -#include +#include "src_config.h" #if SRC_HIFI4 +#include "src.h" + #include -#include #include #include #include diff --git a/src/audio/src/src_ipc3.c b/src/audio/src/src_ipc3.c new file mode 100644 index 000000000000..b2c2fbfd0930 --- /dev/null +++ b/src/audio/src/src_ipc3.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2017 Intel Corporation. All rights reserved. +// +// Author: Seppo Ingalsuo +// Liam Girdwood +// Keyon Jie + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src.h" +#include "src_config.h" + +/* c1c5326d-8390-46b4-aa47-95c3beca6550 */ +DECLARE_SOF_RT_UUID("src", src_uuid, 0xc1c5326d, 0x8390, 0x46b4, + 0xaa, 0x47, 0x95, 0xc3, 0xbe, 0xca, 0x65, 0x50); + +DECLARE_TR_CTX(src_tr, SOF_UUID(src_uuid), LOG_LEVEL_INFO); + +LOG_MODULE_DECLARE(src, CONFIG_SOF_LOG_LEVEL); + +int src_rate_check(const void *spec) +{ + const struct ipc_config_src *ipc_src = spec; + + if (ipc_src->source_rate == 0 && ipc_src->sink_rate == 0) + return -EINVAL; + + return 0; +} + +int src_stream_pcm_sink_rate_check(struct ipc_config_src cfg, + struct sof_ipc_stream_params *params) +{ + /* In playback, module adapter mod->stream_params from prepare() is for sink side */ + if (cfg.sink_rate && params->rate != cfg.sink_rate) + return -EINVAL; + + return 0; +} + +int src_stream_pcm_source_rate_check(struct ipc_config_src cfg, + struct sof_ipc_stream_params *params) +{ + /* In capture, module adapter mod->stream_params from prepare() is for source side */ + if (cfg.source_rate && params->rate != cfg.source_rate) + return -EINVAL; + + return 0; +} + +int src_set_params(struct processing_module *mod, struct sof_sink *sink) +{ + return 0; +} + +void src_get_source_sink_params(struct comp_dev *dev, struct sof_source *source, + struct sof_sink *sink) +{ + struct processing_module *mod = comp_get_drvdata(dev); + struct comp_data *cd = module_get_private_data(mod); + + /* Set source/sink_rate/frames */ + cd->channels_count = source_get_channels(source); + cd->source_rate = source_get_rate(source); + cd->sink_rate = sink_get_rate(sink); + cd->sample_container_bytes = mod->stream_params->sample_container_bytes; +} + +int src_prepare_general(struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink) +{ + struct comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + int ret = 0; + enum sof_ipc_frame source_format; + enum sof_ipc_frame sink_format; + + /* set align requirements */ + src_set_alignment(source, sink); + + /* get source/sink data format */ + source_format = source_get_frm_fmt(source); + sink_format = sink_get_frm_fmt(sink); + + /* SRC supports S16_LE, S24_4LE and S32_LE formats */ + if (source_format != sink_format) { + comp_err(dev, "src_prepare(): Source fmt %d and sink fmt %d are different.", + source_format, sink_format); + ret = -EINVAL; + goto out; + } + + switch (source_format) { +#if CONFIG_FORMAT_S16LE + case SOF_IPC_FRAME_S16_LE: + cd->data_shift = 0; + cd->polyphase_func = src_polyphase_stage_cir_s16; + break; +#endif /* CONFIG_FORMAT_S16LE */ +#if CONFIG_FORMAT_S24LE + case SOF_IPC_FRAME_S24_4LE: + cd->data_shift = 8; + cd->polyphase_func = src_polyphase_stage_cir; + break; +#endif /* CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S32LE + case SOF_IPC_FRAME_S32_LE: + cd->data_shift = 0; + cd->polyphase_func = src_polyphase_stage_cir; + break; +#endif /* CONFIG_FORMAT_S32LE */ + default: + comp_err(dev, "src_prepare(): invalid format %d", source_format); + ret = -EINVAL; + goto out; + } + +out: + if (ret < 0) + comp_set_state(dev, COMP_TRIGGER_RESET); + + return ret; +} + +int src_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct module_config *cfg = &md->cfg; + struct comp_dev *dev = mod->dev; + struct comp_data *cd = NULL; + + comp_dbg(dev, "src_init()"); + + if (dev->ipc_config.type != SOF_COMP_SRC) { + comp_err(dev, "src_init(): Wrong IPC config type %u", + dev->ipc_config.type); + return -EINVAL; + } + + if (!cfg->init_data || cfg->size != sizeof(cd->ipc_config)) { + comp_err(dev, "src_init(): Missing or bad size (%u) init data", + cfg->size); + return -EINVAL; + } + + /* validate init data - either SRC sink or source rate must be set */ + if (src_rate_check(cfg->init_data) < 0) { + comp_err(dev, "src_init(): SRC sink and source rate are not set"); + return -EINVAL; + } + + cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + if (!cd) + return -ENOMEM; + + md->private = cd; + memcpy_s(&cd->ipc_config, sizeof(cd->ipc_config), cfg->init_data, sizeof(cd->ipc_config)); + + cd->delay_lines = NULL; + cd->src_func = src_fallback; + cd->polyphase_func = NULL; + src_polyphase_reset(&cd->src); + + mod->verify_params_flags = BUFF_PARAMS_RATE; + + return 0; +} + diff --git a/src/audio/src/src_ipc4.c b/src/audio/src/src_ipc4.c new file mode 100644 index 000000000000..cf87bde47554 --- /dev/null +++ b/src/audio/src/src_ipc4.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2017 Intel Corporation. All rights reserved. +// +// Author: Seppo Ingalsuo +// Liam Girdwood +// Keyon Jie + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src.h" +#include "src_config.h" + +/* e61bb28d-149a-4c1f-b709-46823ef5f5a3 */ +DECLARE_SOF_RT_UUID("src", src_uuid, 0xe61bb28d, 0x149a, 0x4c1f, + 0xb7, 0x09, 0x46, 0x82, 0x3e, 0xf5, 0xf5, 0xae); + +DECLARE_TR_CTX(src_tr, SOF_UUID(src_uuid), LOG_LEVEL_INFO); + +LOG_MODULE_DECLARE(src, CONFIG_SOF_LOG_LEVEL); + +int src_rate_check(const void *spec) +{ + const struct ipc4_config_src *ipc_src = spec; + + if (ipc_src->base.audio_fmt.sampling_frequency == 0 || ipc_src->sink_rate == 0) + return -EINVAL; + + return 0; +} + +int src_stream_pcm_source_rate_check(struct ipc4_config_src cfg, + struct sof_ipc_stream_params *params) +{ + /* Nothing to check */ + return 0; +} + +int src_stream_pcm_sink_rate_check(struct ipc4_config_src cfg, + struct sof_ipc_stream_params *params) +{ + if (cfg.sink_rate && params->rate != cfg.sink_rate) + return -EINVAL; + + return 0; +} + +/* In ipc4 case param is figured out by module config so we need to first + * set up param then verify param. BTW for IPC3 path, the param is sent by + * host driver. + */ +int src_set_params(struct processing_module *mod, struct sof_sink *sink) +{ + struct sof_ipc_stream_params src_params; + struct sof_ipc_stream_params *params = mod->stream_params; + struct comp_data *cd = module_get_private_data(mod); + enum sof_ipc_frame frame_fmt, valid_fmt; + struct comp_dev *dev = mod->dev; + int ret; + + src_params = *params; + src_params.channels = mod->priv.cfg.base_cfg.audio_fmt.channels_count; + src_params.buffer_fmt = mod->priv.cfg.base_cfg.audio_fmt.interleaving_style; + src_params.rate = cd->ipc_config.sink_rate; + + /* Get frame_fmt and valid_fmt */ + audio_stream_fmt_conversion(mod->priv.cfg.base_cfg.audio_fmt.depth, + mod->priv.cfg.base_cfg.audio_fmt.valid_bit_depth, + &frame_fmt, &valid_fmt, + mod->priv.cfg.base_cfg.audio_fmt.s_type); + + src_params.frame_fmt = valid_fmt; + ret = sink_set_params(sink, &src_params, true); + + /* if module is to be run as DP, calculate module period + * according to OBS size and data rate + * as SRC uses period value to calculate its internal buffers, + * it must be done here, right after setting sink parameters + */ + if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) + dev->period = 1000000 * sink_get_min_free_space(sink) / + (sink_get_frame_bytes(sink) * sink_get_rate(sink)); + + comp_info(dev, "SRC DP period calculated as: %u", dev->period); + + component_set_nearest_period_frames(dev, src_params.rate); + /* Update module stream_params */ + params->rate = cd->ipc_config.sink_rate; + return ret; +} + +void src_get_source_sink_params(struct comp_dev *dev, struct sof_source *source, + struct sof_sink *sink) +{ + struct processing_module *mod = comp_get_drvdata(dev); + struct comp_data *cd = module_get_private_data(mod); + enum sof_ipc_frame frame_fmt, valid_fmt; + + /* convert IPC4 config to format used by the module */ + audio_stream_fmt_conversion(cd->ipc_config.base.audio_fmt.depth, + cd->ipc_config.base.audio_fmt.valid_bit_depth, + &frame_fmt, &valid_fmt, + cd->ipc_config.base.audio_fmt.s_type); + sink_set_frm_fmt(sink, frame_fmt); + sink_set_valid_fmt(sink, valid_fmt); + sink_set_channels(sink, cd->ipc_config.base.audio_fmt.channels_count); + sink_set_buffer_fmt(sink, cd->ipc_config.base.audio_fmt.interleaving_style); + sink_set_rate(sink, cd->ipc_config.sink_rate); +} + +int src_prepare_general(struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink) +{ + struct comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + int ret = 0; + + /* set align requirements */ + src_set_alignment(source, sink); + + switch (cd->ipc_config.base.audio_fmt.depth) { +#if CONFIG_FORMAT_S16LE + case IPC4_DEPTH_16BIT: + cd->data_shift = 0; + cd->polyphase_func = src_polyphase_stage_cir_s16; + break; +#endif /* CONFIG_FORMAT_S16LE */ +#if CONFIG_FORMAT_S24LE + case IPC4_DEPTH_24BIT: + cd->data_shift = 8; + cd->polyphase_func = src_polyphase_stage_cir; + break; +#endif /* CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S32LE + case IPC4_DEPTH_32BIT: + cd->data_shift = 0; + cd->polyphase_func = src_polyphase_stage_cir; + break; +#endif /* CONFIG_FORMAT_S32LE */ + default: + comp_err(dev, "src_prepare(): Invalid depth %d", + cd->ipc_config.base.audio_fmt.depth); + ret = -EINVAL; + goto out; + } + +out: + if (ret < 0) + comp_set_state(dev, COMP_TRIGGER_RESET); + + return ret; +} + +int src_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct module_config *cfg = &md->cfg; + struct comp_dev *dev = mod->dev; + struct comp_data *cd = NULL; + + comp_dbg(dev, "src_init()"); + + if (!cfg->init_data || cfg->size != sizeof(cd->ipc_config)) { + comp_err(dev, "src_init(): Missing or bad size (%u) init data", + cfg->size); + return -EINVAL; + } + + /* validate init data - either SRC sink or source rate must be set */ + if (src_rate_check(cfg->init_data) < 0) { + comp_err(dev, "src_init(): SRC sink and source rate are not set"); + return -EINVAL; + } + + cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + if (!cd) + return -ENOMEM; + + md->private = cd; + memcpy_s(&cd->ipc_config, sizeof(cd->ipc_config), cfg->init_data, sizeof(cd->ipc_config)); + + cd->delay_lines = NULL; + cd->src_func = src_fallback; + cd->polyphase_func = NULL; + src_polyphase_reset(&cd->src); + + comp_dbg(dev, "src_init(), channels_count = %d, depth = %d", + cd->ipc_config.base.audio_fmt.channels_count, + cd->ipc_config.base.audio_fmt.depth); + comp_dbg(dev, "src_init(), sampling frequency = %d, sink rate = %d", + cd->ipc_config.base.audio_fmt.sampling_frequency, cd->ipc_config.sink_rate); + cd->source_rate = cd->ipc_config.base.audio_fmt.sampling_frequency; + cd->sink_rate = cd->ipc_config.sink_rate; + cd->channels_count = cd->ipc_config.base.audio_fmt.channels_count; + switch (cd->ipc_config.base.audio_fmt.depth) { + case IPC4_DEPTH_16BIT: + cd->sample_container_bytes = sizeof(int16_t); + break; + case IPC4_DEPTH_24BIT: + case IPC4_DEPTH_32BIT: + cd->sample_container_bytes = sizeof(int32_t); + break; + default: + comp_err(dev, "src_init(): Illegal sample depth %d", + cd->ipc_config.base.audio_fmt.depth); + rfree(cd); + return -EINVAL; + } + + return 0; +} + diff --git a/src/audio/tdfb/tdfb.c b/src/audio/tdfb/tdfb.c index d1b04b7faf42..38ff7ee240d8 100644 --- a/src/audio/tdfb/tdfb.c +++ b/src/audio/tdfb/tdfb.c @@ -40,6 +40,12 @@ #include #include +#if CONFIG_IPC_MAJOR_4 +#include +#include +#include +#endif + /* The driver assigns running numbers for control index. If there's single control of * type switch, enum, binary they all have index 0. */ @@ -57,10 +63,60 @@ DECLARE_SOF_RT_UUID("tdfb", tdfb_uuid, 0xdd511749, 0xd9fa, 0x455c, 0xb3, 0xa7, DECLARE_TR_CTX(tdfb_tr, SOF_UUID(tdfb_uuid), LOG_LEVEL_INFO); -/* IPC */ +/* IPC helpers for control update to user space */ -/* TODO: ALSA control update to user space need to be moved to module adapter */ +#if CONFIG_IPC_MAJOR_4 +static struct ipc_msg *tdfb_notification_init(struct processing_module *mod, + uint32_t control_type_param_id, + uint32_t control_id) +{ + struct ipc_msg msg_proto; + struct comp_dev *dev = mod->dev; + struct comp_ipc_config *ipc_config = &dev->ipc_config; + union ipc4_notification_header *primary = + (union ipc4_notification_header *)&msg_proto.header; + struct ipc_msg *msg; + struct tdfb_notification_payload *payload; + + /* Clear header, extension, and other ipc_msg members */ + memset_s(&msg_proto, sizeof(msg_proto), 0, sizeof(msg_proto)); + primary->r.notif_type = SOF_IPC4_MODULE_NOTIFICATION; + primary->r.type = SOF_IPC4_GLB_NOTIFICATION; + primary->r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST; + primary->r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG; + msg = ipc_msg_w_ext_init(msg_proto.header, msg_proto.extension, + sizeof(struct tdfb_notification_payload)); + if (!msg) + return NULL; + + payload = (struct tdfb_notification_payload *)msg->tx_data; + payload->module_data.instance_id = IPC4_INST_ID(ipc_config->id); + payload->module_data.module_id = IPC4_MOD_ID(ipc_config->id); + payload->module_data.event_id = SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL | + control_type_param_id; + payload->module_data.event_data_size = sizeof(struct sof_ipc4_control_msg_payload) + + sizeof(struct sof_ipc4_ctrl_value_chan); + payload->control_msg.id = control_id; + payload->control_msg.num_elems = 1; + payload->control_value.channel = 0; + + comp_dbg(dev, "instance_id = 0x%08x, module_id = 0x%08x", + payload->module_data.instance_id, payload->module_data.module_id); + return msg; +} + +static void tdfb_send_notification(struct ipc_msg *msg, uint32_t val) +{ + struct tdfb_notification_payload *ipc_payload; + + ipc_payload = (struct tdfb_notification_payload *)msg->tx_data; + ipc_payload->control_value.value = val; + ipc_msg_send(msg, NULL, false); +} +/* end CONFIG_IPC_MAJOR_4 */ + +#elif CONFIG_IPC_MAJOR_3 static int init_get_ctl_ipc(struct processing_module *mod) { struct tdfb_comp_data *cd = module_get_private_data(mod); @@ -94,6 +150,7 @@ static void send_get_ctl_ipc(struct processing_module *mod) ipc_msg_send(cd->msg, cd->ctrl_data, false); } +#endif /* CONFIG_IPC_MAJOR_3 */ /* * The optimized FIR functions variants need to be updated into function @@ -447,9 +504,19 @@ static int tdfb_init(struct processing_module *mod) */ /* Initialize IPC for direction of arrival estimate update */ +#if CONFIG_IPC_MAJOR_4 + cd->msg = tdfb_notification_init(mod, SOF_IPC4_ENUM_CONTROL_PARAM_ID, + CTRL_INDEX_AZIMUTH_ESTIMATE); + if (!cd->msg) { + comp_err(dev, "Failed to initialize control notification."); + ret = -EINVAL; + goto err_free_cd; + } +#elif CONFIG_IPC_MAJOR_3 ret = init_get_ctl_ipc(mod); if (ret) goto err_free_cd; +#endif /* Handler for configuration data */ cd->model_handler = comp_data_blob_handler_new(dev); @@ -476,7 +543,9 @@ static int tdfb_init(struct processing_module *mod) return 0; err: + /* These are null if not used for IPC version */ rfree(cd->ctrl_data); + ipc_msg_free(cd->msg); err_free_cd: rfree(cd); @@ -503,6 +572,7 @@ static int tdfb_free(struct processing_module *mod) * Module commands handling */ +#if CONFIG_IPC_MAJOR_3 static int tdfb_cmd_switch_get(struct sof_ipc_ctrl_data *cdata, struct tdfb_comp_data *cd) { int j; @@ -557,11 +627,16 @@ static int tdfb_cmd_get_value(struct processing_module *mod, struct sof_ipc_ctrl comp_err(mod->dev, "tdfb_cmd_get_value() error: invalid cdata->cmd"); return -EINVAL; } +#endif /* CONFIG_IPC_MAJOR_3 */ static int tdfb_get_config(struct processing_module *mod, - uint32_t config_id, uint32_t *data_offset_size, + uint32_t param_id, uint32_t *data_offset_size, uint8_t *fragment, size_t fragment_size) { +#if CONFIG_IPC_MAJOR_4 + comp_err(mod->dev, "tdfb_get_config(), Not supported, should not happen"); + return -EINVAL; +#elif CONFIG_IPC_MAJOR_3 struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; struct tdfb_comp_data *cd = module_get_private_data(mod); @@ -570,8 +645,10 @@ static int tdfb_get_config(struct processing_module *mod, comp_dbg(mod->dev, "tdfb_get_config(), binary"); return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); +#endif /* CONFIG_IPC_MAJOR_3 */ } +#if CONFIG_IPC_MAJOR_3 static int tdfb_cmd_enum_set(struct sof_ipc_ctrl_data *cdata, struct tdfb_comp_data *cd) { if (cdata->num_elems != 1) @@ -634,16 +711,80 @@ static int tdfb_cmd_set_value(struct processing_module *mod, struct sof_ipc_ctrl return -EINVAL; } -static int tdfb_set_config(struct processing_module *mod, uint32_t config_id, +/* end CONFIG_IPC_MAJOR_3 */ + +#elif CONFIG_IPC_MAJOR_4 +static int tdfb_cmd_enum_set(struct sof_ipc4_control_msg_payload *ctl, struct tdfb_comp_data *cd) +{ + if (ctl->num_elems != 1) + return -EINVAL; + + if (ctl->chanv[0].value > SOF_TDFB_MAX_ANGLES) + return -EINVAL; + + switch (ctl->id) { + case CTRL_INDEX_AZIMUTH: + cd->az_value = ctl->chanv[0].value; + cd->update = true; + break; + case CTRL_INDEX_AZIMUTH_ESTIMATE: + cd->az_value_estimate = ctl->chanv[0].value; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int tdfb_cmd_switch_set(struct sof_ipc4_control_msg_payload *ctl, struct tdfb_comp_data *cd) +{ + if (ctl->num_elems != 1) + return -EINVAL; + + switch (ctl->id) { + case CTRL_INDEX_PROCESS: + cd->beam_on = ctl->chanv[0].value; + cd->update = true; + break; + case CTRL_INDEX_DIRECTION: + cd->direction_updates = ctl->chanv[0].value; + break; + default: + return -EINVAL; + } + + return 0; +} +#endif + +static int tdfb_set_config(struct processing_module *mod, uint32_t param_id, enum module_cfg_fragment_position pos, uint32_t data_offset_size, const uint8_t *fragment, size_t fragment_size, uint8_t *response, size_t response_size) { struct tdfb_comp_data *cd = module_get_private_data(mod); + +#if CONFIG_IPC_MAJOR_4 + struct sof_ipc4_control_msg_payload *ctl = (struct sof_ipc4_control_msg_payload *)fragment; + + switch (param_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + comp_info(mod->dev, "SOF_IPC4_SWITCH_CONTROL_PARAM_ID id = %d, num_elems = %d", + ctl->id, ctl->num_elems); + return tdfb_cmd_switch_set(ctl, cd); + + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + comp_info(mod->dev, "SOF_IPC4_ENUM_CONTROL_PARAM_ID id = %d, num_elems = %d", + ctl->id, ctl->num_elems); + return tdfb_cmd_enum_set(ctl, cd); + } +#elif CONFIG_IPC_MAJOR_3 struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; if (cdata->cmd != SOF_CTRL_CMD_BINARY) return tdfb_cmd_set_value(mod, cdata); +#endif /* CONFIG_IPC_MAJOR_3 */ comp_dbg(mod->dev, "tdfb_set_config(), binary"); return comp_data_blob_set(cd->model_handler, pos, data_offset_size, @@ -660,8 +801,8 @@ static int tdfb_process(struct processing_module *mod, { struct comp_dev *dev = mod->dev; struct tdfb_comp_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = input_buffers[0].data; - struct audio_stream __sparse_cache *sink = output_buffers[0].data; + struct audio_stream *source = input_buffers[0].data; + struct audio_stream *sink = output_buffers[0].data; int frame_count = input_buffers[0].size; int ret; @@ -705,7 +846,11 @@ static int tdfb_process(struct processing_module *mod, (int32_t)(cd->direction.level_ambient >> 32), cd->direction.az_slow); if (cd->direction_updates && cd->direction_change) { +#if CONFIG_IPC_MAJOR_3 send_get_ctl_ipc(mod); +#elif CONFIG_IPC_MAJOR_4 + tdfb_send_notification(cd->msg, cd->az_value_estimate); +#endif cd->direction_change = false; comp_dbg(dev, "tdfb_dupd %d %d", cd->az_value_estimate, cd->direction.az_slow); @@ -715,8 +860,8 @@ static int tdfb_process(struct processing_module *mod, return 0; } -static void tdfb_set_alignment(struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink) +static void tdfb_set_alignment(struct audio_stream *source, + struct audio_stream *sink) { const uint32_t byte_align = 1; const uint32_t frame_align_req = 2; /* Process multiples of 2 frames */ @@ -725,13 +870,30 @@ static void tdfb_set_alignment(struct audio_stream __sparse_cache *source, audio_stream_init_alignment_constants(byte_align, frame_align_req, sink); } +#if CONFIG_IPC_MAJOR_4 +static void tdfb_params(struct processing_module *mod) +{ + struct sof_ipc_stream_params *params = mod->stream_params; + struct comp_buffer *sinkb, *sourceb; + struct comp_dev *dev = mod->dev; + + ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); + component_set_nearest_period_frames(dev, params->rate); + + sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); + ipc4_update_buffer_format(sourceb, &mod->priv.cfg.base_cfg.audio_fmt); + + sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); + ipc4_update_buffer_format(sinkb, &mod->priv.cfg.base_cfg.audio_fmt); +} +#endif + static int tdfb_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct tdfb_comp_data *cd = module_get_private_data(mod); struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; struct comp_dev *dev = mod->dev; enum sof_ipc_frame frame_fmt; int source_channels; @@ -741,19 +903,19 @@ static int tdfb_prepare(struct processing_module *mod, comp_info(dev, "tdfb_prepare()"); +#if CONFIG_IPC_MAJOR_4 + tdfb_params(mod); +#endif + /* Find source and sink buffers */ sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - tdfb_set_alignment(&source_c->stream, &sink_c->stream); + tdfb_set_alignment(&sourceb->stream, &sinkb->stream); - frame_fmt = audio_stream_get_frm_fmt(&source_c->stream); - source_channels = audio_stream_get_channels(&source_c->stream); - sink_channels = audio_stream_get_channels(&sink_c->stream); - rate = audio_stream_get_rate(&source_c->stream); - buffer_release(sink_c); - buffer_release(source_c); + frame_fmt = audio_stream_get_frm_fmt(&sourceb->stream); + source_channels = audio_stream_get_channels(&sourceb->stream); + sink_channels = audio_stream_get_channels(&sinkb->stream); + rate = audio_stream_get_rate(&sourceb->stream); /* Initialize filter */ cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); @@ -819,7 +981,7 @@ static int tdfb_reset(struct processing_module *mod) return 0; } -static struct module_interface tdfb_interface = { +static const struct module_interface tdfb_interface = { .init = tdfb_init, .free = tdfb_free, .set_configuration = tdfb_set_config, diff --git a/src/audio/tdfb/tdfb_generic.c b/src/audio/tdfb/tdfb_generic.c index 8306bb6a8991..22f74702ac06 100644 --- a/src/audio/tdfb/tdfb_generic.c +++ b/src/audio/tdfb/tdfb_generic.c @@ -58,8 +58,8 @@ static inline void tdfb_core(struct tdfb_comp_data *cd, int in_nch, int out_nch) void tdfb_fir_s16(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int16_t *x = audio_stream_get_rptr(source); int16_t *y = audio_stream_get_wptr(sink); int fmax; @@ -104,8 +104,8 @@ void tdfb_fir_s16(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource void tdfb_fir_s24(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *x = audio_stream_get_rptr(source); int32_t *y = audio_stream_get_wptr(sink); int fmax; @@ -150,8 +150,8 @@ void tdfb_fir_s24(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource void tdfb_fir_s32(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *x = audio_stream_get_rptr(source); int32_t *y = audio_stream_get_wptr(sink); int fmax; diff --git a/src/audio/tdfb/tdfb_hifi3.c b/src/audio/tdfb/tdfb_hifi3.c index 97b5229d02dd..421784db9d1d 100644 --- a/src/audio/tdfb/tdfb_hifi3.c +++ b/src/audio/tdfb/tdfb_hifi3.c @@ -19,8 +19,8 @@ void tdfb_fir_s16(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct sof_tdfb_config *cfg = cd->config; struct fir_state_32x16 *f; ae_int16x4 d; @@ -108,8 +108,8 @@ void tdfb_fir_s16(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource void tdfb_fir_s24(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct sof_tdfb_config *cfg = cd->config; struct fir_state_32x16 *f; ae_int32x2 d; @@ -197,8 +197,8 @@ void tdfb_fir_s24(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource void tdfb_fir_s32(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; struct sof_tdfb_config *cfg = cd->config; struct fir_state_32x16 *f; ae_int32x2 d; diff --git a/src/audio/tdfb/tdfb_hifiep.c b/src/audio/tdfb/tdfb_hifiep.c index eba8d7c7807e..1f5b71dbe612 100644 --- a/src/audio/tdfb/tdfb_hifiep.c +++ b/src/audio/tdfb/tdfb_hifiep.c @@ -58,8 +58,8 @@ static inline void tdfb_core(struct tdfb_comp_data *cd, int in_nch, int out_nch) void tdfb_fir_s16(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int16_t *x = audio_stream_get_rptr(source); int16_t *y = audio_stream_get_wptr(sink); int fmax; @@ -104,8 +104,8 @@ void tdfb_fir_s16(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource void tdfb_fir_s24(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *x = audio_stream_get_rptr(source); int32_t *y = audio_stream_get_wptr(sink); int fmax; @@ -150,8 +150,8 @@ void tdfb_fir_s24(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource void tdfb_fir_s32(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *x = audio_stream_get_rptr(source); int32_t *y = audio_stream_get_wptr(sink); int fmax; diff --git a/src/audio/tone.c b/src/audio/tone.c index 65c934246909..c669698bd13e 100644 --- a/src/audio/tone.c +++ b/src/audio/tone.c @@ -95,7 +95,7 @@ struct comp_data { uint32_t frame_bytes; uint32_t rate; struct tone_state sg[PLATFORM_MAX_CHANNELS]; - void (*tone_func)(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, + void (*tone_func)(struct comp_dev *dev, struct audio_stream *sink, uint32_t frames); }; @@ -113,7 +113,7 @@ static inline void tone_circ_inc_wrap(int32_t **ptr, int32_t *end, size_t size) *ptr = (int32_t *)((size_t)*ptr - size); } -static void tone_s32_default(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, +static void tone_s32_default(struct comp_dev *dev, struct audio_stream *sink, uint32_t frames) { struct comp_data *cd = comp_get_drvdata(dev); @@ -429,7 +429,6 @@ static int tone_params(struct comp_dev *dev, { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); @@ -444,18 +443,12 @@ static int tone_params(struct comp_dev *dev, if (dev->ipc_config.frame_fmt != SOF_IPC_FRAME_S32_LE) return -EINVAL; - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - - audio_stream_set_frm_fmt(&source_c->stream, dev->ipc_config.frame_fmt); - audio_stream_set_frm_fmt(&sink_c->stream, dev->ipc_config.frame_fmt); + audio_stream_set_frm_fmt(&sourceb->stream, dev->ipc_config.frame_fmt); + audio_stream_set_frm_fmt(&sinkb->stream, dev->ipc_config.frame_fmt); /* calculate period size based on config */ cd->period_bytes = dev->frames * - audio_stream_frame_bytes(&source_c->stream); - - buffer_release(sink_c); - buffer_release(source_c); + audio_stream_frame_bytes(&sourceb->stream); return 0; } @@ -634,7 +627,6 @@ static int tone_trigger(struct comp_dev *dev, int cmd) static int tone_copy(struct comp_dev *dev) { struct comp_buffer *sink; - struct comp_buffer __sparse_cache *sink_c; struct comp_data *cd = comp_get_drvdata(dev); uint32_t free; int ret = 0; @@ -645,25 +637,22 @@ static int tone_copy(struct comp_dev *dev) sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - free = audio_stream_get_free_bytes(&sink_c->stream); + free = audio_stream_get_free_bytes(&sink->stream); /* Test that sink has enough free frames. Then run once to maintain * low latency and steady load for tones. */ if (free >= cd->period_bytes) { /* create tone */ - cd->tone_func(dev, &sink_c->stream, dev->frames); - buffer_stream_writeback(sink_c, cd->period_bytes); + cd->tone_func(dev, &sink->stream, dev->frames); + buffer_stream_writeback(sink, cd->period_bytes); /* calc new free and available */ - comp_update_buffer_produce(sink_c, cd->period_bytes); + comp_update_buffer_produce(sink, cd->period_bytes); ret = dev->frames; } - buffer_release(sink_c); - return ret; } diff --git a/src/audio/up_down_mixer/up_down_mixer.c b/src/audio/up_down_mixer/up_down_mixer.c index e1887865ac70..c6e6c6b5bd58 100644 --- a/src/audio/up_down_mixer/up_down_mixer.c +++ b/src/audio/up_down_mixer/up_down_mixer.c @@ -400,8 +400,8 @@ static int up_down_mixer_init(struct processing_module *mod) /* just stubs for now. Remove these after making these ops optional in the module adapter */ static int up_down_mixer_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct up_down_mixer_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; @@ -456,8 +456,8 @@ up_down_mixer_process(struct processing_module *mod, return 0; } -static struct module_interface up_down_mixer_interface = { - .init = up_down_mixer_init, +static const struct module_interface up_down_mixer_interface = { + .init = up_down_mixer_init, .prepare = up_down_mixer_prepare, .process_audio_stream = up_down_mixer_process, .reset = up_down_mixer_reset, diff --git a/src/audio/volume/Kconfig b/src/audio/volume/Kconfig new file mode 100644 index 000000000000..a0daa89a2940 --- /dev/null +++ b/src/audio/volume/Kconfig @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: BSD-3-Clause + + config COMP_VOLUME + bool "Volume component" + default y + help + Select for Volume component + +if COMP_VOLUME + +config COMP_VOLUME_WINDOWS_FADE + bool "Windows Fade shape volume transitions support" + help + This option enables volume ramp shape that follows + power of 1.75. The shape is not linear, not logarithmic. + The power function uses a lookup table that consumes + 256 bytes. The topology must set volume ramp token to + SOF_VOLUME_WINDOWS_FADE for the volume instance to use + this ramp shape. + +config COMP_VOLUME_LINEAR_RAMP + bool "Linear ramp volume transitions support" + default y + help + This option enables volume linear ramp shape. + +config COMP_PEAK_VOL + bool "Report peak vol data to host" + default y + depends on IPC_MAJOR_4 + help + This option enables reporting to host peak vol regs. + See: struct ipc4_peak_volume_regs + +choice "PEAK_METER_UPDATE_PERIOD_CHOICE" + prompt "The periods(ms) of updating peak meter value" + default PEAK_METER_UPDATE_10MS + depends on COMP_PEAK_VOL + + config PEAK_METER_UPDATE_1MS + bool "1ms" + help + Update the peak meter value every 1ms + + config PEAK_METER_UPDATE_10MS + bool "10ms" + help + Update the peak meter value every 10ms + + config PEAK_METER_UPDATE_100MS + bool "100ms" + help + Update the peak meter value every 100ms + + config PEAK_METER_UPDATE_1000MS + bool "1000ms" + help + Update the peak meter value every 1000ms + endchoice + +config PEAK_METER_UPDATE_PERIOD + int + depends on COMP_PEAK_VOL + default 1 if PEAK_METER_UPDATE_1MS + default 10 if PEAK_METER_UPDATE_10MS + default 100 if PEAK_METER_UPDATE_100MS + default 1000 if PEAK_METER_UPDATE_1000MS + help + Decide which period of update the peak volume meter value + +config COMP_GAIN + bool "GAIN component" + default y + depends on IPC_MAJOR_4 + help + This option enables gain to change volume. It works + as peak volume without updating peak vol to host + +endif # volume \ No newline at end of file diff --git a/src/audio/volume/peak_volume.h b/src/audio/volume/peak_volume.h index fd4a078f0ad5..057db458277a 100644 --- a/src/audio/volume/peak_volume.h +++ b/src/audio/volume/peak_volume.h @@ -24,6 +24,7 @@ #ifndef __SOF_IPC4_PEAK_VOL_H__ #define __SOF_IPC4_PEAK_VOL_H__ +#include #include enum ipc4_vol_mode { @@ -43,7 +44,11 @@ enum ipc4_peak_volume_param { enum ipc4_curve_type { IPC4_AUDIO_CURVE_TYPE_NONE = 0, - IPC4_AUDIO_CURVE_TYPE_WINDOWS_FADE + IPC4_AUDIO_CURVE_TYPE_WINDOWS_FADE, + IPC4_AUDIO_CURVE_TYPE_LINEAR, + IPC4_AUDIO_CURVE_TYPE_LOG, + IPC4_AUDIO_CURVE_TYPE_LINEAR_ZC, + IPC4_AUDIO_CURVE_TYPE_LOG_ZC, }; static const uint32_t IPC4_ALL_CHANNELS_MASK = 0xffffffff; @@ -74,4 +79,28 @@ struct ipc4_peak_volume_module_cfg { struct ipc4_base_module_cfg base_cfg; struct ipc4_peak_volume_config config[]; } __packed __aligned(8); + +static inline enum sof_volume_ramp ipc4_curve_type_convert(enum ipc4_curve_type ipc4_type) +{ + switch (ipc4_type) { + case IPC4_AUDIO_CURVE_TYPE_WINDOWS_FADE: + return SOF_VOLUME_WINDOWS_FADE; + + case IPC4_AUDIO_CURVE_TYPE_LINEAR: + return SOF_VOLUME_LINEAR; + + case IPC4_AUDIO_CURVE_TYPE_LOG: + return SOF_VOLUME_LOG; + + case IPC4_AUDIO_CURVE_TYPE_LINEAR_ZC: + return SOF_VOLUME_LINEAR_ZC; + + case IPC4_AUDIO_CURVE_TYPE_LOG_ZC: + return SOF_VOLUME_LOG_ZC; + + case IPC4_AUDIO_CURVE_TYPE_NONE: + default: + return SOF_VOLUME_WINDOWS_NO_FADE; + } +} #endif diff --git a/src/audio/volume/volume.c b/src/audio/volume/volume.c index a4128136a5e5..30896fd87a33 100644 --- a/src/audio/volume/volume.c +++ b/src/audio/volume/volume.c @@ -57,7 +57,7 @@ LOG_MODULE_REGISTER(volume, CONFIG_SOF_LOG_LEVEL); * \param[in] frames Number of frames. * \param[in,out] prev_sum Previous sum of channel samples. */ -static uint32_t vol_zc_get_s16(const struct audio_stream __sparse_cache *source, +static uint32_t vol_zc_get_s16(const struct audio_stream *source, uint32_t frames, int64_t *prev_sum) { uint32_t curr_frames = frames; @@ -105,7 +105,7 @@ static uint32_t vol_zc_get_s16(const struct audio_stream __sparse_cache *source, * \param[in] frames Number of frames. * \param[in,out] prev_sum Previous sum of channel samples. */ -static uint32_t vol_zc_get_s24(const struct audio_stream __sparse_cache *source, +static uint32_t vol_zc_get_s24(const struct audio_stream *source, uint32_t frames, int64_t *prev_sum) { int64_t sum; @@ -153,7 +153,7 @@ static uint32_t vol_zc_get_s24(const struct audio_stream __sparse_cache *source, * \param[in] frames Number of frames. * \param[in,out] prev_sum Previous sum of channel samples. */ -static uint32_t vol_zc_get_s32(const struct audio_stream __sparse_cache *source, +static uint32_t vol_zc_get_s32(const struct audio_stream *source, uint32_t frames, int64_t *prev_sum) { int64_t sum; @@ -283,18 +283,22 @@ static inline void volume_ramp(struct processing_module *mod) * calculated from previous gain and ramp time. The slope * coefficient is calculated in volume_set_chan(). */ -#if defined CONFIG_COMP_VOLUME_WINDOWS_FADE && defined CONFIG_COMP_VOLUME_LINEAR_RAMP - if (cd->ramp_type == SOF_VOLUME_WINDOWS_FADE) + switch (cd->ramp_type) { +#if CONFIG_COMP_VOLUME_WINDOWS_FADE + case SOF_VOLUME_WINDOWS_FADE: new_vol = volume_windows_fade_ramp(cd, ramp_time, i); - else + break; +#endif +#if CONFIG_COMP_VOLUME_LINEAR_RAMP + case SOF_VOLUME_LINEAR: + case SOF_VOLUME_LINEAR_ZC: new_vol = volume_linear_ramp(cd, ramp_time, i); -#elif defined CONFIG_COMP_VOLUME_WINDOWS_FADE - new_vol = volume_windows_fade_ramp(cd, ramp_time, i); -#elif defined CONFIG_COMP_VOLUME_LINEAR_RAMP - new_vol = volume_linear_ramp(cd, ramp_time, i); -#else - new_vol = tvolume; + break; #endif + default: + new_vol = tvolume; + } + if (volume < tvolume) { /* ramp up, check if ramp completed */ if (new_vol < tvolume) @@ -575,7 +579,7 @@ static int volume_process(struct processing_module *mod, * \param[in,out] dev Volume base component device. */ static vol_zc_func vol_get_zc_function(struct comp_dev *dev, - struct comp_buffer __sparse_cache *sinkb) + struct comp_buffer *sinkb) { int i; @@ -593,8 +597,8 @@ static vol_zc_func vol_get_zc_function(struct comp_dev *dev, * \param[in,out] source Structure pointer of source. * \param[in,out] sink Structure pointer of sink. */ -static void volume_set_alignment(struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink) +static void volume_set_alignment(struct audio_stream *source, + struct audio_stream *sink) { #if XCHAL_HAVE_HIFI3 || XCHAL_HAVE_HIFI4 @@ -631,14 +635,13 @@ static void volume_set_alignment(struct audio_stream __sparse_cache *source, * to also do some type of conversion here. */ static int volume_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct vol_data *cd = module_get_private_data(mod); struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; uint32_t sink_period_bytes; int ret; int i; @@ -653,20 +656,15 @@ static int volume_prepare(struct processing_module *mod, sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - sink_c = buffer_acquire(sinkb); - source_c = buffer_acquire(sourceb); - - volume_set_alignment(&source_c->stream, &sink_c->stream); - - buffer_release(source_c); + volume_set_alignment(&sourceb->stream, &sinkb->stream); /* get sink period bytes */ - sink_period_bytes = audio_stream_period_bytes(&sink_c->stream, + sink_period_bytes = audio_stream_period_bytes(&sinkb->stream, dev->frames); - if (audio_stream_get_size(&sink_c->stream) < sink_period_bytes) { + if (audio_stream_get_size(&sinkb->stream) < sink_period_bytes) { comp_err(dev, "volume_prepare(): sink buffer size %d is insufficient < %d", - audio_stream_get_size(&sink_c->stream), sink_period_bytes); + audio_stream_get_size(&sinkb->stream), sink_period_bytes); ret = -ENOMEM; goto err; } @@ -680,7 +678,7 @@ static int volume_prepare(struct processing_module *mod, goto err; } - cd->zc_get = vol_get_zc_function(dev, sink_c); + cd->zc_get = vol_get_zc_function(dev, sinkb); if (!cd->zc_get) { comp_err(dev, "volume_prepare(): invalid cd->zc_get"); ret = -EINVAL; @@ -695,16 +693,14 @@ static int volume_prepare(struct processing_module *mod, */ cd->ramp_finished = false; - cd->channels = audio_stream_get_channels(&sink_c->stream); + cd->channels = audio_stream_get_channels(&sinkb->stream); if (cd->channels > SOF_IPC_MAX_CHANNELS) { ret = -EINVAL; goto err; } cd->sample_rate_inv = (int32_t)(1000LL * INT32_MAX / - audio_stream_get_rate(&sink_c->stream)); - - buffer_release(sink_c); + audio_stream_get_rate(&sinkb->stream)); for (i = 0; i < cd->channels; i++) { cd->volume[i] = cd->vol_min; @@ -725,7 +721,6 @@ static int volume_prepare(struct processing_module *mod, return 0; err: - buffer_release(sink_c); comp_set_state(dev, COMP_TRIGGER_RESET); return ret; } @@ -745,8 +740,8 @@ static int volume_reset(struct processing_module *mod) return 0; } -static struct module_interface volume_interface = { - .init = volume_init, +static const struct module_interface volume_interface = { + .init = volume_init, .prepare = volume_prepare, .process_audio_stream = volume_process, .set_configuration = volume_set_config, @@ -759,8 +754,8 @@ DECLARE_MODULE_ADAPTER(volume_interface, volume_uuid, volume_tr); SOF_MODULE_INIT(volume, sys_comp_module_volume_interface_init); #if CONFIG_COMP_GAIN -static struct module_interface gain_interface = { - .init = volume_init, +static const struct module_interface gain_interface = { + .init = volume_init, .prepare = volume_prepare, .process_audio_stream = volume_process, .set_configuration = volume_set_config, diff --git a/src/audio/volume/volume.h b/src/audio/volume/volume.h index 856c27568d84..140ec3e7af2f 100644 --- a/src/audio/volume/volume.h +++ b/src/audio/volume/volume.h @@ -134,7 +134,7 @@ typedef void (*vol_scale_func)(struct processing_module *mod, struct input_strea /** * \brief volume interface for function getting nearest zero crossing frame */ -typedef uint32_t (*vol_zc_func)(const struct audio_stream __sparse_cache *source, +typedef uint32_t (*vol_zc_func)(const struct audio_stream *source, uint32_t frames, int64_t *prev_sum); /** @@ -205,7 +205,7 @@ struct comp_zc_func_map { * \param[in] cd Volume data structure. */ static inline vol_scale_func vol_get_processing_function(struct comp_dev *dev, - struct comp_buffer __sparse_cache *sinkb, + struct comp_buffer *sinkb, struct vol_data *cd) { int i; diff --git a/src/audio/volume/volume_generic.c b/src/audio/volume/volume_generic.c index 966f62b7da34..30498bc992eb 100644 --- a/src/audio/volume/volume_generic.c +++ b/src/audio/volume/volume_generic.c @@ -61,8 +61,8 @@ static void vol_s24_to_s24(struct processing_module *mod, struct input_stream_bu uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t vol; int32_t *x, *x0; int32_t *y, *y0; @@ -110,8 +110,8 @@ static void vol_passthrough_s24_to_s24(struct processing_module *mod, struct output_stream_buffer *bsink, uint32_t frames, uint32_t attenuation) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *x; int32_t *y; int nmax, n; @@ -153,8 +153,8 @@ static void vol_s32_to_s32(struct processing_module *mod, struct input_stream_bu uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t vol; int32_t *x, *x0; int32_t *y, *y0; @@ -205,8 +205,8 @@ static void vol_passthrough_s32_to_s32(struct processing_module *mod, struct output_stream_buffer *bsink, uint32_t frames, uint32_t attenuation) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *x; int32_t *y; int nmax, n; @@ -247,8 +247,8 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t vol; int16_t *x, *x0; int16_t *y, *y0; @@ -296,8 +296,8 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, struct output_stream_buffer *bsink, uint32_t frames, uint32_t attenuation) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int16_t *x; int16_t *y; int nmax, n; diff --git a/src/audio/volume/volume_generic_with_peakvol.c b/src/audio/volume/volume_generic_with_peakvol.c index fb0cff0bee3a..0ef720d78665 100644 --- a/src/audio/volume/volume_generic_with_peakvol.c +++ b/src/audio/volume/volume_generic_with_peakvol.c @@ -57,8 +57,8 @@ static void vol_s24_to_s24(struct processing_module *mod, struct input_stream_bu uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t vol; int32_t *x, *x0; int32_t *y, *y0; @@ -112,8 +112,8 @@ static void vol_passthrough_s24_to_s24(struct processing_module *mod, uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *x, *x0; int32_t *y, *y0; int nmax, n, i, j; @@ -166,8 +166,8 @@ static void vol_s32_to_s32(struct processing_module *mod, struct input_stream_bu uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t vol; int32_t *x, *x0; int32_t *y, *y0; @@ -224,8 +224,8 @@ static void vol_passthrough_s32_to_s32(struct processing_module *mod, uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *x, *x0; int32_t *y, *y0; int nmax, n, i, j; @@ -280,8 +280,8 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t vol; int16_t *x, *x0; int16_t *y, *y0; @@ -336,8 +336,8 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *x, *x0; int32_t *y, *y0; int nmax, n, i, j; diff --git a/src/audio/volume/volume_hifi3.c b/src/audio/volume/volume_hifi3.c index 05746ab40f67..e32b8551c775 100644 --- a/src/audio/volume/volume_hifi3.c +++ b/src/audio/volume/volume_hifi3.c @@ -61,8 +61,8 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); ae_f32x2 out_sample = AE_ZERO32(); ae_f32x2 volume = AE_ZERO32(); @@ -147,8 +147,8 @@ static void vol_passthrough_s24_to_s24_s32(struct processing_module *mod, struct output_stream_buffer *bsink, uint32_t frames, uint32_t attenuation) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); int i, n, m; ae_valign inu = AE_ZALIGN64(); @@ -198,8 +198,8 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); ae_f32x2 out_sample = AE_ZERO32(); ae_f32x2 volume = AE_ZERO32(); @@ -289,8 +289,8 @@ static void vol_passthrough_s32_to_s24_s32(struct processing_module *mod, struct output_stream_buffer *bsink, uint32_t frames, uint32_t attenuation) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); int i, n, m; ae_valign inu = AE_ZALIGN64(); @@ -339,8 +339,8 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 volume0 = AE_ZERO32(); ae_f32x2 volume1 = AE_ZERO32(); ae_f32x2 out_sample0 = AE_ZERO32(); @@ -436,8 +436,8 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, struct output_stream_buffer *bsink, uint32_t frames, uint32_t attenuation) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f16x4 in_sample = AE_ZERO16(); int i, n, m; ae_valign inu = AE_ZALIGN64(); diff --git a/src/audio/volume/volume_hifi3_with_peakvol.c b/src/audio/volume/volume_hifi3_with_peakvol.c index 5d0ff31b0385..9bda00a27bc7 100644 --- a/src/audio/volume/volume_hifi3_with_peakvol.c +++ b/src/audio/volume/volume_hifi3_with_peakvol.c @@ -41,8 +41,8 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); ae_f32x2 out_sample = AE_ZERO32(); ae_f32x2 volume = AE_ZERO32(); @@ -116,8 +116,8 @@ static void vol_passthrough_s24_to_s24_s32(struct processing_module *mod, uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); int channel, n, i, m; ae_f32 *in0 = (ae_f32 *)audio_stream_wrap(source, (char *)audio_stream_get_rptr(source) @@ -176,8 +176,8 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); ae_f32x2 out_sample = AE_ZERO32(); ae_f32x2 volume = AE_ZERO32(); @@ -252,8 +252,8 @@ static void vol_passthrough_s32_to_s24_s32(struct processing_module *mod, uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); int i, n, channel, m; const int channels_count = audio_stream_get_channels(sink); @@ -312,8 +312,8 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 volume = AE_ZERO32(); ae_f32x2 out_sample0 = AE_ZERO32(); ae_f16x4 in_sample = AE_ZERO16(); @@ -394,8 +394,8 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f16x4 in_sample = AE_ZERO16(); int i, n, channel, m; ae_f16 *in; diff --git a/src/audio/volume/volume_hifi4.c b/src/audio/volume/volume_hifi4.c index 880aef23f139..d0d114dcfc5d 100644 --- a/src/audio/volume/volume_hifi4.c +++ b/src/audio/volume/volume_hifi4.c @@ -61,8 +61,8 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); ae_f32x2 out_sample = AE_ZERO32(); ae_f32x2 volume = AE_ZERO32(); @@ -147,8 +147,8 @@ static void vol_passthrough_s24_to_s24_s32(struct processing_module *mod, struct output_stream_buffer *bsink, uint32_t frames, uint32_t attenuation) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); int i, n, m; ae_valign inu = AE_ZALIGN64(); @@ -198,8 +198,8 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); ae_f32x2 out_sample = AE_ZERO32(); ae_f32x2 volume = AE_ZERO32(); @@ -289,8 +289,8 @@ static void vol_passthrough_s32_to_s24_s32(struct processing_module *mod, struct output_stream_buffer *bsink, uint32_t frames, uint32_t attenuation) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); int i, n, m; ae_valign inu = AE_ZALIGN64(); @@ -338,8 +338,8 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 volume0 = AE_ZERO32(); ae_f32x2 volume1 = AE_ZERO32(); ae_f32x2 out_sample0 = AE_ZERO32(); @@ -435,8 +435,8 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, struct output_stream_buffer *bsink, uint32_t frames, uint32_t attenuation) { - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f16x4 in_sample = AE_ZERO16(); int i, n, m; ae_valign inu = AE_ZALIGN64(); diff --git a/src/audio/volume/volume_hifi4_with_peakvol.c b/src/audio/volume/volume_hifi4_with_peakvol.c index df1eafff2788..cbb08e297b87 100644 --- a/src/audio/volume/volume_hifi4_with_peakvol.c +++ b/src/audio/volume/volume_hifi4_with_peakvol.c @@ -54,8 +54,8 @@ static void vol_s24_to_s24_s32(struct processing_module *mod, struct input_strea uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); ae_f32x2 out_sample = AE_ZERO32(); ae_f32x2 volume = AE_ZERO32(); @@ -150,8 +150,8 @@ static void vol_passthrough_s24_to_s24_s32(struct processing_module *mod, uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); int i, n, m; @@ -217,8 +217,8 @@ static void vol_s32_to_s24_s32(struct processing_module *mod, struct input_strea uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); ae_f32x2 out_sample = AE_ZERO32(); ae_f32x2 volume = AE_ZERO32(); @@ -321,8 +321,8 @@ static void vol_passthrough_s32_to_s24_s32(struct processing_module *mod, uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 in_sample = AE_ZERO32(); int i, n, m; ae_valign inu = AE_ZALIGN64(); @@ -385,8 +385,8 @@ static void vol_s16_to_s16(struct processing_module *mod, struct input_stream_bu uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f32x2 volume0 = AE_ZERO32(); ae_f32x2 volume1 = AE_ZERO32(); ae_f32x2 out_sample0 = AE_ZERO32(); @@ -501,8 +501,8 @@ static void vol_passthrough_s16_to_s16(struct processing_module *mod, uint32_t attenuation) { struct vol_data *cd = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; ae_f16x4 in_sample = AE_ZERO16(); int i, n, m; ae_valign inu = AE_ZALIGN64(); diff --git a/src/audio/volume/volume_ipc3.c b/src/audio/volume/volume_ipc3.c index c1378acbdd45..6ab48e33915b 100644 --- a/src/audio/volume/volume_ipc3.c +++ b/src/audio/volume/volume_ipc3.c @@ -37,7 +37,6 @@ LOG_MODULE_DECLARE(volume, CONFIG_SOF_LOG_LEVEL); void set_volume_process(struct vol_data *cd, struct comp_dev *dev, bool source_or_sink) { struct comp_buffer *bufferb; - struct comp_buffer __sparse_cache *buffer_c; if (source_or_sink) bufferb = list_first_item(&dev->bsource_list, @@ -46,10 +45,7 @@ void set_volume_process(struct vol_data *cd, struct comp_dev *dev, bool source_o bufferb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - buffer_c = buffer_acquire(bufferb); - cd->scale_vol = vol_get_processing_function(dev, buffer_c, cd); - - buffer_release(buffer_c); + cd->scale_vol = vol_get_processing_function(dev, bufferb, cd); } /** diff --git a/src/audio/volume/volume_ipc4.c b/src/audio/volume/volume_ipc4.c index 0ec4c4c275f0..b54e52c39a53 100644 --- a/src/audio/volume/volume_ipc4.c +++ b/src/audio/volume/volume_ipc4.c @@ -58,13 +58,10 @@ static int set_volume_ipc4(struct vol_data *cd, uint32_t const channel, cd->mvolume[channel] = 0; /* set muted as false*/ cd->muted[channel] = false; -#if CONFIG_COMP_VOLUME_WINDOWS_FADE + /* ATM there is support for the same ramp for all channels */ - if (curve_type == IPC4_AUDIO_CURVE_TYPE_WINDOWS_FADE) - cd->ramp_type = SOF_VOLUME_WINDOWS_FADE; - else - cd->ramp_type = SOF_VOLUME_WINDOWS_NO_FADE; -#endif + cd->ramp_type = ipc4_curve_type_convert((enum ipc4_curve_type)curve_type); + return 0; } @@ -89,8 +86,13 @@ static void init_ramp(struct vol_data *cd, uint32_t curve_duration, uint32_t tar /* In IPC4 driver sends curve_duration in hundred of ns - it should be * converted into ms value required by firmware */ - cd->initial_ramp = Q_MULTSR_32X32((int64_t)curve_duration, - Q_CONVERT_FLOAT(1.0 / 10000, 31), 0, 31, 0); + if (cd->ramp_type == SOF_VOLUME_WINDOWS_NO_FADE) { + cd->initial_ramp = 0; + cd->ramp_finished = true; + } else { + cd->initial_ramp = Q_MULTSR_32X32((int64_t)curve_duration, + Q_CONVERT_FLOAT(1.0 / 10000, 31), 0, 31, 0); + } if (!cd->initial_ramp) { /* In case when initial ramp time is equal to zero, vol_min and @@ -366,7 +368,6 @@ int volume_get_config(struct processing_module *mod, static int volume_params(struct processing_module *mod) { struct sof_ipc_stream_params *params = mod->stream_params; - struct comp_buffer __sparse_cache *sink_c, *source_c; struct comp_buffer *sinkb, *sourceb; struct comp_dev *dev = mod->dev; @@ -378,14 +379,10 @@ static int volume_params(struct processing_module *mod) /* volume component will only ever have 1 sink buffer */ sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sinkb); - ipc4_update_buffer_format(sink_c, &mod->priv.cfg.base_cfg.audio_fmt); - buffer_release(sink_c); + ipc4_update_buffer_format(sinkb, &mod->priv.cfg.base_cfg.audio_fmt); sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(sourceb); - ipc4_update_buffer_format(source_c, &mod->priv.cfg.base_cfg.audio_fmt); - buffer_release(source_c); + ipc4_update_buffer_format(sourceb, &mod->priv.cfg.base_cfg.audio_fmt); return 0; } diff --git a/src/drivers/imx/CMakeLists.txt b/src/drivers/imx/CMakeLists.txt index 874e8c012190..5fdc480b76c2 100644 --- a/src/drivers/imx/CMakeLists.txt +++ b/src/drivers/imx/CMakeLists.txt @@ -22,6 +22,10 @@ if(CONFIG_IMX_SDMA) endif() endif() +if(CONFIG_IMX_MICFIL) + add_local_sources(sof micfil.c) +endif() + if(CONFIG_IMX_INTERRUPT_IRQSTEER) add_local_sources(sof interrupt-irqsteer.c) elseif(CONFIG_IMX_INTERRUPT_GENERIC) diff --git a/src/drivers/imx/Kconfig b/src/drivers/imx/Kconfig index a74cc8e552e4..7874c72c096b 100644 --- a/src/drivers/imx/Kconfig +++ b/src/drivers/imx/Kconfig @@ -21,6 +21,15 @@ config IMX_ESAI help Select this to enable support for i.MX ESAI IP. +config IMX_MICFIL + bool "i.MX MICFIL PDM driver" + default n + depends on IMX + help + Select this to enable support for i.MX MICFIL PDM IP. This block implements + the required digital interface to provide a 24-bits audio signal from a PDM + microphone bitstream in a configurable output sampling rate + config IMX_INTERRUPT_IRQSTEER bool default n @@ -36,7 +45,7 @@ config IMX_INTERRUPT_GENERIC It enables NXP platforms-specific features. config HAVE_SDMA_FIRMWARE - bool + bool "Enable SDMA firmware load" default n help Select this to load SDMA firmware to enable additional functionality diff --git a/src/drivers/imx/micfil.c b/src/drivers/imx/micfil.c new file mode 100644 index 000000000000..20c96b9eb4a8 --- /dev/null +++ b/src/drivers/imx/micfil.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright 2023 NXP +// +// Author: Daniel Baluta + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(micfil_dai, CONFIG_SOF_LOG_LEVEL); + +/* dd400475-35d7-4045-ab03-0c34957d7a08 */ +DECLARE_SOF_UUID("micfil-dai", micfil_uuid, 0xdd400475, 0x35d7, 0x4045, + 0xab, 0x03, 0x0c, 0x34, 0x95, 0x7d, 0x7a, 0x08); + +DECLARE_TR_CTX(micfil_tr, SOF_UUID(micfil_uuid), LOG_LEVEL_INFO); + +#define MICFIL_OSR_DEFAULT 16 +/* set default gain to 2 */ +#define MICFIL_DEFAULT_ADJ_RANGE 0x22222222 +#define MICFIL_CLK_ROOT 24576000 + +enum micfil_quality { + QUALITY_HIGH, + QUALITY_MEDIUM, + QUALITY_LOW, + QUALITY_VLOW0, + QUALITY_VLOW1, + QUALITY_VLOW2, +}; + +static void micfil_reset(struct dai *dai) +{ + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_MDIS, 0); + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_SRES, MICFIL_CTRL1_SRES); + dai_update_bits(dai, REG_MICFIL_STAT, 0xff, 0xff); +} + +static int micfil_get_hw_params(struct dai *dai, + struct sof_ipc_stream_params *params, int dir) +{ + struct micfil_pdata *micfil = dai_get_drvdata(dai); + + dai_err(dai, "micfil_get_hw_params()"); + + params->rate = micfil->params.pdm_rate; + params->channels = micfil->params.pdm_ch; + params->buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED; + params->frame_fmt = SOF_IPC_FRAME_S32_LE; + + return 0; +} + +static int micfil_set_quality(struct dai *dai) +{ + struct micfil_pdata *micfil = dai_get_drvdata(dai); + int qsel; + + switch (micfil->quality) { + case QUALITY_HIGH: + qsel = MICFIL_QSEL_HIGH_QUALITY; + break; + case QUALITY_MEDIUM: + qsel = MICFIL_QSEL_MEDIUM_QUALITY; + break; + case QUALITY_LOW: + qsel = MICFIL_QSEL_LOW_QUALITY; + break; + case QUALITY_VLOW0: + qsel = MICFIL_QSEL_VLOW0_QUALITY; + break; + case QUALITY_VLOW1: + qsel = MICFIL_QSEL_VLOW1_QUALITY; + break; + case QUALITY_VLOW2: + qsel = MICFIL_QSEL_VLOW2_QUALITY; + break; + default: + dai_err(dai, "MICFIL: invalid quality mode %d", micfil->quality); + return -EINVAL; + } + + dai_update_bits(dai, REG_MICFIL_CTRL2, MICFIL_CTRL2_QSEL, + MICFIL_CTRL2_QSEL_BITS(qsel)); + + return 0; +} + +/* get_pdm_clk - computes the product between k-factor and PDM_CLK rate + * @param dai, SOF DAI struct + * @param rate, output sampling rate + * + * PDM_CLK depends on Quality Mode, output sampling rate and quality + * mode + */ +static unsigned int micfil_get_pdm_clk(struct dai *dai, int rate) +{ + unsigned int osr; + unsigned int qsel; + unsigned int ctrl2_reg; + unsigned int pdm_clk = 0; + + ctrl2_reg = dai_read(dai, REG_MICFIL_CTRL2); + osr = 16 - ((ctrl2_reg & MICFIL_CTRL2_CICOSR) >> MICFIL_CTRL2_CICOSR_SHIFT); + qsel = (ctrl2_reg & MICFIL_CTRL2_QSEL) >> MICFIL_CTRL2_QSEL_SHIFT; + + /* See Quality modes chapter in MICFIL documentation */ + switch (qsel) { + case MICFIL_QSEL_HIGH_QUALITY: + pdm_clk = rate * 8 * osr / 2; /* kfactor = 0.5 */ + break; + case MICFIL_QSEL_MEDIUM_QUALITY: + case MICFIL_QSEL_VLOW0_QUALITY: + pdm_clk = rate * 4 * osr; /* kfactor = 1 */ + break; + case MICFIL_QSEL_LOW_QUALITY: + case MICFIL_QSEL_VLOW1_QUALITY: + pdm_clk = rate * 2 * osr * 2; /* kfactor = 2 */ + break; + case MICFIL_QSEL_VLOW2_QUALITY: + pdm_clk = rate * osr; /* kfactor = 4 */ + break; + default: + break; + } + + return pdm_clk; +} + +static int micfil_get_clk_div(struct dai *dai, int rate) +{ + unsigned int pdm_clk; + + pdm_clk = micfil_get_pdm_clk(dai, rate); + if (!pdm_clk) + return -EINVAL; + + /* + * + * See: Clock divider chapter from micfil documentation + * PDM_CLK rate = MICFIL_CLK_ROOT rate / (2 * K * CLKDIV) + * + * this means that if we want to compute CLKDIV then: + * CLKDIV = MICFIL_CLK_ROOT rate / (PDM_CLK rate * K * 2) + * + * micfil_get_pdm_clk function returns K * PDM_CLK rate + */ + return MICFIL_CLK_ROOT / (pdm_clk * 2); +} + +static int micfil_set_clock_params(struct dai *dai, int rate) +{ + int clk_div; + + dai_update_bits(dai, REG_MICFIL_CTRL2, MICFIL_CTRL2_CICOSR, + MICFIL_CTRL2_CICOSR_BITS(MICFIL_OSR_DEFAULT)); + + clk_div = micfil_get_clk_div(dai, rate); + if (clk_div < 0) + return clk_div; + + dai_update_bits(dai, REG_MICFIL_CTRL2, MICFIL_CTRL2_CLKDIV, + MICFIL_CTRL2_CLKDIV_BITS(clk_div)); + + return 0; +} + +static int micfil_set_config(struct dai *dai, struct ipc_config_dai *common_config, + const void *spec_config) +{ + int i, ret; + unsigned int val = 0; + struct micfil_pdata *micfil = dai_get_drvdata(dai); + const struct sof_ipc_dai_config *config = spec_config; + + micfil->params = config->micfil; + + dai_info(dai, "micfil_set_config() dai_idx %d channels %d sampling_freq %d", + common_config->dai_index, micfil->params.pdm_ch, micfil->params.pdm_rate); + + /* disable the module */ + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_PDMIEN, 0); + + micfil_set_quality(dai); + + /* set default gain to 2 */ + dai_write(dai, REG_MICFIL_OUT_CTRL, MICFIL_DEFAULT_ADJ_RANGE); + + /* set DC Remover in bypass mode */ + for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) + val |= MICFIL_DC_BYPASS << MICFIL_DC_CHX_SHIFT(i); + dai_update_bits(dai, REG_MICFIL_DC_CTRL, MICFIL_DC_CTRL_CONFIG, val); + + /* FIFO WMK */ + dai_update_bits(dai, REG_MICFIL_FIFO_CTRL, MICFIL_FIFO_CTRL_FIFOWMK, + MICFIL_FIFO_CTRL_FIFOWMK_BITS(31)); + + /* enable channels */ + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_CHNEN, + ((1 << micfil->params.pdm_ch) - 1)); + + ret = micfil_set_clock_params(dai, micfil->params.pdm_rate); + if (ret < 0) + return ret; + + return 0; +} + +static int micfil_get_handshake(struct dai *dai, int direction, int stream_id) +{ + return dai->plat_data.fifo[SOF_IPC_STREAM_CAPTURE].handshake; +} + +static int micfil_get_fifo(struct dai *dai, int direction, int stream_id) +{ + return dai->plat_data.fifo[SOF_IPC_STREAM_CAPTURE].offset; +} + +static int micfil_get_fifo_depth(struct dai *dai, int direction) +{ + return dai->plat_data.fifo[SOF_IPC_STREAM_CAPTURE].depth; +} + +static void micfil_start(struct dai *dai) +{ + dai_info(dai, "micfil_start()"); + + micfil_reset(dai); + + /* DMA Interrupt Selection - DISEL bits + * 00 - DMA and IRQ disabled + * 01 - DMA req enabled + * 10 - IRQ enabled + * 11 - reserved + */ + dai_update_bits(dai, REG_MICFIL_CTRL1, + MICFIL_CTRL1_DISEL, + MICFIL_CTRL1_DISEL_BITS(MICFIL_CTRL1_DISEL_DMA)); + + /* Enable the module */ + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_PDMIEN, MICFIL_CTRL1_PDMIEN); +} + +static void micfil_stop(struct dai *dai) +{ + dai_info(dai, "micfil_stop()"); + + /* Disable the module */ + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_PDMIEN, 0); + + dai_update_bits(dai, REG_MICFIL_CTRL1, MICFIL_CTRL1_DISEL, + MICFIL_CTRL1_DISEL_BITS(MICFIL_CTRL1_DISEL_DISABLE)); +} + +static int micfil_trigger(struct dai *dai, int cmd, int direction) +{ + dai_info(dai, "micfil_trigger() cmd %d dir %d", cmd, direction); + + switch (cmd) { + case COMP_TRIGGER_START: + case COMP_TRIGGER_RELEASE: + micfil_start(dai); + break; + case COMP_TRIGGER_STOP: + case COMP_TRIGGER_PAUSE: + micfil_stop(dai); + case COMP_TRIGGER_PRE_START: + case COMP_TRIGGER_PRE_RELEASE: + break; + default: + dai_err(dai, "MICFIL: invalid trigger cmd %d", cmd); + return -EINVAL; + } + + return 0; +} + +static int micfil_probe(struct dai *dai) +{ + struct micfil_pdata *micfil; + + dai_info(dai, "micfil_probe()"); + + micfil = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*micfil)); + if (!micfil) { + dai_err(dai, "micfil probe failed"); + return -ENOMEM; + } + + micfil->quality = QUALITY_VLOW0; + + dai_set_drvdata(dai, micfil); + + return 0; +} + +static int micfil_remove(struct dai *dai) +{ + struct micfil_pdata *micfil = dai_get_drvdata(dai); + + dai_info(dai, "micfil_remove()"); + + rfree(micfil); + dai_set_drvdata(dai, NULL); + + return 0; +} + +const struct dai_driver micfil_driver = { + .type = SOF_DAI_IMX_MICFIL, + .uid = SOF_UUID(micfil_uuid), + .tctx = &micfil_tr, + .dma_dev = DMA_DEV_MICFIL, + .ops = { + .trigger = micfil_trigger, + .set_config = micfil_set_config, + .get_hw_params = micfil_get_hw_params, + .get_handshake = micfil_get_handshake, + .get_fifo = micfil_get_fifo, + .get_fifo_depth = micfil_get_fifo_depth, + .probe = micfil_probe, + .remove = micfil_remove, + }, +}; diff --git a/src/drivers/imx/sai.c b/src/drivers/imx/sai.c index df9690eb8d7c..c6e30f791fb2 100644 --- a/src/drivers/imx/sai.c +++ b/src/drivers/imx/sai.c @@ -229,6 +229,7 @@ static inline int sai_set_config(struct dai *dai, struct ipc_config_dai *common_ uint32_t val_cr2 = 0, val_cr4 = 0, val_cr5 = 0; uint32_t mask_cr2 = 0, mask_cr4 = 0, mask_cr5 = 0; uint32_t clk_div; + bool tdm_enable; struct sai_pdata *sai = dai_get_drvdata(dai); sai->config = *config; @@ -251,6 +252,14 @@ static inline int sai_set_config(struct dai *dai, struct ipc_config_dai *common_ clk_div = (config->sai.mclk_rate / config->sai.bclk_rate / 2) - 1; } + /* TDM mode is enabled only when fmt is dsp_a or dsp_b and + * we can have from 1 to 32 channels. + * for any other formats we assume I2S like interface where + * audio frames have 2 channels, even for mono scenario. The + * second channel will be masked out. + */ + tdm_enable = false; + switch (config->format & SOF_DAI_FMT_FORMAT_MASK) { case SOF_DAI_FMT_I2S: /* @@ -285,6 +294,7 @@ static inline int sai_set_config(struct dai *dai, struct ipc_config_dai *common_ val_cr2 |= REG_SAI_CR2_BCP; val_cr4 |= REG_SAI_CR4_FSE; val_cr4 |= REG_SAI_CR4_SYWD(1U); + tdm_enable = true; break; case SOF_DAI_FMT_DSP_B: /* @@ -293,6 +303,7 @@ static inline int sai_set_config(struct dai *dai, struct ipc_config_dai *common_ */ val_cr2 |= REG_SAI_CR2_BCP; val_cr4 |= REG_SAI_CR4_SYWD(1U); + tdm_enable = true; break; case SOF_DAI_FMT_PDM: val_cr2 |= REG_SAI_CR2_BCP; @@ -355,6 +366,7 @@ static inline int sai_set_config(struct dai *dai, struct ipc_config_dai *common_ return -EINVAL; } +#ifndef CONFIG_IMX8ULP switch (sai->params.tdm_slot_width) { case 8: val_cr4 |= REG_SAI_CR4_FPACK_8; @@ -365,8 +377,14 @@ static inline int sai_set_config(struct dai *dai, struct ipc_config_dai *common_ default: break; } +#endif + + if (tdm_enable) + val_cr4 |= REG_SAI_CR4_FRSZ(sai->params.tdm_slots); + else + val_cr4 |= REG_SAI_CR4_FRSZ( + (sai->params.tdm_slots == 1) ? 2 : sai->params.tdm_slots); - val_cr4 |= REG_SAI_CR4_FRSZ(sai->params.tdm_slots); val_cr4 |= REG_SAI_CR4_CHMOD; val_cr4 |= REG_SAI_CR4_MF; diff --git a/src/idc/idc.c b/src/idc/idc.c index 9a630ca6fbf7..860f427a551d 100644 --- a/src/idc/idc.c +++ b/src/idc/idc.c @@ -227,8 +227,8 @@ static int idc_prepare(uint32_t comp_id) dev = ipc_dev->cd; - /* we're running on different core, so allocate our own task */ - if (!dev->task) { + /* we're running LL on different core, so allocate our own task */ + if (!dev->task && dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) { /* allocate task for shared component */ dev->task = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*dev->task)); diff --git a/src/idc/zephyr_idc.c b/src/idc/zephyr_idc.c index 36b373e1aad8..9c33128349f4 100644 --- a/src/idc/zephyr_idc.c +++ b/src/idc/zephyr_idc.c @@ -63,7 +63,8 @@ static void idc_handler(struct k_p4wq_work *work) int payload = -1; k_spinlock_key_t key; - sys_cache_data_flush_range(msg, sizeof(*msg)); + /* A message is received from another core, invalidate local cache */ + sys_cache_data_invd_range(msg, sizeof(*msg)); if (msg->size == sizeof(int)) { const int idc_handler_memcpy_err __unused = @@ -123,12 +124,14 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode) msg->payload, msg->size); assert(!idc_send_memcpy_err); + /* Sending a message to another core, write back local payload cache */ sys_cache_data_flush_range(payload->data, MIN(sizeof(payload->data), msg->size)); } /* Temporarily store sender core ID */ msg_cp->core = cpu_get_id(); + /* Sending a message to another core, write back local message cache */ sys_cache_data_flush_range(msg_cp, sizeof(*msg_cp)); k_p4wq_submit(q_zephyr_idc + target_cpu, work); diff --git a/src/include/ipc/dai-imx.h b/src/include/ipc/dai-imx.h index bc478f0c97ad..5f9fc4dce837 100644 --- a/src/include/ipc/dai-imx.h +++ b/src/include/ipc/dai-imx.h @@ -54,4 +54,11 @@ struct sof_ipc_dai_sai_params { uint16_t reserved2; /* alignment */ } __attribute__((packed, aligned(4))); + +/* MICFIL Configuration Request - SOF_IPC_DAI_MICFIL_CONFIG */ +struct sof_ipc_dai_micfil_params { + uint32_t pdm_rate; + uint32_t pdm_ch; +} __attribute__((packed, aligned(4))); + #endif /* __IPC_DAI_IMX_H__ */ diff --git a/src/include/ipc/dai.h b/src/include/ipc/dai.h index b0ea6d7f6af5..37bd91fa6c29 100644 --- a/src/include/ipc/dai.h +++ b/src/include/ipc/dai.h @@ -92,7 +92,8 @@ enum sof_ipc_dai_type { SOF_DAI_MEDIATEK_AFE, /**< Mtk AFE */ SOF_DAI_AMD_HS, /**< Amd HS */ SOF_DAI_AMD_SP_VIRTUAL, /** #include #include -#include +#include /* Reports current ROM/FW status. */ struct ipc4_fw_status_reg { diff --git a/src/include/ipc4/header.h b/src/include/ipc4/header.h index 4a91b1a8cb13..5abef50342b0 100644 --- a/src/include/ipc4/header.h +++ b/src/include/ipc4/header.h @@ -171,4 +171,48 @@ struct ipc4_message_reply { } extension; } __attribute((packed, aligned(4))); +#define SOF_IPC4_SWITCH_CONTROL_PARAM_ID 200 +#define SOF_IPC4_ENUM_CONTROL_PARAM_ID 201 +#define SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL ((uint32_t)(0xA15A << 16)) + +/** + * struct sof_ipc4_ctrl_value_chan: generic channel mapped value data + * @channel: Channel ID + * @value: control value + */ +struct sof_ipc4_ctrl_value_chan { + uint32_t channel; + uint32_t value; +} __attribute((packed, aligned(4))); + +/** + * struct sof_ipc4_control_msg_payload - IPC payload for kcontrol parameters + * @id: unique id of the control + * @num_elems: Number of elememnts in the chanv array + * @reserved: reserved for future use, must be set to 0 + * @chanv: channel ID and value array + */ +struct sof_ipc4_control_msg_payload { + uint16_t id; + uint16_t num_elems; + uint32_t reserved[4]; + struct sof_ipc4_ctrl_value_chan chanv[]; +} __attribute((packed, aligned(4))); + +/** + * struct sof_ipc4_notify_module_data - payload for module notification + * @instance_id: instance ID of the originator module of the notification + * @module_id: module ID of the originator of the notification + * @event_id: module specific event id + * @event_data_size: Size of the @event_data (if any) in bytes + * @event_data: Optional notification data, module and notification dependent + */ +struct sof_ipc4_notify_module_data { + uint16_t instance_id; + uint16_t module_id; + uint32_t event_id; + uint32_t event_data_size; + uint8_t event_data[]; +} __attribute((packed, aligned(4))); + #endif diff --git a/src/include/ipc4/kpb.h b/src/include/ipc4/kpb.h index ad558bc4ac25..0c56942313c3 100644 --- a/src/include/ipc4/kpb.h +++ b/src/include/ipc4/kpb.h @@ -19,4 +19,16 @@ struct ipc4_kpb_module_cfg { struct ipc4_base_module_cfg base_cfg; } __packed __aligned(4); + +/* For the sake of compatibility, do not change IDs, only add new ones.*/ +enum ipc4_kpb_module_config_params { + /*! Configure the module ID's which would be part of the Fast mode tasks */ + KP_BUF_CFG_FM_MODULE = 1, + /* Mic selector for client - sets microphone id for real time sink mic selector + * IPC4-compatible ID - please do not change the number + */ + KP_BUF_CLIENT_MIC_SELECT = 11, +}; + #endif + diff --git a/src/include/ipc4/logging.h b/src/include/ipc4/logging.h index 55f4a5edbffc..bbb913677231 100644 --- a/src/include/ipc4/logging.h +++ b/src/include/ipc4/logging.h @@ -8,10 +8,20 @@ #define SOF_IPC4_LOGGING_MTRACE_PAGE_SIZE 0x1000 +#if CONFIG_LIBRARY +static inline int ipc4_logging_enable_logs(bool first_block, + bool last_block, + uint32_t data_offset_or_size, + const char *data) +{ + return 0; +} +#else int ipc4_logging_enable_logs(bool first_block, bool last_block, uint32_t data_offset_or_size, const char *data); +#endif int ipc4_logging_shutdown(void); diff --git a/src/include/ipc4/mixin_mixout.h b/src/include/ipc4/mixin_mixout.h index f44ef97e0b37..49184e2aa51b 100644 --- a/src/include/ipc4/mixin_mixout.h +++ b/src/include/ipc4/mixin_mixout.h @@ -105,15 +105,15 @@ struct ipc4_mixer_mode_config { /** * \brief normal mode mixin_mixout processing function interface */ -typedef void (*normal_mix_func)(struct audio_stream __sparse_cache *sink, int32_t start_frame, +typedef void (*normal_mix_func)(struct audio_stream *sink, int32_t start_frame, int32_t mixed_frames, - const struct audio_stream __sparse_cache *source, + const struct audio_stream *source, int32_t frame_count, uint16_t gain); /** * \brief mixin_mixout mute processing function interface */ -typedef void (*mute_func) (struct audio_stream __sparse_cache *stream, int32_t channel_index, +typedef void (*mute_func) (struct audio_stream *stream, int32_t channel_index, int32_t start_frame, int32_t mixed_frames, int32_t frame_count); /** diff --git a/src/include/ipc4/module.h b/src/include/ipc4/module.h index cf5f60b453bc..86279567cb85 100644 --- a/src/include/ipc4/module.h +++ b/src/include/ipc4/module.h @@ -36,6 +36,9 @@ #define SOF_IPC4_DST_QUEUE_ID_BITFIELD_SIZE 3 #define SOF_IPC4_SRC_QUEUE_ID_BITFIELD_SIZE 3 +/* Special large_param_id values */ +#define VENDOR_CONFIG_PARAM 0xFF + enum sof_ipc4_module_type { SOF_IPC4_MOD_INIT_INSTANCE = 0, SOF_IPC4_MOD_CONFIG_GET = 1, @@ -51,6 +54,18 @@ enum sof_ipc4_module_type { SOF_IPC4_MOD_DELETE_INSTANCE = 11, }; +/* + * Structs for Vendor Config Set + */ + +union ipc4_extended_param_id { + uint32_t full; + struct{ + uint32_t parameter_type : 8; + uint32_t parameter_instance : 24; + } part; +} __packed __aligned(4); + /* * Host Driver sends this message to create a new module instance. */ @@ -408,7 +423,7 @@ struct ipc4_module_load_library { } __packed __aligned(4); #define IPC4_COMP_ID(x, y) ((y) << 16 | (x)) -#define IPC4_MOD_ID(x) ((x) & 0xffff) +#define IPC4_MOD_ID(x) (IS_ENABLED(CONFIG_IPC_MAJOR_4) ? ((x) & 0xffff) : 0) #define IPC4_INST_ID(x) ((x) >> 16) #define IPC4_SRC_QUEUE_ID(x) ((x) & 0xffff) #define IPC4_SINK_QUEUE_ID(x) (((x) >> 16) & 0xffff) diff --git a/src/include/sof/audio/aria/aria.h b/src/include/sof/audio/aria/aria.h index 64e34e09c86b..6718f84a72da 100644 --- a/src/include/sof/audio/aria/aria.h +++ b/src/include/sof/audio/aria/aria.h @@ -48,14 +48,14 @@ * \brief aria get data function interface */ typedef void (*aria_get_data_func)(struct processing_module *mod, - struct audio_stream __sparse_cache *sink, int frames); + struct audio_stream *sink, int frames); struct aria_data; /** * \brief Aria gain processing function */ void aria_algo_calc_gain(struct aria_data *cd, size_t gain_idx, - struct audio_stream __sparse_cache *source, int frames); + struct audio_stream *source, int frames); aria_get_data_func aria_algo_get_data_func(struct processing_module *mod); diff --git a/src/include/sof/audio/audio_stream.h b/src/include/sof/audio/audio_stream.h index ecfc63432d86..49f3dab09245 100644 --- a/src/include/sof/audio/audio_stream.h +++ b/src/include/sof/audio/audio_stream.h @@ -104,148 +104,146 @@ struct audio_stream { struct sof_audio_stream_params runtime_stream_params; }; -static inline void *audio_stream_get_rptr(const struct audio_stream __sparse_cache *buf) +static inline void *audio_stream_get_rptr(const struct audio_stream *buf) { return buf->r_ptr; } -static inline void *audio_stream_get_wptr(const struct audio_stream __sparse_cache *buf) +static inline void *audio_stream_get_wptr(const struct audio_stream *buf) { return buf->w_ptr; } -static inline void *audio_stream_get_end_addr(const struct audio_stream __sparse_cache *buf) +static inline void *audio_stream_get_end_addr(const struct audio_stream *buf) { return buf->end_addr; } -static inline void *audio_stream_get_addr(const struct audio_stream __sparse_cache *buf) +static inline void *audio_stream_get_addr(const struct audio_stream *buf) { return buf->addr; } -static inline uint32_t audio_stream_get_size(const struct audio_stream __sparse_cache *buf) +static inline uint32_t audio_stream_get_size(const struct audio_stream *buf) { return buf->size; } -static inline uint32_t audio_stream_get_avail(const struct audio_stream __sparse_cache *buf) +static inline uint32_t audio_stream_get_avail(const struct audio_stream *buf) { return buf->avail; } -static inline uint32_t audio_stream_get_free(const struct audio_stream __sparse_cache *buf) +static inline uint32_t audio_stream_get_free(const struct audio_stream *buf) { return buf->free; } -static inline enum sof_ipc_frame audio_stream_get_frm_fmt( - const struct audio_stream __sparse_cache *buf) +static inline enum sof_ipc_frame audio_stream_get_frm_fmt(const struct audio_stream *buf) { return buf->runtime_stream_params.frame_fmt; } -static inline enum sof_ipc_frame audio_stream_get_valid_fmt( - const struct audio_stream __sparse_cache *buf) +static inline enum sof_ipc_frame audio_stream_get_valid_fmt(const struct audio_stream *buf) { return buf->runtime_stream_params.valid_sample_fmt; } -static inline uint32_t audio_stream_get_rate(const struct audio_stream __sparse_cache *buf) +static inline uint32_t audio_stream_get_rate(const struct audio_stream *buf) { return buf->runtime_stream_params.rate; } -static inline uint32_t audio_stream_get_channels(const struct audio_stream __sparse_cache *buf) +static inline uint32_t audio_stream_get_channels(const struct audio_stream *buf) { return buf->runtime_stream_params.channels; } -static inline bool audio_stream_get_underrun(const struct audio_stream __sparse_cache *buf) +static inline bool audio_stream_get_underrun(const struct audio_stream *buf) { return buf->runtime_stream_params.underrun_permitted; } -static inline uint32_t audio_stream_get_buffer_fmt(const struct audio_stream __sparse_cache *buf) +static inline uint32_t audio_stream_get_buffer_fmt(const struct audio_stream *buf) { return buf->runtime_stream_params.buffer_fmt; } -static inline bool audio_stream_get_overrun(const struct audio_stream __sparse_cache *buf) +static inline bool audio_stream_get_overrun(const struct audio_stream *buf) { return buf->runtime_stream_params.overrun_permitted; } -static inline void audio_stream_set_rptr(struct audio_stream __sparse_cache *buf, void *val) +static inline void audio_stream_set_rptr(struct audio_stream *buf, void *val) { buf->r_ptr = val; } -static inline void audio_stream_set_wptr(struct audio_stream __sparse_cache *buf, void *val) +static inline void audio_stream_set_wptr(struct audio_stream *buf, void *val) { buf->w_ptr = val; } -static inline void audio_stream_set_end_addr(struct audio_stream __sparse_cache *buf, void *val) +static inline void audio_stream_set_end_addr(struct audio_stream *buf, void *val) { buf->end_addr = val; } -static inline void audio_stream_set_addr(struct audio_stream __sparse_cache *buf, void *val) +static inline void audio_stream_set_addr(struct audio_stream *buf, void *val) { buf->addr = val; } -static inline void audio_stream_set_size(struct audio_stream __sparse_cache *buf, uint32_t val) +static inline void audio_stream_set_size(struct audio_stream *buf, uint32_t val) { buf->size = val; } -static inline void audio_stream_set_avail(struct audio_stream __sparse_cache *buf, uint32_t val) +static inline void audio_stream_set_avail(struct audio_stream *buf, uint32_t val) { buf->avail = val; } -static inline void audio_stream_set_free(struct audio_stream __sparse_cache *buf, uint32_t val) +static inline void audio_stream_set_free(struct audio_stream *buf, uint32_t val) { buf->free = val; } -static inline void audio_stream_set_frm_fmt(struct audio_stream __sparse_cache *buf, +static inline void audio_stream_set_frm_fmt(struct audio_stream *buf, enum sof_ipc_frame val) { buf->runtime_stream_params.frame_fmt = val; } -static inline void audio_stream_set_valid_fmt(struct audio_stream __sparse_cache *buf, +static inline void audio_stream_set_valid_fmt(struct audio_stream *buf, enum sof_ipc_frame val) { buf->runtime_stream_params.valid_sample_fmt = val; } -static inline void audio_stream_set_rate(struct audio_stream __sparse_cache *buf, uint32_t val) +static inline void audio_stream_set_rate(struct audio_stream *buf, uint32_t val) { buf->runtime_stream_params.rate = val; } -static inline void audio_stream_set_channels(struct audio_stream __sparse_cache *buf, uint16_t val) +static inline void audio_stream_set_channels(struct audio_stream *buf, uint16_t val) { buf->runtime_stream_params.channels = val; } -static inline void audio_stream_set_underrun(struct audio_stream __sparse_cache *buf, +static inline void audio_stream_set_underrun(struct audio_stream *buf, bool underrun_permitted) { buf->runtime_stream_params.underrun_permitted = underrun_permitted; } -static inline void audio_stream_set_overrun(struct audio_stream __sparse_cache *buf, +static inline void audio_stream_set_overrun(struct audio_stream *buf, bool overrun_permitted) { buf->runtime_stream_params.overrun_permitted = overrun_permitted; } -static inline void audio_stream_set_buffer_fmt(struct audio_stream __sparse_cache *buf, +static inline void audio_stream_set_buffer_fmt(struct audio_stream *buf, uint32_t buffer_fmt) { buf->runtime_stream_params.buffer_fmt = buffer_fmt; @@ -356,7 +354,7 @@ static inline void audio_stream_set_buffer_fmt(struct audio_stream __sparse_cach * @param params Parameters (frame format, rate, number of channels). * @return 0 if succeeded, error code otherwise. */ -static inline int audio_stream_set_params(struct audio_stream __sparse_cache *buffer, +static inline int audio_stream_set_params(struct audio_stream *buffer, struct sof_ipc_stream_params *params) { if (!params) @@ -374,7 +372,7 @@ static inline int audio_stream_set_params(struct audio_stream __sparse_cache *bu * @param buf Component buffer. * @return Period size in bytes. */ -static inline uint32_t audio_stream_frame_bytes(const struct audio_stream __sparse_cache *buf) +static inline uint32_t audio_stream_frame_bytes(const struct audio_stream *buf) { return get_frame_bytes(buf->runtime_stream_params.frame_fmt, buf->runtime_stream_params.channels); @@ -385,7 +383,7 @@ static inline uint32_t audio_stream_frame_bytes(const struct audio_stream __spar * @param buf Component buffer. * @return Size of sample in bytes. */ -static inline uint32_t audio_stream_sample_bytes(const struct audio_stream __sparse_cache *buf) +static inline uint32_t audio_stream_sample_bytes(const struct audio_stream *buf) { return get_sample_bytes(buf->runtime_stream_params.frame_fmt); } @@ -423,7 +421,7 @@ static inline uint32_t audio_stream_frame_align_get(const uint32_t byte_align, */ static inline void audio_stream_init_alignment_constants(const uint32_t byte_align, const uint32_t frame_align_req, - struct audio_stream __sparse_cache *stream) + struct audio_stream *stream) { uint32_t process_size; uint32_t frame_size = audio_stream_frame_bytes(stream); @@ -441,8 +439,7 @@ static inline void audio_stream_init_alignment_constants(const uint32_t byte_ali * @param frames Number of processing frames. * @return Period size in bytes. */ -static inline uint32_t audio_stream_period_bytes(const struct audio_stream __sparse_cache *buf, - uint32_t frames) +static inline uint32_t audio_stream_period_bytes(const struct audio_stream *buf, uint32_t frames) { return frames * audio_stream_frame_bytes(buf); } @@ -454,8 +451,7 @@ static inline uint32_t audio_stream_period_bytes(const struct audio_stream __spa * @param ptr Pointer * @return Pointer, adjusted if necessary. */ -static inline void *audio_stream_wrap(const struct audio_stream __sparse_cache *buffer, - void *ptr) +static inline void *audio_stream_wrap(const struct audio_stream *buffer, void *ptr) { if (ptr >= buffer->end_addr) ptr = (char *)buffer->addr + @@ -492,8 +488,7 @@ static inline void *cir_buf_wrap(void *ptr, void *buf_addr, void *buf_end) * @param ptr Pointer * @return Pointer, adjusted if necessary. */ -static inline void *audio_stream_rewind_wrap(const struct audio_stream __sparse_cache *buffer, - void *ptr) +static inline void *audio_stream_rewind_wrap(const struct audio_stream *buffer, void *ptr) { if (ptr < buffer->addr) ptr = (char *)buffer->end_addr - ((char *)buffer->addr - (char *)ptr); @@ -509,7 +504,7 @@ static inline void *audio_stream_rewind_wrap(const struct audio_stream __sparse_ * @return amount of data available for processing in bytes */ static inline uint32_t -audio_stream_get_avail_bytes(const struct audio_stream __sparse_cache *stream) +audio_stream_get_avail_bytes(const struct audio_stream *stream) { /* * In case of underrun-permitted stream, report buffer full instead of @@ -529,7 +524,7 @@ audio_stream_get_avail_bytes(const struct audio_stream __sparse_cache *stream) * @return amount of data available for processing in samples */ static inline uint32_t -audio_stream_get_avail_samples(const struct audio_stream __sparse_cache *stream) +audio_stream_get_avail_samples(const struct audio_stream *stream) { return audio_stream_get_avail_bytes(stream) / audio_stream_sample_bytes(stream); @@ -541,7 +536,7 @@ audio_stream_get_avail_samples(const struct audio_stream __sparse_cache *stream) * @return amount of data available for processing in frames */ static inline uint32_t -audio_stream_get_avail_frames(const struct audio_stream __sparse_cache *stream) +audio_stream_get_avail_frames(const struct audio_stream *stream) { return audio_stream_get_avail_bytes(stream) / audio_stream_frame_bytes(stream); @@ -553,7 +548,7 @@ audio_stream_get_avail_frames(const struct audio_stream __sparse_cache *stream) * @return amount of space free in bytes */ static inline uint32_t -audio_stream_get_free_bytes(const struct audio_stream __sparse_cache *stream) +audio_stream_get_free_bytes(const struct audio_stream *stream) { /* * In case of overrun-permitted stream, report buffer empty instead of @@ -573,7 +568,7 @@ audio_stream_get_free_bytes(const struct audio_stream __sparse_cache *stream) * @return amount of space free in samples */ static inline uint32_t -audio_stream_get_free_samples(const struct audio_stream __sparse_cache *stream) +audio_stream_get_free_samples(const struct audio_stream *stream) { return audio_stream_get_free_bytes(stream) / audio_stream_sample_bytes(stream); @@ -585,7 +580,7 @@ audio_stream_get_free_samples(const struct audio_stream __sparse_cache *stream) * @return amount of space free in frames */ static inline uint32_t -audio_stream_get_free_frames(const struct audio_stream __sparse_cache *stream) +audio_stream_get_free_frames(const struct audio_stream *stream) { return audio_stream_get_free_bytes(stream) / audio_stream_frame_bytes(stream); @@ -601,8 +596,8 @@ audio_stream_get_free_frames(const struct audio_stream __sparse_cache *stream) * @return 1 if there is not enough free space in sink. * @return -1 if there is not enough data in source. */ -static inline int audio_stream_can_copy_bytes(const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, +static inline int audio_stream_can_copy_bytes(const struct audio_stream *source, + const struct audio_stream *sink, uint32_t bytes) { /* check for underrun */ @@ -626,8 +621,8 @@ static inline int audio_stream_can_copy_bytes(const struct audio_stream __sparse * @return Number of bytes. */ static inline uint32_t -audio_stream_get_copy_bytes(const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink) +audio_stream_get_copy_bytes(const struct audio_stream *source, + const struct audio_stream *sink) { uint32_t avail = audio_stream_get_avail_bytes(source); uint32_t free = audio_stream_get_free_bytes(sink); @@ -647,8 +642,8 @@ audio_stream_get_copy_bytes(const struct audio_stream __sparse_cache *source, * @return Number of frames. */ static inline uint32_t -audio_stream_avail_frames(const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink) +audio_stream_avail_frames(const struct audio_stream *source, + const struct audio_stream *sink) { uint32_t src_frames = audio_stream_get_avail_frames(source); uint32_t sink_frames = audio_stream_get_free_frames(sink); @@ -665,8 +660,8 @@ audio_stream_avail_frames(const struct audio_stream __sparse_cache *source, * @return Number of frames. */ static inline uint32_t -audio_stream_avail_frames_aligned(const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink) +audio_stream_avail_frames_aligned(const struct audio_stream *source, + const struct audio_stream *sink) { uint32_t src_frames = (audio_stream_get_avail_bytes(source) >> source->runtime_stream_params.align_shift_idx) * @@ -683,8 +678,7 @@ audio_stream_avail_frames_aligned(const struct audio_stream __sparse_cache *sour * @param buffer Buffer to update. * @param bytes Number of written bytes. */ -static inline void audio_stream_produce(struct audio_stream __sparse_cache *buffer, - uint32_t bytes) +static inline void audio_stream_produce(struct audio_stream *buffer, uint32_t bytes) { buffer->w_ptr = audio_stream_wrap(buffer, (char *)buffer->w_ptr + bytes); @@ -711,8 +705,7 @@ static inline void audio_stream_produce(struct audio_stream __sparse_cache *buff * @param buffer Buffer to update. * @param bytes Number of read bytes. */ -static inline void audio_stream_consume(struct audio_stream __sparse_cache *buffer, - uint32_t bytes) +static inline void audio_stream_consume(struct audio_stream *buffer, uint32_t bytes) { buffer->r_ptr = audio_stream_wrap(buffer, (char *)buffer->r_ptr + bytes); @@ -734,7 +727,7 @@ static inline void audio_stream_consume(struct audio_stream __sparse_cache *buff * Resets the buffer. * @param buffer Buffer to reset. */ -static inline void audio_stream_reset(struct audio_stream __sparse_cache *buffer) +static inline void audio_stream_reset(struct audio_stream *buffer) { /* reset read and write pointer to buffer bas */ buffer->w_ptr = buffer->addr; @@ -753,8 +746,7 @@ static inline void audio_stream_reset(struct audio_stream __sparse_cache *buffer * @param buff_addr Address of the memory block to assign. * @param size Size of the memory block in bytes. */ -void audio_stream_init(struct audio_stream __sparse_cache *audio_stream, - void *buff_addr, uint32_t size); +void audio_stream_init(struct audio_stream *audio_stream, void *buff_addr, uint32_t size); /** * Invalidates (in DSP d-cache) the buffer in range [r_ptr, r_ptr+bytes], @@ -762,8 +754,7 @@ void audio_stream_init(struct audio_stream __sparse_cache *audio_stream, * @param buffer Buffer. * @param bytes Size of the fragment to invalidate. */ -static inline void audio_stream_invalidate(struct audio_stream __sparse_cache *buffer, - uint32_t bytes) +static inline void audio_stream_invalidate(struct audio_stream *buffer, uint32_t bytes) { uint32_t head_size = bytes; uint32_t tail_size = 0; @@ -786,8 +777,7 @@ static inline void audio_stream_invalidate(struct audio_stream __sparse_cache *b * @param buffer Buffer. * @param bytes Size of the fragment to write back. */ -static inline void audio_stream_writeback(struct audio_stream __sparse_cache *buffer, - uint32_t bytes) +static inline void audio_stream_writeback(struct audio_stream *buffer, uint32_t bytes) { uint32_t head_size = bytes; uint32_t tail_size = 0; @@ -811,8 +801,7 @@ static inline void audio_stream_writeback(struct audio_stream __sparse_cache *bu * @return Number of data samples to buffer wrap. */ static inline int -audio_stream_bytes_without_wrap(const struct audio_stream __sparse_cache *source, - const void *ptr) +audio_stream_bytes_without_wrap(const struct audio_stream *source, const void *ptr) { assert((intptr_t)source->end_addr >= (intptr_t)ptr); return (intptr_t)source->end_addr - (intptr_t)ptr; @@ -827,8 +816,7 @@ audio_stream_bytes_without_wrap(const struct audio_stream __sparse_cache *source * need to add size of sample to returned bytes count. */ static inline int -audio_stream_rewind_bytes_without_wrap(const struct audio_stream __sparse_cache *source, - const void *ptr) +audio_stream_rewind_bytes_without_wrap(const struct audio_stream *source, const void *ptr) { assert((intptr_t)ptr >= (intptr_t)source->addr); int to_begin = (intptr_t)ptr - (intptr_t)source->addr; @@ -843,8 +831,7 @@ audio_stream_rewind_bytes_without_wrap(const struct audio_stream __sparse_cache * @return Previous position of the write pointer. */ static inline uint32_t -*audio_stream_rewind_wptr_by_bytes(const struct audio_stream __sparse_cache *source, - const uint32_t bytes) +*audio_stream_rewind_wptr_by_bytes(const struct audio_stream *source, const uint32_t bytes) { void *wptr = audio_stream_get_wptr(source); int to_begin = audio_stream_rewind_bytes_without_wrap(source, wptr); @@ -866,8 +853,7 @@ static inline uint32_t * @return Number of data s16 samples until circular wrap need at end */ static inline int -audio_stream_samples_without_wrap_s16(const struct audio_stream __sparse_cache *source, - const void *ptr) +audio_stream_samples_without_wrap_s16(const struct audio_stream *source, const void *ptr) { int to_end = (int16_t *)source->end_addr - (int16_t *)ptr; @@ -883,8 +869,7 @@ audio_stream_samples_without_wrap_s16(const struct audio_stream __sparse_cache * * @return Number of data s24 samples until circular wrap need at end */ static inline int -audio_stream_samples_without_wrap_s24(const struct audio_stream __sparse_cache *source, - const void *ptr) +audio_stream_samples_without_wrap_s24(const struct audio_stream *source, const void *ptr) { int to_end = (int32_t *)source->end_addr - (int32_t *)ptr; @@ -900,8 +885,7 @@ audio_stream_samples_without_wrap_s24(const struct audio_stream __sparse_cache * * @return Number of data s32 samples until circular wrap need at end */ static inline int -audio_stream_samples_without_wrap_s32(const struct audio_stream __sparse_cache *source, - const void *ptr) +audio_stream_samples_without_wrap_s32(const struct audio_stream *source, const void *ptr) { int to_end = (int32_t *)source->end_addr - (int32_t *)ptr; @@ -947,8 +931,7 @@ static inline int cir_buf_samples_without_wrap_s32(void *ptr, void *buf_end) * @return Number of data frames to buffer wrap. */ static inline uint32_t -audio_stream_frames_without_wrap(const struct audio_stream __sparse_cache *source, - const void *ptr) +audio_stream_frames_without_wrap(const struct audio_stream *source, const void *ptr) { uint32_t bytes = audio_stream_bytes_without_wrap(source, ptr); uint32_t frame_bytes = audio_stream_frame_bytes(source); @@ -965,8 +948,8 @@ audio_stream_frames_without_wrap(const struct audio_stream __sparse_cache *sourc * @param samples Number of samples to copy. * @return number of processed samples. */ -int audio_stream_copy(const struct audio_stream __sparse_cache *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, uint32_t ooffset, uint32_t samples); +int audio_stream_copy(const struct audio_stream *source, uint32_t ioffset, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples); /** * Copies data from one circular buffer to another circular buffer. @@ -990,7 +973,7 @@ void cir_buf_copy(void *src, void *src_addr, void *src_end, void *dst, * @param samples Number of samples to copy. */ void audio_stream_copy_from_linear(const void *linear_source, int ioffset, - struct audio_stream __sparse_cache *sink, int ooffset, + struct audio_stream *sink, int ooffset, unsigned int samples); /** @@ -1001,7 +984,7 @@ void audio_stream_copy_from_linear(const void *linear_source, int ioffset, * @param ooffset Offset (in samples) in sink buffer to start writing to. * @param samples Number of samples to copy. */ -void audio_stream_copy_to_linear(const struct audio_stream __sparse_cache *source, int ioffset, +void audio_stream_copy_to_linear(const struct audio_stream *source, int ioffset, void *linear_sink, int ooffset, unsigned int samples); /** @@ -1011,8 +994,7 @@ void audio_stream_copy_to_linear(const struct audio_stream __sparse_cache *sourc * @return 0 if there is enough free space in buffer. * @return 1 if there is not enough free space in buffer. */ -static inline int audio_stream_set_zero(struct audio_stream __sparse_cache *buffer, - uint32_t bytes) +static inline int audio_stream_set_zero(struct audio_stream *buffer, uint32_t bytes) { uint32_t head_size = bytes; uint32_t tail_size = 0; @@ -1071,16 +1053,15 @@ static inline void audio_stream_fmt_conversion(enum ipc4_bit_depth depth, } /** get a handler to source API - * NOTE! to use the handlers the buffer must be acquired by buffer_acquire */ -static inline struct sof_source __sparse_cache * -audio_stream_get_source(struct audio_stream __sparse_cache *audio_stream) +static inline struct sof_source * +audio_stream_get_source(struct audio_stream *audio_stream) { return &audio_stream->source_api; } -static inline struct sof_sink __sparse_cache * -audio_stream_get_sink(struct audio_stream __sparse_cache *audio_stream) +static inline struct sof_sink * +audio_stream_get_sink(struct audio_stream *audio_stream) { return &audio_stream->sink_api; } diff --git a/src/include/sof/audio/buffer.h b/src/include/sof/audio/buffer.h index 2eeef2d9f80a..568a121db575 100644 --- a/src/include/sof/audio/buffer.h +++ b/src/include/sof/audio/buffer.h @@ -133,9 +133,9 @@ extern struct tr_ctx buffer_tr; * 5) write back cached data and release lock using uncache pointer. */ struct comp_buffer { - struct coherent c; - /* data buffer */ + CORE_CHECK_STRUCT_FIELD; + struct audio_stream stream; /* configuration */ @@ -144,6 +144,7 @@ struct comp_buffer { uint32_t caps; uint32_t core; struct tr_ctx tctx; /* trace settings */ + bool is_shared; /* buffer structure is shared between 2 cores */ /* connected components */ struct comp_dev *source; /* source component */ @@ -162,7 +163,7 @@ struct comp_buffer { /* Only to be used for synchronous same-core notifications! */ struct buffer_cb_transact { - struct comp_buffer __sparse_cache *buffer; + struct comp_buffer *buffer; uint32_t transaction_amount; void *transaction_begin_address; }; @@ -188,54 +189,37 @@ struct buffer_cb_free { } while (0) /* pipeline buffer creation and destruction */ -struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, uint32_t align); -struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc); -int buffer_set_size(struct comp_buffer __sparse_cache *buffer, uint32_t size, uint32_t alignment); +struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, uint32_t align, + bool is_shared); +struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc, bool is_shared); +int buffer_set_size(struct comp_buffer *buffer, uint32_t size, uint32_t alignment); void buffer_free(struct comp_buffer *buffer); -void buffer_zero(struct comp_buffer __sparse_cache *buffer); +void buffer_zero(struct comp_buffer *buffer); /* called by a component after producing data into this buffer */ -void comp_update_buffer_produce(struct comp_buffer __sparse_cache *buffer, uint32_t bytes); +void comp_update_buffer_produce(struct comp_buffer *buffer, uint32_t bytes); /* called by a component after consuming data from this buffer */ -void comp_update_buffer_consume(struct comp_buffer __sparse_cache *buffer, uint32_t bytes); +void comp_update_buffer_consume(struct comp_buffer *buffer, uint32_t bytes); -int buffer_set_params(struct comp_buffer __sparse_cache *buffer, +int buffer_set_params(struct comp_buffer *buffer, struct sof_ipc_stream_params *params, bool force_update); -bool buffer_params_match(struct comp_buffer __sparse_cache *buffer, +bool buffer_params_match(struct comp_buffer *buffer, struct sof_ipc_stream_params *params, uint32_t flag); -static inline void buffer_stream_invalidate(struct comp_buffer __sparse_cache *buffer, - uint32_t bytes) +static inline void buffer_stream_invalidate(struct comp_buffer *buffer, uint32_t bytes) { - if (!is_coherent_shared(buffer, c)) - return; - - audio_stream_invalidate(&buffer->stream, bytes); + if (buffer->is_shared) + audio_stream_invalidate(&buffer->stream, bytes); } -static inline void buffer_stream_writeback(struct comp_buffer __sparse_cache *buffer, - uint32_t bytes) +static inline void buffer_stream_writeback(struct comp_buffer *buffer, uint32_t bytes) { - if (!is_coherent_shared(buffer, c)) - return; - - audio_stream_writeback(&buffer->stream, bytes); + if (buffer->is_shared) + audio_stream_writeback(&buffer->stream, bytes); } -__must_check static inline struct comp_buffer __sparse_cache *buffer_acquire( - struct comp_buffer *buffer) -{ - struct coherent __sparse_cache *c = coherent_acquire_thread(&buffer->c, sizeof(*buffer)); - - return attr_container_of(c, struct comp_buffer __sparse_cache, c, __sparse_cache); -} - -static inline void buffer_release(struct comp_buffer __sparse_cache *buffer) -{ - coherent_release_thread(&buffer->c, sizeof(*buffer)); -} /* * Attach a new buffer at the beginning of the list. Note, that "head" must @@ -255,14 +239,11 @@ void buffer_detach(struct comp_buffer *buffer, struct list_item *head, int dir); static inline struct comp_dev *buffer_get_comp(struct comp_buffer *buffer, int dir) { - struct comp_buffer __sparse_cache *buffer_c = buffer_acquire(buffer); - struct comp_dev *comp = dir == PPL_DIR_DOWNSTREAM ? buffer_c->sink : - buffer_c->source; - buffer_release(buffer_c); + struct comp_dev *comp = dir == PPL_DIR_DOWNSTREAM ? buffer->sink : buffer->source; return comp; } -static inline void buffer_reset_pos(struct comp_buffer __sparse_cache *buffer, void *data) +static inline void buffer_reset_pos(struct comp_buffer *buffer, void *data) { /* reset rw pointers and avail/free bytes counters */ audio_stream_reset(&buffer->stream); @@ -272,7 +253,7 @@ static inline void buffer_reset_pos(struct comp_buffer __sparse_cache *buffer, v } /* Run-time buffer re-configuration calls this too, so it must use cached access */ -static inline void buffer_init(struct comp_buffer __sparse_cache *buffer, +static inline void buffer_init(struct comp_buffer *buffer, uint32_t size, uint32_t caps) { buffer->caps = caps; @@ -281,7 +262,7 @@ static inline void buffer_init(struct comp_buffer __sparse_cache *buffer, audio_stream_init(&buffer->stream, buffer->stream.addr, size); } -static inline void buffer_reset_params(struct comp_buffer __sparse_cache *buffer, void *data) +static inline void buffer_reset_params(struct comp_buffer *buffer, void *data) { buffer->hw_params_configured = false; } diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index f860cdcb3d90..4a24d08ffb28 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -48,6 +48,7 @@ struct comp_dev; struct sof_ipc_stream_posn; struct dai_hw_params; struct timestamp_data; +struct dai_ts_data; /** \addtogroup component_api Component API * @{ @@ -455,8 +456,12 @@ struct comp_ops { * * Mandatory for components that allocate DAI. */ +#if CONFIG_ZEPHYR_NATIVE_DRIVERS + int (*dai_ts_get)(struct comp_dev *dev, struct dai_ts_data *tsd); +#else int (*dai_ts_get)(struct comp_dev *dev, struct timestamp_data *tsd); +#endif /** * Bind, atomic - used to notify component of bind event. @@ -576,7 +581,12 @@ struct comp_dev { * 2) for all DP tasks */ uint32_t size; /**< component's allocated size */ - uint32_t period; /**< component's processing period */ + uint32_t period; /**< component's processing period + * for LL modules is set to LL pipeline's period + * for DP module its meaning is "the time the module MUST + * provide data that allows the following module to perform + * without glitches" + */ uint32_t priority; /**< component's processing priority */ bool is_shared; /**< indicates whether component is shared * across cores @@ -664,9 +674,7 @@ static inline struct comp_dev *comp_alloc(const struct comp_driver *drv, /* * Use uncached address everywhere to access components to rule out - * multi-core failures. In the future we might decide to switch over to - * the latest coherence API for performance. In that case components - * will be acquired for cached access and released afterwards. + * multi-core failures. TODO: verify if cached alias may be used in some cases */ dev = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, bytes); if (!dev) @@ -817,7 +825,7 @@ static inline void component_set_nearest_period_frames(struct comp_dev *current, * @param copy_bytes Requested size of data to be available. */ static inline void comp_underrun(struct comp_dev *dev, - struct comp_buffer __sparse_cache *source, + struct comp_buffer *source, uint32_t copy_bytes) { LOG_MODULE_DECLARE(component, CONFIG_SOF_LOG_LEVEL); @@ -839,7 +847,7 @@ static inline void comp_underrun(struct comp_dev *dev, * @param sink Sink buffer. * @param copy_bytes Requested size of free space to be available. */ -static inline void comp_overrun(struct comp_dev *dev, struct comp_buffer __sparse_cache *sink, +static inline void comp_overrun(struct comp_dev *dev, struct comp_buffer *sink, uint32_t copy_bytes) { LOG_MODULE_DECLARE(component, CONFIG_SOF_LOG_LEVEL); @@ -864,8 +872,8 @@ static inline void comp_overrun(struct comp_dev *dev, struct comp_buffer __spars * @param[in] sink Sink buffer. * @param[out] cl Current copy limits. */ -void comp_get_copy_limits(struct comp_buffer __sparse_cache *source, - struct comp_buffer __sparse_cache *sink, +void comp_get_copy_limits(struct comp_buffer *source, + struct comp_buffer *sink, struct comp_copy_limits *cl); /** @@ -877,59 +885,10 @@ void comp_get_copy_limits(struct comp_buffer __sparse_cache *source, * @param[in] sink Buffer of sink. * @param[out] cl Current copy limits. */ -void comp_get_copy_limits_frame_aligned(const struct comp_buffer __sparse_cache *source, - const struct comp_buffer __sparse_cache *sink, +void comp_get_copy_limits_frame_aligned(const struct comp_buffer *source, + const struct comp_buffer *sink, struct comp_copy_limits *cl); -/** - * Version of comp_get_copy_limits that locks both buffers to guarantee - * consistent state readings. - * - * @param[in] source Source buffer. - * @param[in] sink Sink buffer - * @param[out] cl Current copy limits. - */ -static inline -void comp_get_copy_limits_with_lock(struct comp_buffer *source, - struct comp_buffer *sink, - struct comp_copy_limits *cl) -{ - struct comp_buffer __sparse_cache *source_c, *sink_c; - - source_c = buffer_acquire(source); - sink_c = buffer_acquire(sink); - - comp_get_copy_limits(source_c, sink_c, cl); - - buffer_release(sink_c); - buffer_release(source_c); -} - -/** - * Version of comp_get_copy_limits_with_lock_frame_aligned that locks both - * buffers to guarantee consistent state readings and the frames aligned with - * the requirement. - * - * @param[in] source Buffer of source. - * @param[in] sink Buffer of sink - * @param[out] cl Current copy limits. - */ -static inline -void comp_get_copy_limits_with_lock_frame_aligned(struct comp_buffer *source, - struct comp_buffer *sink, - struct comp_copy_limits *cl) -{ - struct comp_buffer __sparse_cache *source_c, *sink_c; - - source_c = buffer_acquire(source); - sink_c = buffer_acquire(sink); - - comp_get_copy_limits_frame_aligned(source_c, sink_c, cl); - - buffer_release(sink_c); - buffer_release(source_c); -} - /** * Get component state. * diff --git a/src/include/sof/audio/component_ext.h b/src/include/sof/audio/component_ext.h index 4aa65bf61fcd..2c51943413c3 100644 --- a/src/include/sof/audio/component_ext.h +++ b/src/include/sof/audio/component_ext.h @@ -55,6 +55,7 @@ static inline void comp_free(struct comp_dev *dev) dev->task) { schedule_task_free(dev->task); rfree(dev->task); + dev->task = NULL; } dev->drv->ops.free(dev); diff --git a/src/include/sof/audio/dai_copier.h b/src/include/sof/audio/dai_copier.h index 6219b92fb5b7..67165cb6d265 100644 --- a/src/include/sof/audio/dai_copier.h +++ b/src/include/sof/audio/dai_copier.h @@ -44,7 +44,11 @@ int dai_common_ts_start(struct dai_data *dd, struct comp_dev *dev); int dai_common_ts_stop(struct dai_data *dd, struct comp_dev *dev); +#if CONFIG_ZEPHYR_NATIVE_DRIVERS +int dai_common_ts_get(struct dai_data *dd, struct comp_dev *dev, struct dai_ts_data *tsd); +#else int dai_common_ts_get(struct dai_data *dd, struct comp_dev *dev, struct timestamp_data *tsd); +#endif int dai_common_get_hw_params(struct dai_data *dd, struct comp_dev *dev, struct sof_ipc_stream_params *params, int dir); diff --git a/src/include/sof/audio/dcblock/dcblock.h b/src/include/sof/audio/dcblock/dcblock.h index 35019364b33f..2d0d46317e5c 100644 --- a/src/include/sof/audio/dcblock/dcblock.h +++ b/src/include/sof/audio/dcblock/dcblock.h @@ -43,8 +43,8 @@ struct dcblock_state { struct comp_data; typedef void (*dcblock_func)(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames); /* DC Blocking Filter component private data */ diff --git a/src/include/sof/audio/dp_queue.h b/src/include/sof/audio/dp_queue.h new file mode 100644 index 000000000000..b187eb7a6f86 --- /dev/null +++ b/src/include/sof/audio/dp_queue.h @@ -0,0 +1,224 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + */ + +#ifndef __SOF_DP_QUEUE_H__ +#define __SOF_DP_QUEUE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * DP queue is a lockless circular buffer + * providing safe consumer/producer cached operations cross cores + * + * prerequisites: + * 1) incoming and outgoing data rate MUST be the same + * 2) Both data consumer and data producer declare max chunk sizes they want to use (IBS/OBS) + * + * required Buffer size is 2*MAX(IBS,OBS) to allow free read/write in various data chunk sizes + * and execution periods (of course in/out data rates must be same) + * example: + * Consumer reads 5bytes each 3 cycles (IBS = 5) + * producer writes 3bytes every 5 cycles (OBS = 3) + * - cycle0 buffer empty, producer starting processing, consumer must wait + * - cycle3 produce 3 bytes (buf occupation = 3) + * - cycle6 produce 3 bytes (buf occupation = 6), consumer becomes ready + * in DP thread will start now - asyn to LL cycles + * in this example assuming it consumes data in next cycle + * - cycle7 consume 5 bytes, (buf occupation = 1) + * - cycle9 produce 3 bytes (buf occupation = 4) + * - cycle12 (producer goes first) produce 3 bytes (buf occupation = 7) + * consume 5 bytes (buf occupation = 2) + * - cycle15 produce 3 bytes (buf occupation = 5) + * consumer has enough data, but is busy processing prev data + * - cycle15 consume 5 bytes (buf occupation = 0) + * + * ===> max buf occupation = 7 + * + * The worst case is when IBS=OBS and equal periods of consumer/producer + * the buffer must be 2*MAX(IBS,OBS) as we do not know who goes first - consumer or producer, + * especially when both are located on separate cores and EDF scheduling is used + * + * Consumer reads 5 bytes every cycle (IBS = 5) + * producer writes 5 bytes every cycle (OBS = 5) + * - cycle0 consumer goes first - must wait (buf occupation = 0) + * producer produce 5 bytes (buf occupation = 5) + * - cycle1 producer goes first - produce 5 bytes (buf occupation = 10) + * consumer consumes 5 bytes (buf occupation = 5) + * ===> max buf occupation = 10 + * + * + * The queue may work in 2 modes + * 1) local mode + * in case both receiver and sender are located on the same core and cache coherency + * does not matter. dp_queue structure is located in cached memory + * In this case DP Queue is a simple ring buffer + * + * 2) shared mode + * In this case we need to writeback cache when new data arrive and invalidate cache on + * secondary core. dp_queue structure is located in shared memory + * + * + * dpQueue is a lockless consumer/producer safe buffer. It is achieved by having only 2 shared + * variables: + * _write_offset - can be modified by data producer only + * _read_offset - can be modified by data consumer only + * + * as 32 bit operations are atomic, it is multi-thread and multi-core save + * + * There some explanation needed how free_space and available_data are calculated + * + * number of avail data in circular buffer may be calculated as: + * data_avail = _write_offset - _read_offset + * and check for wrap around + * if (data_avail < 0) data_avail = buffer_size - data_avail + * + * The problem is when _write_offset == _read_offset, + * !!! it may mean either that the buffer is empty or the buffer is completely filled !!! + * + * To solve the above issue having only 2 variables mentioned before: + * - allow both offsets to point from 0 to DOUBLE buffer_size + * - when calculating pointers to data, use: data_bufer[offset % buffer_size] + * - use double buffer size in wrap around check when calculating available data + * + * And now: + * - _write_offset == _read_offset + * always means "buffer empty" + * - _write_offset == _read_offset + buffer_size + * always means "buffer full" + */ + +struct dp_queue; +struct sof_audio_stream_params; + +/* DP flags */ +#define DP_QUEUE_MODE_LOCAL 0 +#define DP_QUEUE_MODE_SHARED BIT(1) + +/* the dpQueue structure */ +struct dp_queue { + CORE_CHECK_STRUCT_FIELD; + + /* public */ + struct list_item list; /**< fields for connection queues in a list */ + + /* public: read only */ + struct sof_audio_stream_params audio_stream_params; + size_t data_buffer_size; + + /* private: */ + struct sof_source _source_api; /**< src api handler */ + struct sof_sink _sink_api; /**< sink api handler */ + + uint32_t _flags; /* DP_QUEUE_MODE_* */ + + uint8_t __sparse_cache *_data_buffer; + size_t _write_offset; /* private: to be modified by data producer using API */ + size_t _read_offset; /* private: to be modified by data consumer using API */ + + bool _hw_params_configured; +}; + +/** + * + * @param min_available minimum data available in queue required by the module using + * dp_queue's source api + * @param min_free_space minimum buffer space in queue required by the module using + * dp_queue's sink api + * + * @param flags a combinatin of DP_QUEUE_MODE_* flags determining working mode + * + */ +struct dp_queue *dp_queue_create(size_t min_available, size_t min_free_space, uint32_t flags); + +/** + * @brief remove the queue from the list, free dp queue memory + */ +static inline +void dp_queue_free(struct dp_queue *dp_queue) +{ + CORE_CHECK_STRUCT(dp_queue); + list_item_del(&dp_queue->list); + rfree((__sparse_force void *)dp_queue->_data_buffer); + rfree(dp_queue); +} + +/** + * @brief return a handler to sink API of dp_queue. + * the handler may be used by helper functions defined in sink_api.h + */ +static inline +struct sof_sink *dp_queue_get_sink(struct dp_queue *dp_queue) +{ + CORE_CHECK_STRUCT(dp_queue); + return &dp_queue->_sink_api; +} + +/** + * @brief return a handler to source API of dp_queue + * the handler may be used by helper functions defined in source_api.h + */ +static inline +struct sof_source *dp_queue_get_source(struct dp_queue *dp_queue) +{ + CORE_CHECK_STRUCT(dp_queue); + return &dp_queue->_source_api; +} + +/** + * @brief this is a backdoor to get complete audio params structure from dp_queue + * it is needed till pipeline 2.0 is ready + * + */ +static inline +struct sof_audio_stream_params *dp_queue_get_audio_params(struct dp_queue *dp_queue) +{ + CORE_CHECK_STRUCT(dp_queue); + return &dp_queue->audio_stream_params; +} + +/** + * @brief return true if the queue is shared between 2 cores + */ +static inline +bool dp_queue_is_shared(struct dp_queue *dp_queue) +{ + CORE_CHECK_STRUCT(dp_queue); + return !!(dp_queue->_flags & DP_QUEUE_MODE_SHARED); +} + +/** + * @brief append a dp_queue to the list + */ +static inline void dp_queue_append_to_list(struct dp_queue *item, struct list_item *list) +{ + list_item_append(&item->list, list); +} + +/** + * @brief return a pointer to the first dp_queue on the list + */ +static inline struct dp_queue *dp_queue_get_first_item(struct list_item *list) +{ + return list_first_item(list, struct dp_queue, list); +} + +/** + * @brief return a pointer to the next dp_queue on the list + */ +static inline struct dp_queue *dp_queue_get_next_item(struct dp_queue *item) +{ + return list_next_item(item, list); +} + +#endif /* __SOF_DP_QUEUE_H__ */ diff --git a/src/include/sof/audio/drc/drc.h b/src/include/sof/audio/drc/drc.h index ee480e1d8692..e7571096313e 100644 --- a/src/include/sof/audio/drc/drc.h +++ b/src/include/sof/audio/drc/drc.h @@ -60,8 +60,8 @@ struct drc_state { }; typedef void (*drc_func)(struct processing_module *mod, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames); /* DRC component private data */ @@ -83,8 +83,8 @@ extern const struct drc_proc_fnmap drc_proc_fnmap[]; extern const size_t drc_proc_fncount; void drc_default_pass(struct processing_module *mod, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, uint32_t frames); + const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames); /** * \brief Returns DRC processing function. */ diff --git a/src/include/sof/audio/format.h b/src/include/sof/audio/format.h index 55b0c8a5debf..a33d3c60fce4 100644 --- a/src/include/sof/audio/format.h +++ b/src/include/sof/audio/format.h @@ -179,6 +179,21 @@ static inline uint32_t get_sample_bytes(enum sof_ipc_frame fmt) } } +static inline uint32_t get_sample_bitdepth(enum sof_ipc_frame fmt) +{ + switch (fmt) { + case SOF_IPC_FRAME_S16_LE: + return 16; + case SOF_IPC_FRAME_S24_4LE: + case SOF_IPC_FRAME_S24_3LE: + return 24; + case SOF_IPC_FRAME_U8: + return 8; + default: + return 32; + } +} + static inline uint32_t get_frame_bytes(enum sof_ipc_frame fmt, uint32_t channels) { diff --git a/src/include/sof/audio/host_copier.h b/src/include/sof/audio/host_copier.h index 60f0dccfdb90..c7ac454bf800 100644 --- a/src/include/sof/audio/host_copier.h +++ b/src/include/sof/audio/host_copier.h @@ -96,6 +96,7 @@ struct host_data { /* stream info */ struct sof_ipc_stream_posn posn; /* TODO: update this */ struct ipc_msg *msg; /**< host notification */ + uint32_t dma_buffer_size; /* dma buffer size */ #if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION bool is_grouped; uint8_t group_id; diff --git a/src/include/sof/audio/igo_nr/igo_nr_comp.h b/src/include/sof/audio/igo_nr/igo_nr_comp.h index 50159adb1a08..64c663a99944 100644 --- a/src/include/sof/audio/igo_nr/igo_nr_comp.h +++ b/src/include/sof/audio/igo_nr/igo_nr_comp.h @@ -41,8 +41,8 @@ struct comp_data { int32_t sink_frames_max; /* Max # of frames to process at sink */ int32_t frames; /* IO buffer length */ void (*igo_nr_func)(struct comp_data *cd, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, int32_t frames); }; diff --git a/src/include/sof/audio/kpb.h b/src/include/sof/audio/kpb.h index 852659f86c98..dbec1207c467 100644 --- a/src/include/sof/audio/kpb.h +++ b/src/include/sof/audio/kpb.h @@ -43,6 +43,7 @@ struct comp_buffer; (KPB_SAMPLE_CONTAINER_SIZE(sw) / 8) * KPB_MAX_BUFF_TIME * \ (channels_number)) #define KPB_MAX_NO_OF_CLIENTS 2 +#define KPB_MAX_SINK_CNT (1 + KPB_MAX_NO_OF_CLIENTS) #define KPB_NO_OF_HISTORY_BUFFERS 2 /**< no of internal buffers */ #define KPB_ALLOCATION_STEP 0x100 #define KPB_NO_OF_MEM_POOLS 3 @@ -66,6 +67,9 @@ struct comp_buffer; * i.e. number of max supported channels - reference channels) */ #define KPB_MAX_MICSEL_CHANNELS 4 +/* Used in FMT */ +#define FAST_MODE_TASK_MAX_MODULES_COUNT 16 +#define REALTIME_PIN_ID 0 /** All states below as well as relations between them are documented in * the sof-dosc in [kpbm-state-diagram] @@ -159,18 +163,88 @@ struct history_data { struct history_buffer *c_hb; /**< current buffer used for writing */ }; -enum ipc4_kpb_module_config_params { - /* Mic selector for client - sets microphone id for real time sink mic selector - * IPC4-compatible ID - please do not change the number - */ - KP_BUF_CLIENT_MIC_SELECT = 11, -}; +/* moved to ipc4/kpb.h */ +/* enum ipc4_kpb_module_config_params */ /* Stores KPB mic selector config */ struct kpb_micselector_config { /* channel bit set to 1 implies channel selection */ uint32_t mask; }; + +struct kpb_task_params { + /* If largeconfigset is set to KP_POS_IN_BUFFER then number of modules must + * correspond to number of modules between kpb and copier attached to hostdma. + * Once draining path is configured, cannot be reinitialized/changed. + */ + uint32_t number_of_modules; + struct { + uint16_t module_id; + uint16_t instance_id; + } dev_ids[1]; +}; + +/* fmt namespace: */ +#define FAST_MODE_TASK_MAX_LIST_COUNT 5 + +struct fast_mode_task { + /*! Array of pointers to all module lists to be processed. */ + struct device_list *device_list[FAST_MODE_TASK_MAX_LIST_COUNT]; +}; + +/* The +1 is here because we also push the kbp device + * handle in addition to the max number of modules + */ +#define DEVICE_LIST_SIZE (FAST_MODE_TASK_MAX_MODULES_COUNT + 1) + +/* Devicelist type + * In Reference FW KPB used Bi-dir lists to store modules for FMT. It is possible that lists are + * not necessary, but in case it might be wrong, here we use an array + * with a list interface to switch it to a list easily. + */ +struct device_list { + struct comp_dev **devs[DEVICE_LIST_SIZE]; + /* number of items AND index of next empty box */ + size_t count; +}; + +/* + * + * + * KPB FMT config set steps: + * 1. Get dev_ids of module instances from IPC + * 2. Alloc this kpb module instance on kpb_list_item, save address of where it was allocated + * 3. Push the address on dev_list.device_list + * 2. For each dev_id get device handler(module instance) + * 3. Alloc device handler in modules_list_item, save address of where it was allocated + * 4. Register this address in fmt.device_list + * + * Pointer structure: + * + * COMP_DEVS + * ^ + * | + * dev_list.modules_list_item(comp_dev* ) + * ^ + * | + * dev_list.device_list(comp_dev**) + * ^ + * | + * fmt.device_list(device_list*) + * + * + */ + +/* KpbFastModeTaskModulesList Namespace */ +struct kpb_fmt_dev_list { + /*! Array of all module lists to be processed. */ + struct device_list device_list[FAST_MODE_TASK_MAX_LIST_COUNT]; + /* One for each sinkpin. */ + struct comp_dev *kpb_list_item[KPB_MAX_SINK_CNT]; + struct comp_dev *modules_list_item[FAST_MODE_TASK_MAX_MODULES_COUNT]; + struct comp_dev *kpb_mi_ptr; +}; + #ifdef UNIT_TEST void sys_comp_kpb_init(void); #endif diff --git a/src/include/sof/audio/mixer.h b/src/include/sof/audio/mixer.h index 2dd5e3c80885..118aaf1c914f 100644 --- a/src/include/sof/audio/mixer.h +++ b/src/include/sof/audio/mixer.h @@ -34,16 +34,16 @@ void sys_comp_module_mixer_interface_init(void); /* mixer component private data */ struct mixer_data { - void (*mix_func)(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, uint32_t count, + void (*mix_func)(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream **sources, uint32_t count, uint32_t frames); }; /** * \brief mixer processing function interface */ -typedef void (*mixer_func)(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, uint32_t num_sources, +typedef void (*mixer_func)(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream **sources, uint32_t num_sources, uint32_t frames); /** \brief Volume processing functions map. */ @@ -64,7 +64,7 @@ extern const size_t mixer_func_count; * \param[in] sinkb Sink buffer to match against */ static inline mixer_func mixer_get_processing_function(struct comp_dev *dev, - struct comp_buffer __sparse_cache *sinkb) + struct comp_buffer *sinkb) { int i; diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index 28f5c0765d0c..90f91ab0cef7 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -15,12 +15,28 @@ #include #include #include +#include +#include +#include #include "module_interface.h" #if CONFIG_INTEL_MODULES #include "modules.h" #endif +/* + * helpers to determine processing type + * Needed till all the modules use PROCESSING_MODE_SINK_SOURCE + */ +#define IS_PROCESSING_MODE_AUDIO_STREAM(mod) \ + (!!((struct module_data *)&(mod)->priv)->ops->process_audio_stream) + +#define IS_PROCESSING_MODE_RAW_DATA(mod) \ + (!!((struct module_data *)&(mod)->priv)->ops->process_raw_data) + +#define IS_PROCESSING_MODE_SINK_SOURCE(mod) \ + (!!((struct module_data *)&(mod)->priv)->ops->process) + #define module_get_private_data(mod) (mod->priv.private) #define MAX_BLOB_SIZE 8192 #define MODULE_MAX_SOURCES 8 @@ -155,23 +171,13 @@ struct module_data { void *private; /**< self object, memory tables etc here */ void *runtime_params; struct module_config cfg; /**< module configuration data */ - struct module_interface *ops; /**< module specific operations */ + const struct module_interface *ops; /**< module specific operations */ struct module_memory memory; /**< memory allocated by module */ struct module_processing_data mpd; /**< shared data comp <-> module */ void *module_adapter; /**ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP + */ + struct list_item dp_queue_ll_to_dp_list; + struct list_item dp_queue_dp_to_ll_list; + }; + }; struct comp_buffer *source_comp_buffer; /**< single source component buffer */ struct comp_buffer *sink_comp_buffer; /**< single sink compoonent buffer */ @@ -224,9 +253,6 @@ struct processing_module { /* pointer to system services for loadable modules */ uint32_t *sys_service; - /* table containing the list of connected sources */ - struct module_source_info *source_info; - /* total processed data after stream started */ uint64_t total_data_consumed; uint64_t total_data_produced; @@ -240,19 +266,19 @@ struct processing_module { /* Module generic interfaces */ /*****************************************************************************/ int module_load_config(struct comp_dev *dev, const void *cfg, size_t size); -int module_init(struct processing_module *mod, struct module_interface *interface); +int module_init(struct processing_module *mod, const struct module_interface *interface); void *module_allocate_memory(struct processing_module *mod, uint32_t size, uint32_t alignment); int module_free_memory(struct processing_module *mod, void *ptr); void module_free_all_memory(struct processing_module *mod); int module_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks); + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks); static inline bool module_is_ready_to_process(struct processing_module *mod, - struct sof_source __sparse_cache **sources, + struct sof_source **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, + struct sof_sink **sinks, int num_of_sinks) { struct module_data *md = &mod->priv; @@ -267,13 +293,13 @@ bool module_is_ready_to_process(struct processing_module *mod, /* default action - the module is ready if there's enough data for processing and enough * space to store result. IBS/OBS as declared in init_instance */ - return (source_get_data_available(sources[0]) >= source_get_ibs(sources[0]) && - sink_get_free_size(sinks[0]) >= sink_get_obs(sinks[0])); + return (source_get_data_available(sources[0]) >= source_get_min_available(sources[0]) && + sink_get_free_size(sinks[0]) >= sink_get_min_free_space(sinks[0])); } int module_process_sink_src(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks); + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks); int module_process_legacy(struct processing_module *mod, struct input_stream_buffer *input_buffers, int num_input_buffers, struct output_stream_buffer *output_buffers, @@ -290,7 +316,7 @@ int module_unbind(struct processing_module *mod, void *data); struct comp_dev *module_adapter_new(const struct comp_driver *drv, const struct comp_ipc_config *config, - struct module_interface *interface, const void *spec); + const struct module_interface *interface, const void *spec); int module_adapter_prepare(struct comp_dev *dev); int module_adapter_params(struct comp_dev *dev, struct sof_ipc_stream_params *params); int module_adapter_copy(struct comp_dev *dev); @@ -298,69 +324,73 @@ int module_adapter_cmd(struct comp_dev *dev, int cmd, void *data, int max_data_s int module_adapter_trigger(struct comp_dev *dev, int cmd); void module_adapter_free(struct comp_dev *dev); int module_adapter_reset(struct comp_dev *dev); -int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, - bool last_block, uint32_t data_offset, const char *data); -int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, - bool last_block, uint32_t *data_offset, char *data); -int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value); -int module_adapter_bind(struct comp_dev *dev, void *data); -int module_adapter_unbind(struct comp_dev *dev, void *data); -uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, - uint32_t stream_no, bool input); -int module_adapter_get_hw_params(struct comp_dev *dev, struct sof_ipc_stream_params *params, - int dir); -int module_adapter_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn); -int module_adapter_ts_config_op(struct comp_dev *dev); -int module_adapter_ts_start_op(struct comp_dev *dev); -int module_adapter_ts_stop_op(struct comp_dev *dev); -int module_adapter_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd); -static inline void module_update_buffer_position(struct input_stream_buffer *input_buffers, - struct output_stream_buffer *output_buffers, - uint32_t frames) +#if CONFIG_IPC_MAJOR_3 +static inline +int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value) { - struct audio_stream __sparse_cache *source = input_buffers->data; - struct audio_stream __sparse_cache *sink = output_buffers->data; - - input_buffers->consumed += audio_stream_frame_bytes(source) * frames; - output_buffers->size += audio_stream_frame_bytes(sink) * frames; + return -EINVAL; } -__must_check static inline -struct module_source_info __sparse_cache *module_source_info_acquire(struct module_source_info *msi) +static inline +int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, + bool last_block, uint32_t data_offset, const char *data) { - struct coherent __sparse_cache *c; - - c = coherent_acquire_thread(&msi->c, sizeof(*msi)); + return 0; +} - return attr_container_of(c, struct module_source_info __sparse_cache, c, __sparse_cache); +static inline +int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, + bool last_block, uint32_t *data_offset, char *data) +{ + return 0; } -static inline void module_source_info_release(struct module_source_info __sparse_cache *msi) +static inline +int module_adapter_bind(struct comp_dev *dev, void *data) { - coherent_release_thread(&msi->c, sizeof(*msi)); + return 0; } -/* when source argument is NULL, this function returns the first unused entry */ static inline -int find_module_source_index(struct module_source_info __sparse_cache *msi, - const struct comp_dev *source) +int module_adapter_unbind(struct comp_dev *dev, void *data) { - int i; + return 0; +} - for (i = 0; i < MODULE_MAX_SOURCES; i++) { - if (msi->sources[i] == source) - return i; - } +static inline +uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, + uint32_t stream_no, bool input) +{ + return 0; +} - return -EINVAL; +static inline int module_process_endpoint(struct processing_module *mod, + struct input_stream_buffer *input_buffers, + int num_input_buffers, + struct output_stream_buffer *output_buffers, + int num_output_buffers) +{ + return module_process_legacy(mod, input_buffers, num_input_buffers, + output_buffers, num_output_buffers); } -static inline int module_process_stream(struct processing_module *mod, - struct input_stream_buffer *input_buffers, - int num_input_buffers, - struct output_stream_buffer *output_buffers, - int num_output_buffers) +#else +int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, + bool last_block, uint32_t data_offset, const char *data); +int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, + bool last_block, uint32_t *data_offset, char *data); +int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value); +int module_adapter_bind(struct comp_dev *dev, void *data); +int module_adapter_unbind(struct comp_dev *dev, void *data); +uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, + uint32_t stream_no, bool input); + +static inline int module_process_endpoint(struct processing_module *mod, + struct input_stream_buffer *input_buffers, + int num_input_buffers, + struct output_stream_buffer *output_buffers, + int num_output_buffers) { struct module_data *md = &mod->priv; @@ -368,4 +398,32 @@ static inline int module_process_stream(struct processing_module *mod, output_buffers, num_output_buffers); } +#endif + +int module_adapter_get_hw_params(struct comp_dev *dev, struct sof_ipc_stream_params *params, + int dir); +int module_adapter_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn); +int module_adapter_ts_config_op(struct comp_dev *dev); +int module_adapter_ts_start_op(struct comp_dev *dev); +int module_adapter_ts_stop_op(struct comp_dev *dev); +#if CONFIG_ZEPHYR_NATIVE_DRIVERS +int module_adapter_ts_get_op(struct comp_dev *dev, struct dai_ts_data *tsd); +#else +int module_adapter_ts_get_op(struct comp_dev *dev, struct timestamp_data *tsd); +#endif + +void module_update_buffer_position(struct input_stream_buffer *input_buffers, + struct output_stream_buffer *output_buffers, + uint32_t frames); + +int module_adapter_init_data(struct comp_dev *dev, + struct module_config *dst, + const struct comp_ipc_config *config, + const void *spec); +void module_adapter_reset_data(struct module_config *dst); +void module_adapter_check_data(struct processing_module *mod, struct comp_dev *dev, + struct comp_buffer *sink); +void module_adapter_set_params(struct processing_module *mod, struct sof_ipc_stream_params *params); +int module_adapter_set_state(struct processing_module *mod, struct comp_dev *dev, + int cmd); #endif /* __SOF_AUDIO_MODULE_GENERIC__ */ diff --git a/src/include/sof/audio/module_adapter/module/module_interface.h b/src/include/sof/audio/module_adapter/module/module_interface.h index e4b7ddcfb7d4..70884e493861 100644 --- a/src/include/sof/audio/module_adapter/module/module_interface.h +++ b/src/include/sof/audio/module_adapter/module/module_interface.h @@ -50,7 +50,7 @@ enum module_processing_mode { * \brief Input stream buffer */ struct input_stream_buffer { - void __sparse_cache *data; /* data stream buffer */ + void *data; /* data stream buffer */ uint32_t size; /* size of data in the buffer */ uint32_t consumed; /* number of bytes consumed by the module */ @@ -63,12 +63,13 @@ struct input_stream_buffer { * \brief Output stream buffer */ struct output_stream_buffer { - void __sparse_cache *data; /* data stream buffer */ + void *data; /* data stream buffer */ uint32_t size; /* size of data in the buffer */ }; struct comp_dev; struct timestamp_data; +struct dai_ts_data; /** * \struct module_endpoint_ops * \brief Ops relevant only for the endpoint devices such as the host copier or DAI copier. @@ -120,7 +121,11 @@ struct module_endpoint_ops { * * Mandatory for components that allocate DAI. */ +#if CONFIG_ZEPHYR_NATIVE_DRIVERS + int (*dai_ts_get)(struct comp_dev *dev, struct dai_ts_data *tsd); +#else int (*dai_ts_get)(struct comp_dev *dev, struct timestamp_data *tsd); +#endif /** * Fetches hardware stream parameters. @@ -158,8 +163,8 @@ struct module_interface { * component preparation in .prepare() */ int (*prepare)(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks); + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks); /** * (optional) return true if the module is ready to process @@ -177,8 +182,8 @@ struct module_interface { * the module */ bool (*is_ready_to_process)(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks); + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks); /** * Module specific processing procedure @@ -200,8 +205,8 @@ struct module_interface { * - sinks are handlers to sink API struct sink*[] */ int (*process)(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks); + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks); /** * process_audio_stream (depreciated) diff --git a/src/include/sof/audio/multiband_drc/multiband_drc.h b/src/include/sof/audio/multiband_drc/multiband_drc.h index a5058bd158dc..2c331215a8ee 100644 --- a/src/include/sof/audio/multiband_drc/multiband_drc.h +++ b/src/include/sof/audio/multiband_drc/multiband_drc.h @@ -28,8 +28,8 @@ struct multiband_drc_state { }; typedef void (*multiband_drc_func)(const struct processing_module *mod, - const struct audio_stream __sparse_cache *source, - struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + struct audio_stream *sink, uint32_t frames); /* Multiband DRC component private data */ diff --git a/src/include/sof/audio/mux.h b/src/include/sof/audio/mux.h index 2c42c2506edd..e8eb9bc9de54 100644 --- a/src/include/sof/audio/mux.h +++ b/src/include/sof/audio/mux.h @@ -65,11 +65,11 @@ struct mux_stream_data { uint8_t reserved2[3]; // padding to ensure proper alignment of following instances } __attribute__((packed, aligned(4))); -typedef void(*demux_func)(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, uint32_t frames, +typedef void(*demux_func)(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream *source, uint32_t frames, struct mux_look_up *look_up); -typedef void(*mux_func)(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache **sources, uint32_t frames, +typedef void(*mux_func)(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream **sources, uint32_t frames, struct mux_look_up *look_up); /** diff --git a/src/include/sof/audio/pcm_converter.h b/src/include/sof/audio/pcm_converter.h index 09d20f5568b6..a06dc79f632a 100644 --- a/src/include/sof/audio/pcm_converter.h +++ b/src/include/sof/audio/pcm_converter.h @@ -45,8 +45,8 @@ struct audio_stream; * \param samples number of samples to convert * \return error code or number of processed samples. */ -typedef int (*pcm_converter_func)(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +typedef int (*pcm_converter_func)(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples); /** @@ -156,8 +156,8 @@ pcm_get_conversion_vc_function(enum sof_ipc_frame in_bits, * \param converter core conversion function working on linear memory regions * \return error code or number of processed samples */ -int pcm_convert_as_linear(const struct audio_stream __sparse_cache *source, uint32_t ioffset, - struct audio_stream __sparse_cache *sink, uint32_t ooffset, +int pcm_convert_as_linear(const struct audio_stream *source, uint32_t ioffset, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples, pcm_converter_lin_func converter); #endif /* __SOF_AUDIO_PCM_CONVERTER_H__ */ diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index d80e4380aa82..8dc5ea16d51d 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -100,7 +100,7 @@ struct pipeline_walk_context { int (*comp_func)(struct comp_dev *cd, struct comp_buffer *buffer, struct pipeline_walk_context *ctx, int dir); void *comp_data; - void (*buff_func)(struct comp_buffer __sparse_cache *buffer, void *data); + void (*buff_func)(struct comp_buffer *buffer, void *data); void *buff_data; struct comp_buffer *incoming; /**< pipelines to be scheduled after trigger walk */ diff --git a/src/include/sof/audio/selector.h b/src/include/sof/audio/selector.h index e07576430322..cd4aa926c7f4 100644 --- a/src/include/sof/audio/selector.h +++ b/src/include/sof/audio/selector.h @@ -100,8 +100,8 @@ struct sof_selector_avs_ipc4_config { }; #else -typedef void (*sel_func)(struct comp_dev *dev, struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *source, uint32_t frames); +typedef void (*sel_func)(struct comp_dev *dev, struct audio_stream *sink, + const struct audio_stream *source, uint32_t frames); #endif /** \brief Selector component private data. */ diff --git a/src/include/sof/audio/sink_api.h b/src/include/sof/audio/sink_api.h index 07172f332555..bb279166c167 100644 --- a/src/include/sof/audio/sink_api.h +++ b/src/include/sof/audio/sink_api.h @@ -54,13 +54,13 @@ struct sof_ipc_stream_params; * Retrieves size of free space available in sink (in bytes) * return number of free bytes in buffer available to immediate filling */ -size_t sink_get_free_size(struct sof_sink __sparse_cache *sink); +size_t sink_get_free_size(struct sof_sink *sink); /** * Retrieves size of free space available in sink (in frames) * return number of free bytes in buffer available to immediate filling */ -size_t sink_get_free_frames(struct sof_sink __sparse_cache *sink); +size_t sink_get_free_frames(struct sof_sink *sink); /** * Get a circular buffer to operate on (to write). @@ -81,7 +81,7 @@ size_t sink_get_free_frames(struct sof_sink __sparse_cache *sink); * @retval -ENODATA if req_size is bigger than free space * */ -int sink_get_buffer(struct sof_sink __sparse_cache *sink, size_t req_size, +int sink_get_buffer(struct sof_sink *sink, size_t req_size, void **data_ptr, void **buffer_start, size_t *buffer_size); /** @@ -96,7 +96,7 @@ int sink_get_buffer(struct sof_sink __sparse_cache *sink, size_t req_size, * commit_buffer with commit_size==MAXINT * @return proper error code (0 on success) */ -int sink_commit_buffer(struct sof_sink __sparse_cache *sink, size_t commit_size); +int sink_commit_buffer(struct sof_sink *sink, size_t commit_size); /** * Get total number of bytes processed by the sink (meaning - committed by sink_commit_buffer()) @@ -104,33 +104,33 @@ int sink_commit_buffer(struct sof_sink __sparse_cache *sink, size_t commit_size) * @param sink a handler to sink * @return total number of processed data */ -size_t sink_get_num_of_processed_bytes(struct sof_sink __sparse_cache *sink); +size_t sink_get_num_of_processed_bytes(struct sof_sink *sink); /** * sets counter of total number of bytes processed to zero */ -void sink_reset_num_of_processed_bytes(struct sof_sink __sparse_cache *sink); +void sink_reset_num_of_processed_bytes(struct sof_sink *sink); /** get size of a single audio frame (in bytes) */ -size_t sink_get_frame_bytes(struct sof_sink __sparse_cache *sink); +size_t sink_get_frame_bytes(struct sof_sink *sink); /** set of functions for retrieve audio parameters */ -enum sof_ipc_frame sink_get_frm_fmt(struct sof_sink __sparse_cache *sink); -enum sof_ipc_frame sink_get_valid_fmt(struct sof_sink __sparse_cache *sink); -uint32_t sink_get_rate(struct sof_sink __sparse_cache *sink); -uint32_t sink_get_channels(struct sof_sink __sparse_cache *sink); -uint32_t sink_get_buffer_fmt(struct sof_sink __sparse_cache *sink); -bool sink_get_overrun(struct sof_sink __sparse_cache *sink); +enum sof_ipc_frame sink_get_frm_fmt(struct sof_sink *sink); +enum sof_ipc_frame sink_get_valid_fmt(struct sof_sink *sink); +uint32_t sink_get_rate(struct sof_sink *sink); +uint32_t sink_get_channels(struct sof_sink *sink); +uint32_t sink_get_buffer_fmt(struct sof_sink *sink); +bool sink_get_overrun(struct sof_sink *sink); /** set of functions for setting audio parameters */ -int sink_set_frm_fmt(struct sof_sink __sparse_cache *sink, enum sof_ipc_frame frame_fmt); -int sink_set_valid_fmt(struct sof_sink __sparse_cache *sink, enum sof_ipc_frame valid_sample_fmt); -int sink_set_rate(struct sof_sink __sparse_cache *sink, unsigned int rate); -int sink_set_channels(struct sof_sink __sparse_cache *sink, unsigned int channels); -int sink_set_overrun(struct sof_sink __sparse_cache *sink, bool overrun_permitted); -int sink_set_buffer_fmt(struct sof_sink __sparse_cache *sink, uint32_t buffer_fmt); -void sink_set_obs(struct sof_sink __sparse_cache *sink, size_t obs); -size_t sink_get_obs(struct sof_sink __sparse_cache *sink); +int sink_set_frm_fmt(struct sof_sink *sink, enum sof_ipc_frame frame_fmt); +int sink_set_valid_fmt(struct sof_sink *sink, enum sof_ipc_frame valid_sample_fmt); +int sink_set_rate(struct sof_sink *sink, unsigned int rate); +int sink_set_channels(struct sof_sink *sink, unsigned int channels); +int sink_set_overrun(struct sof_sink *sink, bool overrun_permitted); +int sink_set_buffer_fmt(struct sof_sink *sink, uint32_t buffer_fmt); +void sink_set_min_free_space(struct sof_sink *sink, size_t min_free_space); +size_t sink_get_min_free_space(struct sof_sink *sink); /** * initial set of audio parameters, provided in sof_ipc_stream_params @@ -140,7 +140,7 @@ size_t sink_get_obs(struct sof_sink __sparse_cache *sink); * @param force_update tells the implementation that the params should override actual settings * @return 0 if success */ -int sink_set_params(struct sof_sink __sparse_cache *sink, +int sink_set_params(struct sof_sink *sink, struct sof_ipc_stream_params *params, bool force_update); /** @@ -158,7 +158,7 @@ int sink_set_params(struct sof_sink __sparse_cache *sink, * * @return 0 if success */ -int sink_set_alignment_constants(struct sof_sink __sparse_cache *sink, +int sink_set_alignment_constants(struct sof_sink *sink, const uint32_t byte_align, const uint32_t frame_align_req); diff --git a/src/include/sof/audio/sink_api_implementation.h b/src/include/sof/audio/sink_api_implementation.h index 15db32152039..23cec8dbb30e 100644 --- a/src/include/sof/audio/sink_api_implementation.h +++ b/src/include/sof/audio/sink_api_implementation.h @@ -27,18 +27,18 @@ struct sink_ops { /** * see comment of sink_get_free_size() */ - size_t (*get_free_size)(struct sof_sink __sparse_cache *sink); + size_t (*get_free_size)(struct sof_sink *sink); /** * see comment of sink_get_buffer() */ - int (*get_buffer)(struct sof_sink __sparse_cache *sink, size_t req_size, + int (*get_buffer)(struct sof_sink *sink, size_t req_size, void **data_ptr, void **buffer_start, size_t *buffer_size); /** * see comment of sink_commit_buffer() */ - int (*commit_buffer)(struct sof_sink __sparse_cache *sink, size_t commit_size); + int (*commit_buffer)(struct sof_sink *sink, size_t commit_size); /** * OPTIONAL: Notification to the sink implementation about changes in audio format @@ -49,20 +49,20 @@ struct sink_ops { * * @retval 0 if success, negative if new parameters are not supported */ - int (*on_audio_format_set)(struct sof_sink __sparse_cache *sink); + int (*on_audio_format_set)(struct sof_sink *sink); /** * OPTIONAL * see sink_set_params comments */ - int (*audio_set_ipc_params)(struct sof_sink __sparse_cache *sink, + int (*audio_set_ipc_params)(struct sof_sink *sink, struct sof_ipc_stream_params *params, bool force_update); /** * OPTIONAL * see comment for sink_set_alignment_constants */ - int (*set_alignment_constants)(struct sof_sink __sparse_cache *sink, + int (*set_alignment_constants)(struct sof_sink *sink, const uint32_t byte_align, const uint32_t frame_align_req); }; @@ -72,7 +72,9 @@ struct sof_sink { const struct sink_ops *ops; /** operations interface */ size_t requested_write_frag_size; /** keeps number of bytes requested by get_buffer() */ size_t num_of_bytes_processed; /** processed bytes counter */ - size_t obs; /** output buffer size as declared in module bind IPC */ + size_t min_free_space; /** minimum buffer space required by the module using sink + * it is module's OBS as declared in module bind IPC + */ struct sof_audio_stream_params *audio_stream_params; /** pointer to audio params */ }; @@ -86,7 +88,7 @@ struct sof_sink { * the implementation must ensure coherent access to the parameteres * in case of i.e. cross core shared queue, it must be located in non-cached memory */ -void sink_init(struct sof_sink __sparse_cache *sink, const struct sink_ops *ops, +void sink_init(struct sof_sink *sink, const struct sink_ops *ops, struct sof_audio_stream_params *audio_stream_params); #endif /* __SOF_SINK_API_IMPLEMENTATION_H__ */ diff --git a/src/include/sof/audio/sink_source_utils.h b/src/include/sof/audio/sink_source_utils.h index 8f550b1d2276..ca8752f07294 100644 --- a/src/include/sof/audio/sink_source_utils.h +++ b/src/include/sof/audio/sink_source_utils.h @@ -19,7 +19,7 @@ * if false, data will remain in the source * @param size number of bytes to be copied */ -int source_to_sink_copy(struct sof_source __sparse_cache *source, - struct sof_sink __sparse_cache *sink, bool free, size_t size); +int source_to_sink_copy(struct sof_source *source, + struct sof_sink *sink, bool free, size_t size); #endif /* SINK_SOURCE_UTILS_H */ diff --git a/src/include/sof/audio/smart_amp/smart_amp.h b/src/include/sof/audio/smart_amp/smart_amp.h index 6438d7f082bc..6417d17726a0 100644 --- a/src/include/sof/audio/smart_amp/smart_amp.h +++ b/src/include/sof/audio/smart_amp/smart_amp.h @@ -1,8 +1,12 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2020 Maxim Integrated. All rights reserved. + * Copyright(c) 2020 Maxim Integrated All rights reserved. * * Author: Ryan Lee + * + * Copyright(c) 2023 Google LLC. + * + * Author: Pin-chih Lin */ #ifndef __SOF_AUDIO_DSM_H__ @@ -11,6 +15,46 @@ #include #include +/* Smart Amplifier component is a two-layer structured design, i.e. generic + * layer and inner model layer. The latter can have various implementations + * respectively for Amplifier solution suppliers, while the former is the common + * part of Smart Amp process adaptable for all solutions. + * + * In structural aspect, one can regard generic layer as the glue code that + * wraps inner model in a SOF component. Ops are defined for interaction between + * two layers. Inner model is the solution-specific modular code, which may have + * static libraries linked as needed. The structure is figured below: + * + * SRC(FF) SINK(OUT) +-SRC(FB) bytectl + * +- SMART_AMP |^ comp ops | ^ | ^| + * | +------------------v|-------------v---------|------v-----------|v---------+ + * | | Generic Layer (chan remap/fmt conv) || | + * | | (memory mgr)--+------> :::::::::BUFFERS::::::::::::: |+> CONFIG | + * | +------------------|-|^-----------|---------^------|-----------^|---------+ + * | | || mod ops | | | || + * | +------------------v-v|-----------v---------|------v-----------|v---------+ + * | | Inner Model :::::::::::::::::::::BUFFERS::::::::::::::::::::::: | + * | | (solution-specific impl/wrapper) |+> MODEL | + * | +------------------------------|^------------------------------^----------+ + * +--- v| lib ops | CALDATA + * Static Libs (as needed) ----------+ + * Note: + * - FF(Feed-Forward): un-processed playback frame source + * - FB(Feedback): feedback reference frame source (from the capture pipeline) + * + * As illustrated above, generic layer handles the cross-communication for inner + * model and SOF pipeline flow, as well as the smart-amp common tasks including: + * 1. Channel remapping for input/output frames + * 2. Frame format conversion for input/output frames. It allows inner model to + * work with different format from SOF audio stream. + * (Now it only allows the bitdepth of inner model format >= SOF stream, + * e.g. inner model: S32_LE, SOF stream: S16_LE) + * 3. Full-management of runtime memory. That is, dynamic memory buffers either + * required by generic layer or inner model will be allocated/owned/released + * by generic layer. + * More details are stated in the comment of each struct/function later. + */ + /* Maximum number of channels for algorithm in */ #define SMART_AMP_FF_MAX_CH_NUM 2 /* Maximum number of channels for algorithm out */ @@ -18,173 +62,261 @@ /* Maximum number of channels for feedback */ #define SMART_AMP_FB_MAX_CH_NUM 4 -#define SMART_AMP_FRM_SZ 48 /* samples per 1ms */ +#define SMART_AMP_FRM_SZ 48 /* frames per 1ms */ #define SMART_AMP_FF_BUF_SZ (SMART_AMP_FRM_SZ * SMART_AMP_FF_MAX_CH_NUM) #define SMART_AMP_FB_BUF_SZ (SMART_AMP_FRM_SZ * SMART_AMP_FB_MAX_CH_NUM) -/* Maxim DSM(Dynamic Speaker Manangement) process buffer size */ -#define DSM_FRM_SZ 48 -#define DSM_FF_BUF_SZ (DSM_FRM_SZ * SMART_AMP_FF_MAX_CH_NUM) -#define DSM_FB_BUF_SZ (DSM_FRM_SZ * SMART_AMP_FB_MAX_CH_NUM) - #define SMART_AMP_FF_BUF_DB_SZ\ (SMART_AMP_FF_BUF_SZ * SMART_AMP_FF_MAX_CH_NUM) #define SMART_AMP_FB_BUF_DB_SZ\ (SMART_AMP_FB_BUF_SZ * SMART_AMP_FB_MAX_CH_NUM) -#define DSM_FF_BUF_DB_SZ (DSM_FF_BUF_SZ * SMART_AMP_FF_MAX_CH_NUM) -#define DSM_FB_BUF_DB_SZ (DSM_FB_BUF_SZ * SMART_AMP_FB_MAX_CH_NUM) - -/* DSM parameter table structure - * +--------------+-----------------+---------------------------------+ - * | ID (4 bytes) | VALUE (4 bytes) | 1st channel : | - * | | | 8 bytes per single parameter | - * +--------------+-----------------+---------------------------------+ - * | ... | ... | Repeat N times for N parameters | - * +--------------+-----------------+---------------------------------+ - * | ID (4 bytes) | VALUE (4 bytes) | 2nd channel : | - * | | | 8 bytes per single parameter | - * +--------------+-----------------+---------------------------------+ - * | ... | ... | Repeat N times for N parameters | - * +--------------+-----------------+---------------------------------+ - */ -enum dsm_param { - DSM_PARAM_ID = 0, - DSM_PARAM_VALUE, - DSM_PARAM_MAX -}; -#define DSM_SINGLE_PARAM_SZ (DSM_PARAM_MAX * SMART_AMP_FF_MAX_CH_NUM) +struct inner_model_ops; -union smart_amp_buf { - int16_t *buf16; - int32_t *buf32; +/* The common base for inner model data structs. Inner model should declare its + * model data struct while putting this base as the leading member of struct, e.g. + * struct solution_foo_mod_data { + * struct smart_amp_mod_data_base base; + * uint32_t foo_version; + * struct foo_parameter_set; + * ... + * }; + * + * Then implement mod_data_create() in its own C file, e.g. + * struct smart_amp_mod_data_base *mod_data_create(const struct comp_dev *dev) + * { + * struct solution_foo_mod_data *foo; + * foo = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*foo)); + * assert(foo); + * foo->base.dev = dev; + * foo->base.mod_ops = foo_ops; // declared somewhere as static const + * ... + * return &foo->base; + * } + */ +struct smart_amp_mod_data_base { + const struct comp_dev *dev; /* for logger tracing use only */ + const struct inner_model_ops *mod_ops; }; -struct smart_amp_ff_buf_struct_t { - int32_t *buf; - int avail; +/* The struct of memory buffer managed by generic layer. */ +struct smart_amp_buf { + void *data; + uint32_t size; }; -struct smart_amp_fb_buf_struct_t { - int32_t *buf; - int avail; - int rdy; +/* For memory allocation, generic layer plays the active role that queries the + * required memory size for inner model (then allocate and assign back) in + * some specific moments, i.e. once before and after model initialized. Inner + * model should consider buffers located and allocated onto 3 memory blocks in + * terms of usage: + * PRIVATE - allocated before model init - for libraries internal usage + * FRAME - allocated after model init - for audio frame buffer usage + * PARAM - allocated after model init - for parameter blob usage + */ +enum smart_amp_mod_memblk { + MOD_MEMBLK_PRIVATE = 0, + MOD_MEMBLK_FRAME, + MOD_MEMBLK_PARAM, + MOD_MEMBLK_MAX }; -struct smart_amp_buf_struct_t { - /* buffer : sof -> spk protection feed forward process */ - int32_t *frame_in; - /* buffer : sof <- spk protection feed forward process */ - int32_t *frame_out; - /* buffer : sof -> spk protection feedback process */ - int32_t *frame_iv; - /* buffer : feed forward process input */ - int32_t *input; - /* buffer : feed forward process output */ - int32_t *output; - /* buffer : feedback voltage */ - int32_t *voltage; - /* buffer : feedback current */ - int32_t *current; - /* buffer : feed forward variable length -> fixed length */ - struct smart_amp_ff_buf_struct_t ff; - /* buffer : feed forward variable length <- fixed length */ - struct smart_amp_ff_buf_struct_t ff_out; - /* buffer : feedback variable length -> fixed length */ - struct smart_amp_fb_buf_struct_t fb; +/* The intermediate audio data buffer in generic layer. */ +struct smart_amp_mod_stream { + struct smart_amp_buf buf; + uint32_t channels; + uint16_t frame_fmt; + union { + uint32_t consumed; /* for source (in frames) */ + uint32_t produced; /* for sink (in frames) */ + }; }; -struct param_buf_struct_t { - int id; - int value; -}; +/****************************************************************************** + * Generic functions: * + * The implementation is placed in smart_amp_generic.c * + ******************************************************************************/ -struct smart_amp_caldata { - uint32_t data_size; /* size of component's model data */ - void *data; /* model data pointer */ - uint32_t data_pos; /* data position for read/write */ -}; +typedef void (*smart_amp_src_func)(struct smart_amp_mod_stream *src_mod, + uint32_t frames, + const struct audio_stream __sparse_cache *src, + const int8_t *chan_map); -struct smart_amp_param_struct_t { - struct param_buf_struct_t param; /* variable to keep last parameter ID/value */ - struct smart_amp_caldata caldata; /* model data buffer */ - int pos; /* data position for read/write */ - int max_param; /* keep max number of DSM parameters */ -}; +typedef void (*smart_amp_sink_func)(const struct smart_amp_mod_stream *sink_mod, + uint32_t frames, + const struct audio_stream __sparse_cache *sink); -struct smart_amp_mod_struct_t { - struct smart_amp_buf_struct_t buf; - void *dsmhandle; - /* DSM variables for the initialization */ - int delayedsamples[SMART_AMP_FF_MAX_CH_NUM << 2]; - int circularbuffersize[SMART_AMP_FF_MAX_CH_NUM << 2]; - /* Number of samples of feed forward and feedback frame */ - int ff_fr_sz_samples; - int fb_fr_sz_samples; - int channelmask; - /* Number of channels of DSM */ - int nchannels; - /* Number of samples of feed forward channel */ - int ifsamples; - /* Number of samples of feedback channel */ - int ibsamples; - /* Number of processed samples */ - int ofsamples; - /* Channel bit dempth */ - int bitwidth; - struct smart_amp_param_struct_t param; +struct smart_amp_func_map { + uint16_t comp_fmt; + uint16_t mod_fmt; + smart_amp_src_func src_func; + smart_amp_sink_func sink_func; }; -typedef void (*smart_amp_func)(const struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, - const struct audio_stream __sparse_cache *feedback, - uint32_t frames); -struct smart_amp_func_map { - uint16_t frame_fmt; - smart_amp_func func; +extern const struct smart_amp_func_map src_sink_func_map[]; + +smart_amp_src_func smart_amp_get_src_func(uint16_t comp_fmt, uint16_t mod_fmt); +smart_amp_sink_func smart_amp_get_sink_func(uint16_t comp_fmt, uint16_t mod_fmt); + +/****************************************************************************** + * Inner model operations (mod ops): * + * Model implementations are mutual exclusive (separated by Kconfig). It * + * must be only one solution applicable per build. The solution-specific * + * implementation is placed in its own C file smart_amp_${SOLUTION}.c * + ******************************************************************************/ + +/** + * Creates the self-declared model data struct. + * Refer to "struct smart_amp_mod_data_base" for details of declaration. + * Args: + * dev - the comp_dev object for logger tracing use only. + * Returns: + * The pointer of "smart_amp_mod_data_base" which is the leading member in + * the created model data struct. + */ +struct smart_amp_mod_data_base *mod_data_create(const struct comp_dev *dev); + +/* All ops are mandatory. */ +struct inner_model_ops { + /** + * Initializes model. + * It will be called on comp_ops.create() by generic layer. + * Args: + * mod - the pointer of model data struct object. + * Returns: + * 0 or negative error code. + */ + int (*init)(struct smart_amp_mod_data_base *mod); + + /** + * Returns the required bytesize for the specific memblk. + * It will be called on comp_ops.create() by generic layer, before or after + * mod_ops.init() according to the memblk usage. + * Args: + * mod - the pointer of model data struct object. + * blk - the memblk usage type. + * Returns: + * The bytesize or negative error code. + */ + int (*query_memblk_size)(struct smart_amp_mod_data_base *mod, + enum smart_amp_mod_memblk blk); + + /** + * Sets the allocated memblk info. + * It should be called in sequence after mod_ops.query_memblk_size(). + * Args: + * mod - the pointer of model data struct object. + * blk - the memblk usage type. + * buf - the pointer of smart_amp_buf object including allocated memory. + * Returns: + * 0 or negative error code. + */ + int (*set_memblk)(struct smart_amp_mod_data_base *mod, + enum smart_amp_mod_memblk blk, + struct smart_amp_buf *buf); + + /** + * Returns the list of supported frame formats. + * It will be called on comp_ops.prepare() by generic layer. + * + * Inner model should report all supported formats in the list at once. + * Generic layer will resolve the applicable format according to this list and + * the formats requested from external source/sink stream buffers. If it turns + * out to be no format applicable, generic layer will report errors which will + * force the early-termination of the starting process for the whole pipeline. + * Args: + * mod - the pointer of model data struct object. + * mod_fmts - the pointer for returning the supported format list. + * Format values should be aligned to "enum sof_ipc_frame" and + * put in ascending order. + * num_mod_fmts - the pointer for returning the length of mod_fmts. + * Returns: + * 0 or negative error code. + */ + int (*get_supported_fmts)(struct smart_amp_mod_data_base *mod, + const uint16_t **mod_fmts, int *num_mod_fmts); + + /** + * Sets the frame format after resolved. + * It will be called on comp_ops.prepare() by generic layer, in sequence after + * mod_ops.get_supported_fmts() if the format is resolvable. + * + * Inner model should honor the received format on processing. The FF and FB + * frames (if available) will be put to the input buffers in the same format. + * It will be the last function called before audio stream starts processing. + * needed, inner model should execute the preparing tasks as soon as it is + * called. + * Args: + * mod - the pointer of model data struct object. + * mod_fmt - the frame format to be applied.. + * Returns: + * 0 or negative error code. + */ + int (*set_fmt)(struct smart_amp_mod_data_base *mod, uint16_t mod_fmt); + + /** + * Runs the feed-forward process. + * Args: + * mod - the pointer of model data struct object. + * frames - the number of frames to be processed. + * in - the pointer of input stream buffer object. Inner model should set + * "consumed" to the number of conusmed frames. + * out - the pointer of output stream buffer object. Inner model should set + * "produced" to the number of produced frames. + * Returns: + * 0 or negative error code. + */ + int (*ff_proc)(struct smart_amp_mod_data_base *mod, + uint32_t frames, + struct smart_amp_mod_stream *in, + struct smart_amp_mod_stream *out); + + /** + * Runs the feedback process. + * Args: + * mod - the pointer of model data struct object. + * frames - the number of frames to be processed. + * in - the pointer of input stream buffer object. Inner model should set + * "consumed" to the number of conusmed frames. + * Returns: + * 0 or negative error code. + */ + int (*fb_proc)(struct smart_amp_mod_data_base *mod, + uint32_t frames, + struct smart_amp_mod_stream *in); + + /** + * Gets config data from model. + * Args: + * mod - the pointer of model data struct object. + * cdata - the pointer of sof_ipc_ctrl_data object. + * size - the maximal size for config data to read. + * Returns: + * 0 or negative error code. + */ + int (*get_config)(struct smart_amp_mod_data_base *mod, + struct sof_ipc_ctrl_data *cdata, uint32_t size); + + /** + * Sets config data to model. + * Args: + * mod - the pointer of model data struct object. + * cdata - the pointer of sof_ipc_ctrl_data object. + * Returns: + * 0 or negative error code. + */ + int (*set_config)(struct smart_amp_mod_data_base *mod, + struct sof_ipc_ctrl_data *cdata); + + /** + * Resets model. + * It will be called on comp_ops.reset() by generic layer. + * Args: + * mod - the pointer of model data struct object. + * Returns: + * 0 or negative error code. + */ + int (*reset)(struct smart_amp_mod_data_base *mod); }; -/* Component initialization */ -int smart_amp_init(struct smart_amp_mod_struct_t *hspk, struct comp_dev *dev); -/* Component memory flush */ -int smart_amp_flush(struct smart_amp_mod_struct_t *hspk, struct comp_dev *dev); -/* Feed forward processing function */ -int smart_amp_ff_copy(struct comp_dev *dev, uint32_t frames, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, int8_t *chan_map, - struct smart_amp_mod_struct_t *hspk, - uint32_t num_ch_in, uint32_t num_ch_out); -/* Feedback processing function */ -int smart_amp_fb_copy(struct comp_dev *dev, uint32_t frames, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, int8_t *chan_map, - struct smart_amp_mod_struct_t *hspk, - uint32_t num_ch); -/* memory usage calculation for the component */ -int smart_amp_get_memory_size(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev); -/* supported audio format check */ -int smart_amp_check_audio_fmt(int sample_rate, int ch_num); - -/* this function return number of parameters supported */ -int smart_amp_get_num_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev); -/* this function update whole parameter table */ -int smart_amp_get_all_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev); -/* parameter read function */ -int maxim_dsm_get_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata, int size); -/* parameter write function */ -int maxim_dsm_set_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata); -/* parameter restoration */ -int maxim_dsm_restore_param(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev); -/* parameter forced read, ignore cache */ -int maxim_dsm_get_param_forced(struct smart_amp_mod_struct_t *hspk, - struct comp_dev *dev); #endif diff --git a/src/include/sof/audio/source_api.h b/src/include/sof/audio/source_api.h index bfbcf530a81b..70b3ce38c909 100644 --- a/src/include/sof/audio/source_api.h +++ b/src/include/sof/audio/source_api.h @@ -54,13 +54,13 @@ struct sof_ipc_stream_params; * Retrieves size of available data (in bytes) * return number of bytes that are available for immediate use */ -size_t source_get_data_available(struct sof_source __sparse_cache *source); +size_t source_get_data_available(struct sof_source *source); /** * Retrieves size of available data (in frames) * return number of bytes that are available for immediate use */ -size_t source_get_data_frames_available(struct sof_source __sparse_cache *source); +size_t source_get_data_frames_available(struct sof_source *source); /** * Retrieves a fragment of circular data to be used by the caller (to read) @@ -93,8 +93,8 @@ size_t source_get_data_frames_available(struct sof_source __sparse_cache *source * * @retval -ENODATA if req_size is bigger than available data */ -int source_get_data(struct sof_source __sparse_cache *source, size_t req_size, - void **data_ptr, void **buffer_start, size_t *buffer_size); +int source_get_data(struct sof_source *source, size_t req_size, + void const **data_ptr, void const **buffer_start, size_t *buffer_size); /** * Releases fragment previously obtained by source_get_data() @@ -110,38 +110,38 @@ int source_get_data(struct sof_source __sparse_cache *source, size_t req_size, * * @return proper error code (0 on success) */ -int source_release_data(struct sof_source __sparse_cache *source, size_t free_size); +int source_release_data(struct sof_source *source, size_t free_size); /** * Get total number of bytes processed by the source (meaning - freed by source_release_data()) */ -size_t source_get_num_of_processed_bytes(struct sof_source __sparse_cache *source); +size_t source_get_num_of_processed_bytes(struct sof_source *source); /** * sets counter of total number of bytes processed to zero */ -void source_reset_num_of_processed_bytes(struct sof_source __sparse_cache *source); +void source_reset_num_of_processed_bytes(struct sof_source *source); /** get size of a single audio frame (in bytes) */ -size_t source_get_frame_bytes(struct sof_source __sparse_cache *source); +size_t source_get_frame_bytes(struct sof_source *source); /** set of functions for retrieve audio parameters */ -enum sof_ipc_frame source_get_frm_fmt(struct sof_source __sparse_cache *source); -enum sof_ipc_frame source_get_valid_fmt(struct sof_source __sparse_cache *source); -unsigned int source_get_rate(struct sof_source __sparse_cache *source); -unsigned int source_get_channels(struct sof_source __sparse_cache *source); -uint32_t source_get_buffer_fmt(struct sof_source __sparse_cache *source); -bool source_get_underrun(struct sof_source __sparse_cache *source); +enum sof_ipc_frame source_get_frm_fmt(struct sof_source *source); +enum sof_ipc_frame source_get_valid_fmt(struct sof_source *source); +unsigned int source_get_rate(struct sof_source *source); +unsigned int source_get_channels(struct sof_source *source); +uint32_t source_get_buffer_fmt(struct sof_source *source); +bool source_get_underrun(struct sof_source *source); /** set of functions for setting audio parameters */ -int source_set_valid_fmt(struct sof_source __sparse_cache *source, +int source_set_valid_fmt(struct sof_source *source, enum sof_ipc_frame valid_sample_fmt); -int source_set_rate(struct sof_source __sparse_cache *source, unsigned int rate); -int source_set_channels(struct sof_source __sparse_cache *source, unsigned int channels); -int source_set_underrun(struct sof_source __sparse_cache *source, bool underrun_permitted); -int source_set_buffer_fmt(struct sof_source __sparse_cache *source, uint32_t buffer_fmt); -void source_set_ibs(struct sof_source __sparse_cache *source, size_t ibs); -size_t source_get_ibs(struct sof_source __sparse_cache *source); +int source_set_rate(struct sof_source *source, unsigned int rate); +int source_set_channels(struct sof_source *source, unsigned int channels); +int source_set_underrun(struct sof_source *source, bool underrun_permitted); +int source_set_buffer_fmt(struct sof_source *source, uint32_t buffer_fmt); +void source_set_min_available(struct sof_source *source, size_t min_available); +size_t source_get_min_available(struct sof_source *source); /** * initial set of audio parameters, provided in sof_ipc_stream_params @@ -151,7 +151,7 @@ size_t source_get_ibs(struct sof_source __sparse_cache *source); * @param force_update tells the implementation that the params should override actual settings * @return 0 if success */ -int source_set_params(struct sof_source __sparse_cache *source, +int source_set_params(struct sof_source *source, struct sof_ipc_stream_params *params, bool force_update); /** @@ -169,7 +169,7 @@ int source_set_params(struct sof_source __sparse_cache *source, * * @return 0 if success */ -int source_set_alignment_constants(struct sof_source __sparse_cache *source, +int source_set_alignment_constants(struct sof_source *source, const uint32_t byte_align, const uint32_t frame_align_req); diff --git a/src/include/sof/audio/source_api_implementation.h b/src/include/sof/audio/source_api_implementation.h index c75330cde019..606141c92dfb 100644 --- a/src/include/sof/audio/source_api_implementation.h +++ b/src/include/sof/audio/source_api_implementation.h @@ -27,18 +27,18 @@ struct source_ops { /** * see comment of source_get_data_available() */ - size_t (*get_data_available)(struct sof_source __sparse_cache *source); + size_t (*get_data_available)(struct sof_source *source); /** * see comment of source_get_data_available() */ - int (*get_data)(struct sof_source __sparse_cache *source, size_t req_size, - void **data_ptr, void **buffer_start, size_t *buffer_size); + int (*get_data)(struct sof_source *source, size_t req_size, + void const **data_ptr, void const **buffer_start, size_t *buffer_size); /** * see comment of source_release_data() */ - int (*release_data)(struct sof_source __sparse_cache *source, size_t free_size); + int (*release_data)(struct sof_source *source, size_t free_size); /** * OPTIONAL: Notification to the source implementation about changes in audio format @@ -49,20 +49,20 @@ struct source_ops { * * @retval 0 if success, negative if new parameteres are not supported */ - int (*on_audio_format_set)(struct sof_source __sparse_cache *source); + int (*on_audio_format_set)(struct sof_source *source); /** * OPTIONAL * see source_set_params comments */ - int (*audio_set_ipc_params)(struct sof_source __sparse_cache *source, + int (*audio_set_ipc_params)(struct sof_source *source, struct sof_ipc_stream_params *params, bool force_update); /** * OPTIONAL * see comment for source_set_alignment_constants */ - int (*set_alignment_constants)(struct sof_source __sparse_cache *source, + int (*set_alignment_constants)(struct sof_source *source, const uint32_t byte_align, const uint32_t frame_align_req); }; @@ -72,7 +72,11 @@ struct sof_source { const struct source_ops *ops; size_t requested_read_frag_size; /** keeps size of data obtained by get_data() */ size_t num_of_bytes_processed; /** processed bytes counter */ - size_t ibs; /** input buffer size as declared in module bind IPC */ + size_t min_available; /** minimum data available required by the module using + * source + * it is module's IBS as declared in module bind IPC + */ + struct sof_audio_stream_params *audio_stream_params; }; @@ -86,7 +90,7 @@ struct sof_source { * the implementation must ensure coherent access to the parameteres * in case of i.e. cross core shared queue, it must be located in non-cached memory */ -void source_init(struct sof_source __sparse_cache *source, const struct source_ops *ops, +void source_init(struct sof_source *source, const struct source_ops *ops, struct sof_audio_stream_params *audio_stream_params); #endif /* __SOF_SOURCE_API_IMPLEMENTATION_H__ */ diff --git a/src/include/sof/audio/tdfb/tdfb_comp.h b/src/include/sof/audio/tdfb/tdfb_comp.h index ce48760e22a6..bd229c80f211 100644 --- a/src/include/sof/audio/tdfb/tdfb_comp.h +++ b/src/include/sof/audio/tdfb/tdfb_comp.h @@ -17,6 +17,10 @@ #include #include +#if CONFIG_IPC_MAJOR_4 +#include +#endif + /* Select optimized code variant when xt-xcc compiler is used */ #if defined __XCC__ #include @@ -110,6 +114,14 @@ struct tdfb_comp_data { int frames); }; +#if CONFIG_IPC_MAJOR_4 +struct tdfb_notification_payload { + struct sof_ipc4_notify_module_data module_data; + struct sof_ipc4_control_msg_payload control_msg; + struct sof_ipc4_ctrl_value_chan control_value; /* One channel value */ +}; +#endif + #if CONFIG_FORMAT_S16LE void tdfb_fir_s16(struct tdfb_comp_data *cd, struct input_stream_buffer *bsource, diff --git a/src/include/sof/coherent.h b/src/include/sof/coherent.h index 4ca5120cfee9..8e06fb466a66 100644 --- a/src/include/sof/coherent.h +++ b/src/include/sof/coherent.h @@ -80,9 +80,23 @@ struct coherent { /* debug sharing amongst cores */ #ifdef COHERENT_CHECK_NONSHARED_CORES + +#define CORE_CHECK_STRUCT_FIELD uint32_t __core; bool __is_shared +#define CORE_CHECK_STRUCT_INIT(_c, is_shared) { (_c)->__core = cpu_get_id(); \ + (_c)->__is_shared = is_shared; } +#define CORE_CHECK_STRUCT(_c) { assert(!!(_c)->__is_shared == !!is_uncached(_c)); \ + assert(cpu_get_id() == (_c)->__core || (_c)->__is_shared); } + #define CHECK_COHERENT_CORE(_c) assert((_c)->core == cpu_get_id()) + #else + +#define CORE_CHECK_STRUCT_FIELD +#define CORE_CHECK_STRUCT_INIT(_c, is_shared) +#define CORE_CHECK_STRUCT(_c) + #define CHECK_COHERENT_CORE(_c) + #endif #ifdef __ZEPHYR__ diff --git a/src/include/sof/drivers/micfil.h b/src/include/sof/drivers/micfil.h new file mode 100644 index 000000000000..5d6828102c97 --- /dev/null +++ b/src/include/sof/drivers/micfil.h @@ -0,0 +1,174 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2023 NXP + * + * Author: Daniel Baluta + */ + +#ifndef __SOF_DRIVERS_MICFIL_H__ +#define __SOF_DRIVERS_MICFIL_H__ + +#include +#include +#include +#include +#include +#include + +extern const struct dai_driver micfil_driver; + +/* MICFIL private data */ +struct micfil_pdata { + int quality; + struct sof_ipc_dai_config config; + struct sof_ipc_dai_micfil_params params; +}; + +/* MICFIL Register Map */ +#define REG_MICFIL_CTRL1 0x00 +#define REG_MICFIL_CTRL2 0x04 +#define REG_MICFIL_STAT 0x08 +#define REG_MICFIL_FIFO_CTRL 0x10 +#define REG_MICFIL_FIFO_STAT 0x14 +#define REG_MICFIL_DATACH0 0x24 +#define REG_MICFIL_DATACH1 0x28 +#define REG_MICFIL_DATACH2 0x2C +#define REG_MICFIL_DATACH3 0x30 +#define REG_MICFIL_DATACH4 0x34 +#define REG_MICFIL_DATACH5 0x38 +#define REG_MICFIL_DATACH6 0x3C +#define REG_MICFIL_DATACH7 0x40 +#define REG_MICFIL_DC_CTRL 0x64 +#define REG_MICFIL_OUT_CTRL 0x74 +#define REG_MICFIL_OUT_STAT 0x7C +#define REG_MICFIL_VAD0_CTRL1 0x90 +#define REG_MICFIL_VAD0_CTRL2 0x94 + +#define REG_MICFIL_VAD0_STAT 0x98 +#define REG_MICFIL_VAD0_SCONFIG 0x9C +#define REG_MICFIL_VAD0_NCONFIG 0xA0 +#define REG_MICFIL_VAD0_NDATA 0xA4 +#define REG_MICFIL_VAD0_ZCD 0xA8 + +/* MICFIL Control Register 1 -- REG_MICFILL_CTRL1 0x00 */ +#define MICFIL_CTRL1_MDIS BIT(31) +#define MICFIL_CTRL1_DOZEN BIT(30) +#define MICFIL_CTRL1_PDMIEN BIT(29) +#define MICFIL_CTRL1_DBG BIT(28) +#define MICFIL_CTRL1_SRES BIT(27) +#define MICFIL_CTRL1_DBGE BIT(26) +#define MICFIL_CTRL1_CHNEN MASK(7, 0) + +#define MICFIL_CTRL1_DISEL_DISABLE 0 +#define MICFIL_CTRL1_DISEL_DMA 1 +#define MICFIL_CTRL1_DISEL_IRQ 2 +#define MICFIL_CTRL1_DISEL_BITS(x) SET_BITS(25, 24, x) +#define MICFIL_CTRL1_DISEL MASK(25, 24) +#define MICFIL_CTRL1_ERREN BIT(23) +#define MICFIL_CTRL1_CHEN(ch) BIT(ch) + +/* MICFIL Control Register 2 -- REG_MICFILL_CTRL2 0x04 */ +#define MICFIL_CTRL2_QSEL_SHIFT 25 +#define MICFIL_CTRL2_QSEL MASK(27, 25) +#define MICFIL_CTRL2_QSEL_BITS(x) SET_BITS(27, 25, x) +#define MICFIL_QSEL_MEDIUM_QUALITY 0 +#define MICFIL_QSEL_HIGH_QUALITY 1 +#define MICFIL_QSEL_LOW_QUALITY 7 +#define MICFIL_QSEL_VLOW0_QUALITY 6 +#define MICFIL_QSEL_VLOW1_QUALITY 5 +#define MICFIL_QSEL_VLOW2_QUALITY 4 + +#define MICFIL_CTRL2_CICOSR MASK(19, 16) +#define MICFIL_CTRL2_CICOSR_SHIFT 16 +#define MICFIL_CTRL2_CICOSR_BITS(x) SET_BITS(19, 16, x) +#define MICFIL_CTRL2_CLKDIV MASK(7, 0) +#define MICFIL_CTRL2_CLKDIV_BITS(x) SET_BITS(7, 0, x) + +/* MICFIL Status Register -- REG_MICFIL_STAT 0x08 */ +#define MICFIL_STAT_BSY_FIL BIT(31) +#define MICFIL_STAT_FIR_RDY BIT(30) +#define MICFIL_STAT_LOWFREQF BIT(29) +#define MICFIL_STAT_CHXF(ch) BIT(ch) + +/* MICFIL FIFO Control Register -- REG_MICFIL_FIFO_CTRL 0x10 */ +#define MICFIL_FIFO_CTRL_FIFOWMK MASK(2, 0) +#define MICFIL_FIFO_CTRL_FIFOWMK_BITS(x) SET_BITS(2, 0, x) + +/* MICFIL FIFO Status Register -- REG_MICFIL_FIFO_STAT 0x14 */ +#define MICFIL_FIFO_STAT_FIFOX_OVER(ch) BIT(ch) +#define MICFIL_FIFO_STAT_FIFOX_UNDER(ch) BIT((ch) + 8) + +/* MICFIL DC Remover Control Register -- REG_MICFIL_DC_CTRL */ +#define MICFIL_DC_CTRL_CONFIG MASK(15, 0) +#define MICFIL_DC_CHX_SHIFT(ch) ((ch) << 1) +#define MICFIL_DC_CHX(ch) MASK((((ch) << 1) + 1), ((ch) << 1)) +#define MICFIL_DC_CUTOFF_21HZ 0 +#define MICFIL_DC_CUTOFF_83HZ 1 +#define MICFIL_DC_CUTOFF_152Hz 2 +#define MICFIL_DC_BYPASS 3 + +/* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/ +#define MICFIL_VAD0_CTRL1_CHSEL MASK(26, 24) +#define MICFIL_VAD0_CTRL1_CICOSR MASK(19, 16) +#define MICFIL_VAD0_CTRL1_INITT MASK(12, 8) +#define MICFIL_VAD0_CTRL1_ST10 BIT(4) +#define MICFIL_VAD0_CTRL1_ERIE BIT(3) +#define MICFIL_VAD0_CTRL1_IE BIT(2) +#define MICFIL_VAD0_CTRL1_RST BIT(1) +#define MICFIL_VAD0_CTRL1_EN BIT(0) + +/* MICFIL HWVAD0 Control 2 Register -- REG_MICFIL_VAD0_CTRL2*/ +#define MICFIL_VAD0_CTRL2_FRENDIS BIT(31) +#define MICFIL_VAD0_CTRL2_PREFEN BIT(30) +#define MICFIL_VAD0_CTRL2_FOUTDIS BIT(28) +#define MICFIL_VAD0_CTRL2_FRAMET MASK(21, 16) +#define MICFIL_VAD0_CTRL2_INPGAIN MASK(11, 8) +#define MICFIL_VAD0_CTRL2_HPF MASK(1, 0) + +/* MICFIL HWVAD0 Signal CONFIG Register -- REG_MICFIL_VAD0_SCONFIG */ +#define MICFIL_VAD0_SCONFIG_SFILEN BIT(31) +#define MICFIL_VAD0_SCONFIG_SMAXEN BIT(30) +#define MICFIL_VAD0_SCONFIG_SGAIN MASK(3, 0) + +/* MICFIL HWVAD0 Noise CONFIG Register -- REG_MICFIL_VAD0_NCONFIG */ +#define MICFIL_VAD0_NCONFIG_NFILAUT BIT(31) +#define MICFIL_VAD0_NCONFIG_NMINEN BIT(30) +#define MICFIL_VAD0_NCONFIG_NDECEN BIT(29) +#define MICFIL_VAD0_NCONFIG_NOREN BIT(28) +#define MICFIL_VAD0_NCONFIG_NFILADJ MASK(12, 8) +#define MICFIL_VAD0_NCONFIG_NGAIN MASK(3, 0) + +/* MICFIL HWVAD0 Zero-Crossing Detector - REG_MICFIL_VAD0_ZCD */ +#define MICFIL_VAD0_ZCD_ZCDTH MASK(25, 16) +#define MICFIL_VAD0_ZCD_ZCDADJ MASK(11, 8) +#define MICFIL_VAD0_ZCD_ZCDAND BIT(4) +#define MICFIL_VAD0_ZCD_ZCDAUT BIT(2) +#define MICFIL_VAD0_ZCD_ZCDEN BIT(0) + +/* MICFIL HWVAD0 Status Register - REG_MICFIL_VAD0_STAT */ +#define MICFIL_VAD0_STAT_INITF BIT(31) +#define MICFIL_VAD0_STAT_INSATF BIT(16) +#define MICFIL_VAD0_STAT_EF BIT(15) +#define MICFIL_VAD0_STAT_IF BIT(0) + +/* MICFIL Output Control Register */ +#define MICFIL_OUTGAIN_CHX_SHIFT(v) (4 * (v)) + +/* Constants */ +#define MICFIL_OUTPUT_CHANNELS 8 +#define MICFIL_FIFO_NUM 8 + +#define FIFO_PTRWID 3 +#define FIFO_LEN BIT(FIFO_PTRWID) + +#define MICFIL_IRQ_LINES 4 +#define MICFIL_MAX_RETRY 25 +#define MICFIL_SLEEP_MIN 90000 /* in us */ +#define MICFIL_SLEEP_MAX 100000 /* in us */ +#define MICFIL_DMA_MAXBURST_RX 6 + +/* HWVAD Constants */ +#define MICFIL_HWVAD_ENVELOPE_MODE 0 +#define MICFIL_HWVAD_ENERGY_MODE 1 + +#endif /* __SOF_DRIVERS_MICFIL_H__ */ diff --git a/src/include/sof/drivers/sdma.h b/src/include/sof/drivers/sdma.h index d3c9668157a8..c5b8d0e1ff25 100644 --- a/src/include/sof/drivers/sdma.h +++ b/src/include/sof/drivers/sdma.h @@ -151,7 +151,7 @@ #define SDMA_SCRIPT_SHP2MCU_OFF 893 #define SDMA_SCRIPT_MCU2SHP_OFF 962 -#ifdef CONFIG_SDMA_SCRIPT_CODE +#if CONFIG_HAVE_SDMA_FIRMWARE #include "sdma_script_code_imx7d_4_5.h" #endif diff --git a/src/include/sof/drivers/timestamp.h b/src/include/sof/drivers/timestamp.h deleted file mode 100644 index ff867dc1e33b..000000000000 --- a/src/include/sof/drivers/timestamp.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * - * Copyright(c) 2019 Intel Corporation. All rights reserved. - */ - -#ifndef __SOF_DRIVERS_TIMESTAMP_H__ -#define __SOF_DRIVERS_TIMESTAMP_H__ - -#include - -struct dai; -struct timestamp_cfg; -struct timestamp_data; - -/* HDA */ -int timestamp_hda_config(struct dai *dai, struct timestamp_cfg *cfg); -int timestamp_hda_start(struct dai *dai, struct timestamp_cfg *cfg); -int timestamp_hda_stop(struct dai *dai, struct timestamp_cfg *cfg); -int timestamp_hda_get(struct dai *dai, struct timestamp_cfg *cfg, - struct timestamp_data *tsd); - -/* DMIC */ -int timestamp_dmic_config(struct dai *dai, struct timestamp_cfg *cfg); -int timestamp_dmic_start(struct dai *dai, struct timestamp_cfg *cfg); -int timestamp_dmic_stop(struct dai *dai, struct timestamp_cfg *cfg); -int timestamp_dmic_get(struct dai *dai, struct timestamp_cfg *cfg, - struct timestamp_data *tsd); - -/* SSP */ -int timestamp_ssp_config(struct dai *dai, struct timestamp_cfg *cfg); -int timestamp_ssp_start(struct dai *dai, struct timestamp_cfg *cfg); -int timestamp_ssp_stop(struct dai *dai, struct timestamp_cfg *cfg); -int timestamp_ssp_get(struct dai *dai, struct timestamp_cfg *cfg, - struct timestamp_data *tsd); - -#endif /* __SOF_DRIVERS_TIMESTAMP_H__ */ diff --git a/src/include/sof/ipc/topology.h b/src/include/sof/ipc/topology.h index 810df643fc13..34748379dbc2 100644 --- a/src/include/sof/ipc/topology.h +++ b/src/include/sof/ipc/topology.h @@ -56,7 +56,7 @@ int ipc4_chain_dma_state(struct comp_dev *dev, struct ipc4_chain_dma *cdma); int ipc4_create_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma); int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma, bool *delay); int ipc4_process_on_core(uint32_t core, bool blocking); -int ipc4_pipeline_complete(struct ipc *ipc, uint32_t comp_id); +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_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); diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index 49fbd2e02aa8..98e174a43c8d 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -33,6 +33,7 @@ #include #include #include +#include /** \addtogroup sof_dai_drivers DAI Drivers * DAI Drivers API specification. @@ -52,30 +53,6 @@ struct dai { struct k_spinlock lock; /* protect properties */ }; -struct timestamp_cfg { - uint32_t walclk_rate; /* Rate in Hz, e.g. 19200000 */ - int type; /* SSP, DMIC, HDA, etc. */ - int direction; /* Playback, capture */ - int index; /* For SSPx to select correct timestamp register */ - int dma_id; /* GPDMA id*/ - int dma_chan_index; /* Used GPDMA channel */ - int dma_chan_count; /* Channels in single GPDMA */ -}; - -struct timestamp_data { - uint64_t walclk; /* Wall clock */ - uint64_t sample; /* Sample count */ - uint32_t walclk_rate; /* Rate in Hz, e.g. 19200000 */ -}; - -struct timestamp_ops { - int (*ts_config)(struct dai *dai, struct timestamp_cfg *cfg); - int (*ts_start)(struct dai *dai, struct timestamp_cfg *cfg); - int (*ts_stop)(struct dai *dai, struct timestamp_cfg *cfg); - int (*ts_get)(struct dai *dai, struct timestamp_cfg *cfg, - struct timestamp_data *tsd); -}; - union hdalink_cfg { uint16_t full; struct { @@ -141,7 +118,7 @@ struct dai_data { struct comp_dev *dai_dev; struct comp_buffer *dma_buffer; struct comp_buffer *local_buffer; - struct timestamp_cfg ts_config; + struct dai_ts_cfg ts_config; struct dai *dai; struct dma *dma; struct dai_group *group; /* NULL if no group assigned */ diff --git a/src/include/sof/math/fir_hifi3.h b/src/include/sof/math/fir_hifi3.h index a3d4b19ce0ce..aa1102ef2a1f 100644 --- a/src/include/sof/math/fir_hifi3.h +++ b/src/include/sof/math/fir_hifi3.h @@ -48,7 +48,7 @@ static inline void fir_core_setup_circular(struct fir_state_32x16 *fir) } /* Setup circular for component buffer */ -static inline void fir_comp_setup_circular(const struct audio_stream __sparse_cache *buffer) +static inline void fir_comp_setup_circular(const struct audio_stream *buffer) { AE_SETCBEGIN0(audio_stream_get_addr(buffer)); AE_SETCEND0(audio_stream_get_end_addr(buffer)); diff --git a/src/include/sof/probe/probe.h b/src/include/sof/probe/probe.h index 22522fb09fe3..7b6623737895 100644 --- a/src/include/sof/probe/probe.h +++ b/src/include/sof/probe/probe.h @@ -17,6 +17,11 @@ */ typedef void(*probe_logging_hook_t)(uint8_t *buffer, size_t length); +#if CONFIG_LOG_BACKEND_SOF_PROBE +void probe_logging_hook(uint8_t *buffer, size_t length); +const struct log_backend *log_backend_probe_get(void); +#endif + /** * @brief Initialize the probe logging backend. * diff --git a/src/include/sof/samples/audio/smart_amp_test.h b/src/include/sof/samples/audio/smart_amp_test.h index 7f24b5c37de8..3feda5005125 100644 --- a/src/include/sof/samples/audio/smart_amp_test.h +++ b/src/include/sof/samples/audio/smart_amp_test.h @@ -8,7 +8,6 @@ #ifndef __SOF_AUDIO_SMART_AMP_H__ #define __SOF_AUDIO_SMART_AMP_H__ -#include #include #include diff --git a/src/include/sof/schedule/dp_schedule.h b/src/include/sof/schedule/dp_schedule.h index 81650c563d80..9b7f85c7e798 100644 --- a/src/include/sof/schedule/dp_schedule.h +++ b/src/include/sof/schedule/dp_schedule.h @@ -13,6 +13,8 @@ #include #include +struct processing_module; + /** * * DP scheduler is a scheduler that creates a separate preemptible Zephyr thread for each SOF task @@ -49,9 +51,6 @@ * */ -/** \brief tell the scheduler to run the task immediately, even if LL tick is not yet running */ -#define SCHEDULER_DP_RUN_TASK_IMMEDIATELY ((uint64_t)-1) - /** * \brief Init the Data Processing scheduler */ @@ -64,7 +63,7 @@ int scheduler_dp_init(void); * \param[out] task pointer, pointer to allocated task structure will be return * \param[in] uid pointer to UUID of the task * \param[in] ops pointer to task functions - * \param[in] data pointer to the thread private data + * \param[in] mod pointer to the module to be run * \param[in] core CPU the thread should run on * \param[in] stack_size size of stack for a zephyr task * \param[in] task_priority priority of the zephyr task @@ -72,7 +71,7 @@ int scheduler_dp_init(void); int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid, const struct task_ops *ops, - void *data, + struct processing_module *mod, uint16_t core, size_t stack_size, uint32_t task_priority); diff --git a/src/include/sof/trace/trace.h b/src/include/sof/trace/trace.h index d3953bd16afe..737f9913cf6f 100644 --- a/src/include/sof/trace/trace.h +++ b/src/include/sof/trace/trace.h @@ -233,19 +233,26 @@ void _log_sofdict(log_func_t sofdict_logf, bool atomic, const void *log_entry, #ifdef CONFIG_LIBRARY -extern int test_bench_trace; +#include + +/* trace level used on host configurations */ +extern int host_trace_level; + char *get_trace_class(uint32_t trace_class); #define _log_message(ignored_log_func, atomic, level, comp_class, ctx, id_1, id_2, format, ...) \ -do { \ - (void)ctx; \ - (void)id_1; \ - (void)id_2; \ - if (test_bench_trace) { \ - char *msg = "(%s:%d) " format; \ - fprintf(stderr, msg, strrchr(__FILE__, '/') + 1,\ - __LINE__, ##__VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } \ +do { \ + (void)ctx; \ + (void)id_1; \ + (void)id_2; \ + struct timeval tv; \ + char *msg = "(%s:%d) " format; \ + if (level >= host_trace_level) { \ + gettimeofday(&tv, NULL); \ + fprintf(stderr, "%ld.%6.6ld:", tv.tv_sec, tv.tv_usec); \ + fprintf(stderr, msg, strrchr(__FILE__, '/') + 1, \ + __LINE__, ##__VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } \ } while (0) #define trace_point(x) do {} while (0) diff --git a/src/ipc/ipc-helper.c b/src/ipc/ipc-helper.c index bbcec49698f0..44983f6e6f95 100644 --- a/src/ipc/ipc-helper.c +++ b/src/ipc/ipc-helper.c @@ -36,7 +36,7 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); /* create a new component in the pipeline */ -struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc) +struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc, bool is_shared) { struct comp_buffer *buffer; @@ -44,7 +44,8 @@ struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc) desc->size, desc->comp.pipeline_id, desc->comp.id, desc->flags); /* allocate buffer */ - buffer = buffer_alloc(desc->size, desc->caps, desc->flags, PLATFORM_DCACHE_ALIGN); + buffer = buffer_alloc(desc->size, desc->caps, desc->flags, PLATFORM_DCACHE_ALIGN, + is_shared); if (buffer) { buffer->id = desc->comp.id; buffer->pipeline_id = desc->comp.pipeline_id; @@ -79,7 +80,7 @@ int32_t ipc_comp_pipe_id(const struct ipc_comp_dev *icd) */ static void comp_update_params(uint32_t flag, struct sof_ipc_stream_params *params, - struct comp_buffer __sparse_cache *buffer) + struct comp_buffer *buffer) { if (flag & BUFF_PARAMS_FRAME_FMT) params->frame_fmt = audio_stream_get_frm_fmt(&buffer->stream); @@ -103,7 +104,6 @@ int comp_verify_params(struct comp_dev *dev, uint32_t flag, struct list_item *clist; struct comp_buffer *sinkb; struct comp_buffer *buf; - struct comp_buffer __sparse_cache *buf_c; int dir = dev->direction; if (!params) { @@ -127,22 +127,18 @@ int comp_verify_params(struct comp_dev *dev, uint32_t flag, struct comp_buffer, source_list); - buf_c = buffer_acquire(buf); - /* update specific pcm parameter with buffer parameter if * specific flag is set. */ - comp_update_params(flag, params, buf_c); + comp_update_params(flag, params, buf); /* overwrite buffer parameters with modified pcm * parameters */ - buffer_set_params(buf_c, params, BUFFER_UPDATE_FORCE); + buffer_set_params(buf, params, BUFFER_UPDATE_FORCE); /* set component period frames */ - component_set_nearest_period_frames(dev, audio_stream_get_rate(&buf_c->stream)); - - buffer_release(buf_c); + component_set_nearest_period_frames(dev, audio_stream_get_rate(&buf->stream)); } else { /* for other components we iterate over all downstream buffers * (for playback) or upstream buffers (for capture). @@ -151,19 +147,15 @@ int comp_verify_params(struct comp_dev *dev, uint32_t flag, list_for_item(clist, buffer_list) { buf = buffer_from_list(clist, dir); - buf_c = buffer_acquire(buf); - comp_update_params(flag, params, buf_c); - buffer_set_params(buf_c, params, BUFFER_UPDATE_FORCE); - buffer_release(buf_c); + comp_update_params(flag, params, buf); + buffer_set_params(buf, params, BUFFER_UPDATE_FORCE); } /* fetch sink buffer in order to calculate period frames */ sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - buf_c = buffer_acquire(sinkb); - component_set_nearest_period_frames(dev, audio_stream_get_rate(&buf_c->stream)); - buffer_release(buf_c); + component_set_nearest_period_frames(dev, audio_stream_get_rate(&sinkb->stream)); } return 0; @@ -174,8 +166,8 @@ int comp_buffer_connect(struct comp_dev *comp, uint32_t comp_core, { /* check if it's a connection between cores */ if (buffer->core != comp_core) { - /* set the buffer as a coherent object */ - coherent_shared_thread(buffer, c); + /* buffer must be shared */ + assert(buffer->is_shared); if (!comp->is_shared) comp_make_shared(comp); @@ -290,10 +282,8 @@ int ipc_comp_free(struct ipc *ipc, uint32_t comp_id) irq_local_disable(flags); list_for_item_safe(clist, tmp, &icd->cd->bsource_list) { struct comp_buffer *buffer = container_of(clist, struct comp_buffer, sink_list); - struct comp_buffer __sparse_cache *buffer_c = buffer_acquire(buffer); - buffer_c->sink = NULL; - buffer_release(buffer_c); + buffer->sink = NULL; /* Also if it isn't shared - we are about to modify uncached data */ dcache_writeback_invalidate_region(uncache_to_cache(buffer), sizeof(*buffer)); @@ -303,10 +293,8 @@ int ipc_comp_free(struct ipc *ipc, uint32_t comp_id) list_for_item_safe(clist, tmp, &icd->cd->bsink_list) { struct comp_buffer *buffer = container_of(clist, struct comp_buffer, source_list); - struct comp_buffer __sparse_cache *buffer_c = buffer_acquire(buffer); - buffer_c->source = NULL; - buffer_release(buffer_c); + buffer->source = NULL; /* Also if it isn't shared - we are about to modify uncached data */ dcache_writeback_invalidate_region(uncache_to_cache(buffer), sizeof(*buffer)); diff --git a/src/ipc/ipc3/dai.c b/src/ipc/ipc3/dai.c index decee57299b9..ab5143f64d13 100644 --- a/src/ipc/ipc3/dai.c +++ b/src/ipc/ipc3/dai.c @@ -65,6 +65,10 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void dd->stream_id); channel = EDMA_HS_GET_CHAN(handshake); break; + case SOF_DAI_IMX_MICFIL: + channel = dai_get_handshake(dd->dai, dai->direction, + dd->stream_id); + break; case SOF_DAI_AMD_BT: channel = dai_get_handshake(dd->dai, dai->direction, dd->stream_id); @@ -103,7 +107,6 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) { struct ipc_config_dai *dai = &dd->ipc_config; struct sof_ipc_dai_config *config = ipc_from_dai_config(dd->dai_spec_config); - struct comp_buffer __sparse_cache *buffer_c; if (!config) { comp_err(dev, "dai_data_config(): no config set for dai %d type %d", @@ -145,19 +148,18 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) * all formats, such as 8/16/24/32 bits. */ dev->ipc_config.frame_fmt = SOF_IPC_FRAME_S32_LE; - if (dd->dma_buffer) { - buffer_c = buffer_acquire(dd->dma_buffer); - audio_stream_set_frm_fmt(&buffer_c->stream, dev->ipc_config.frame_fmt); - buffer_release(buffer_c); - } + if (dd->dma_buffer) + audio_stream_set_frm_fmt(&dd->dma_buffer->stream, + dev->ipc_config.frame_fmt); + dd->config.burst_elems = dai_get_fifo_depth(dd->dai, dai->direction); /* As with HDA, the DMA channel is assigned in runtime, * not during topology parsing. */ dd->stream_id = config->alh.stream_id; break; + case SOF_DAI_IMX_MICFIL: case SOF_DAI_IMX_SAI: - COMPILER_FALLTHROUGH; case SOF_DAI_IMX_ESAI: dd->config.burst_elems = dai_get_fifo_depth(dd->dai, dai->direction); break; @@ -170,11 +172,9 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev) break; case SOF_DAI_AMD_DMIC: dev->ipc_config.frame_fmt = SOF_IPC_FRAME_S32_LE; - if (dd->dma_buffer) { - buffer_c = buffer_acquire(dd->dma_buffer); - audio_stream_set_frm_fmt(&buffer_c->stream, dev->ipc_config.frame_fmt); - buffer_release(buffer_c); - } + if (dd->dma_buffer) + audio_stream_set_frm_fmt(&dd->dma_buffer->stream, + dev->ipc_config.frame_fmt); break; case SOF_DAI_AMD_HS: case SOF_DAI_AMD_HS_VIRTUAL: diff --git a/src/ipc/ipc3/helper.c b/src/ipc/ipc3/helper.c index 4a723b9539a7..f7b731ffde90 100644 --- a/src/ipc/ipc3/helper.c +++ b/src/ipc/ipc3/helper.c @@ -454,7 +454,7 @@ int ipc_buffer_new(struct ipc *ipc, const struct sof_ipc_buffer *desc) } /* register buffer with pipeline */ - buffer = buffer_new(desc); + buffer = buffer_new(desc, false); if (!buffer) { tr_err(&ipc_tr, "ipc_buffer_new(): buffer_new() failed"); return -ENOMEM; @@ -487,7 +487,6 @@ int ipc_buffer_free(struct ipc *ipc, uint32_t buffer_id) unsigned int core; bool sink_active = false; bool source_active = false; - struct comp_buffer __sparse_cache *buffer_c; /* check whether buffer exists */ ibd = ipc_get_buffer_by_id(ipc, buffer_id); @@ -498,8 +497,6 @@ int ipc_buffer_free(struct ipc *ipc, uint32_t buffer_id) if (!cpu_is_me(ibd->core)) return ipc_process_on_core(ibd->core, false); - buffer_c = buffer_acquire(ibd->cb); - /* try to find sink/source components to check if they still exists */ list_for_item(clist, &ipc->comp_list) { icd = container_of(clist, struct ipc_comp_dev, list); @@ -507,21 +504,19 @@ int ipc_buffer_free(struct ipc *ipc, uint32_t buffer_id) continue; /* check comp state if sink and source are valid */ - if (buffer_c->sink == icd->cd) { - sink = buffer_c->sink; - if (buffer_c->sink->state != COMP_STATE_READY) + if (ibd->cb->sink == icd->cd) { + sink = ibd->cb->sink; + if (ibd->cb->sink->state != COMP_STATE_READY) sink_active = true; } - if (buffer_c->source == icd->cd) { - source = buffer_c->source; - if (buffer_c->source->state != COMP_STATE_READY) + if (ibd->cb->source == icd->cd) { + source = ibd->cb->source; + if (ibd->cb->source->state != COMP_STATE_READY) source_active = true; } } - buffer_release(buffer_c); - /* * A buffer could be connected to 2 different pipelines. When one pipeline is freed, the * buffer comp that belongs in this pipeline will need to be freed even when the other @@ -572,6 +567,12 @@ static int ipc_comp_to_buffer_connect(struct ipc_comp_dev *comp, tr_dbg(&ipc_tr, "ipc: comp sink %d, source %d -> connect", buffer->id, comp->id); +#if CONFIG_INCOHERENT + if (comp->core != buffer->cb->core) { + tr_err(&ipc_tr, "ipc: shared buffers are not supported for IPC3 incoherent architectures"); + return -ENOTSUP; + } +#endif return comp_buffer_connect(comp->cd, comp->core, buffer->cb, PPL_CONN_DIR_COMP_TO_BUFFER); } @@ -582,6 +583,12 @@ static int ipc_buffer_to_comp_connect(struct ipc_comp_dev *buffer, tr_dbg(&ipc_tr, "ipc: comp sink %d, source %d -> connect", comp->id, buffer->id); +#if CONFIG_INCOHERENT + if (comp->core != buffer->cb->core) { + tr_err(&ipc_tr, "ipc: shared buffers are not supported for IPC3 incoherent architectures"); + return -ENOTSUP; + } +#endif return comp_buffer_connect(comp->cd, comp->core, buffer->cb, PPL_CONN_DIR_BUFFER_TO_COMP); } diff --git a/src/ipc/ipc4/CMakeLists.txt b/src/ipc/ipc4/CMakeLists.txt index 7f9d75f654be..2e162e702672 100644 --- a/src/ipc/ipc4/CMakeLists.txt +++ b/src/ipc/ipc4/CMakeLists.txt @@ -9,4 +9,4 @@ add_local_sources(sof ams_helpers.c ) -target_include_directories(sof_options INTERFACE ${PROJECT_SOURCE_DIR}/rimage/src/include) +target_include_directories(sof_options INTERFACE ${RIMAGE_TOP}/src/include) diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index 0ab182e84d04..209bddf65097 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,56 @@ static struct ipc_msg msg_reply = {0, 0, 0, 0, LIST_INIT(msg_reply.list)}; static struct ipc_msg msg_notify = {0, 0, 0, 0, LIST_INIT(msg_notify.list)}; +#if CONFIG_LIBRARY +static inline struct ipc4_message_request *ipc4_get_message_request(void) +{ + struct ipc *ipc = ipc_get(); + + return (struct ipc4_message_request *)ipc->comp_data; +} + +static inline void ipc4_send_reply(struct ipc4_message_reply *reply) +{ + struct ipc *ipc = ipc_get(); + + memcpy((char *)ipc->comp_data, reply, sizeof(*reply)); +} + +static inline const struct ipc4_pipeline_set_state_data *ipc4_get_pipeline_data(void) +{ + const struct ipc4_pipeline_set_state_data *ppl_data; + struct ipc *ipc = ipc_get(); + + ppl_data = (const struct ipc4_pipeline_set_state_data *)ipc->comp_data; + + return ppl_data; +} +#else +static inline struct ipc4_message_request *ipc4_get_message_request(void) +{ + /* ignoring _hdr as it does not contain valid data in IPC4/IDC case */ + return ipc_from_hdr(&msg_data.msg_in); +} + +static inline void ipc4_send_reply(struct ipc4_message_reply *reply) +{ + struct ipc *ipc = ipc_get(); + char *data = ipc->comp_data; + + ipc_msg_send(&msg_reply, data, true); +} + +static inline const struct ipc4_pipeline_set_state_data *ipc4_get_pipeline_data(void) +{ + const struct ipc4_pipeline_set_state_data *ppl_data; + + ppl_data = (const struct ipc4_pipeline_set_state_data *)MAILBOX_HOSTBOX_BASE; + dcache_invalidate_region((__sparse_force void __sparse_cache *)ppl_data, + sizeof(*ppl_data)); + + return ppl_data; +} +#endif /* * Global IPC Operations. */ @@ -274,7 +325,7 @@ int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd) switch (status) { case COMP_STATE_INIT: tr_dbg(&ipc_tr, "pipeline %d: reset from init", ppl_icd->id); - ret = ipc4_pipeline_complete(ipc, ppl_icd->id); + ret = ipc4_pipeline_complete(ipc, ppl_icd->id, cmd); if (ret < 0) ret = IPC4_INVALID_REQUEST; @@ -296,7 +347,7 @@ int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd) switch (status) { case COMP_STATE_INIT: tr_dbg(&ipc_tr, "pipeline %d: pause from init", ppl_icd->id); - ret = ipc4_pipeline_complete(ipc, ppl_icd->id); + ret = ipc4_pipeline_complete(ipc, ppl_icd->id, cmd); if (ret < 0) ret = IPC4_INVALID_REQUEST; @@ -311,6 +362,7 @@ int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd) case SOF_IPC4_PIPELINE_STATE_EOS: if (status != COMP_STATE_ACTIVE) return IPC4_INVALID_REQUEST; + COMPILER_FALLTHROUGH; case SOF_IPC4_PIPELINE_STATE_SAVED: case SOF_IPC4_PIPELINE_STATE_ERROR_STOP: default: @@ -475,7 +527,8 @@ static int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) struct ipc4_pipeline_set_state state; struct ipc_comp_dev *ppl_icd; struct ipc *ipc = ipc_get(); - uint32_t cmd, ppl_count, id; + uint32_t cmd, ppl_count; + uint32_t id = 0; const uint32_t *ppl_id; bool use_idc = false; uint32_t idx; @@ -485,10 +538,8 @@ static int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) state.primary.dat = ipc4->primary.dat; state.extension.dat = ipc4->extension.dat; cmd = state.primary.r.ppl_state; + ppl_data = ipc4_get_pipeline_data(); - ppl_data = (const struct ipc4_pipeline_set_state_data *)MAILBOX_HOSTBOX_BASE; - dcache_invalidate_region((__sparse_force void __sparse_cache *)ppl_data, - sizeof(*ppl_data)); if (state.extension.r.multi_ppl) { ppl_count = ppl_data->pipelines_count; ppl_id = ppl_data->ppl_id; @@ -782,7 +833,7 @@ static int ipc4_process_glb_message(struct ipc4_message_request *ipc4) static int ipc4_init_module_instance(struct ipc4_message_request *ipc4) { - struct ipc4_module_init_instance module_init = {}; + struct ipc4_module_init_instance module_init; struct comp_dev *dev; /* we only need the common header here, all we have from the IPC */ int ret = memcpy_s(&module_init, sizeof(module_init), ipc4, sizeof(*ipc4)); @@ -872,7 +923,8 @@ static int ipc4_get_large_config_module_instance(struct ipc4_message_request *ip if (config.primary.r.module_id) { uint32_t comp_id; - comp_id = IPC4_COMP_ID(config.primary.r.module_id, config.primary.r.instance_id); + comp_id = IPC4_COMP_ID(config.primary.r.module_id, + config.primary.r.instance_id); dev = ipc4_get_comp_dev(comp_id); if (!dev) return IPC4_MOD_INVALID_ID; @@ -921,6 +973,69 @@ static int ipc4_get_large_config_module_instance(struct ipc4_message_request *ip return ret; } +static int ipc4_set_vendor_config_module_instance(struct comp_dev *dev, + const struct comp_driver *drv, + uint32_t module_id, + uint32_t instance_id, + bool init_block, + bool final_block, + uint32_t data_off_size, + const char *data) +{ + int ret; + + /* Old FW comment: bursted configs */ + if (init_block && final_block) { + const struct sof_tlv *tlv = (struct sof_tlv *)data; + /* if there is no payload in this large config set + * (4 bytes type | 4 bytes length=0 | no value) + * we do not handle such case + */ + if (data_off_size < sizeof(struct sof_tlv)) + return IPC4_INVALID_CONFIG_DATA_STRUCT; + + /* ===Iterate over payload=== + * Payload can have multiple sof_tlv structures inside, + * You can find how many by checking payload size (data_off_size) + * Here we just set pointer end_offset to the end of data + * and iterate until we reach that + */ + const uint8_t *end_offset = data + data_off_size; + + while ((const uint8_t *)tlv < end_offset) { + /* check for invalid length */ + if (!tlv->length) + return IPC4_INVALID_CONFIG_DATA_LEN; + + ret = drv->ops.set_large_config(dev, tlv->type, init_block, + final_block, tlv->length, tlv->value); + if (ret < 0) { + ipc_cmd_err(&ipc_tr, "failed to set large_config_module_instance %x : %x", + (uint32_t)module_id, (uint32_t)instance_id); + return IPC4_INVALID_RESOURCE_ID; + } + /* Move pointer to the end of this tlv */ + tlv = (struct sof_tlv *)((const uint8_t *)tlv + + sizeof(struct sof_tlv) + ALIGN_UP(tlv->length, 4)); + } + return IPC4_SUCCESS; + } + /* else, !(init_block && final_block) */ + const struct sof_tlv *tlv = (struct sof_tlv *)data; + uint32_t param_id = 0; + + if (init_block) { + /* for initial block use param_id from tlv + * move pointer and size to end of the tlv + */ + param_id = tlv->type; + data += sizeof(struct sof_tlv); + data_off_size -= sizeof(struct sof_tlv); + } + return drv->ops.set_large_config(dev, param_id, init_block, final_block, + data_off_size, (uint8_t *)data); +} + static int ipc4_set_large_config_module_instance(struct ipc4_message_request *ipc4) { struct ipc4_module_large_config config; @@ -956,16 +1071,25 @@ static int ipc4_set_large_config_module_instance(struct ipc4_message_request *ip return ipc4_process_on_core(dev->ipc_config.core, false); } - ret = drv->ops.set_large_config(dev, config.extension.r.large_param_id, - config.extension.r.init_block, - config.extension.r.final_block, - config.extension.r.data_off_size, - (const char *)MAILBOX_HOSTBOX_BASE); - if (ret < 0) { - ipc_cmd_err(&ipc_tr, "failed to set large_config_module_instance %x : %x", - (uint32_t)config.primary.r.module_id, - (uint32_t)config.primary.r.instance_id); - ret = IPC4_INVALID_RESOURCE_ID; + /* check for vendor param first */ + if (config.extension.r.large_param_id == VENDOR_CONFIG_PARAM) { + ret = ipc4_set_vendor_config_module_instance(dev, drv, + (uint32_t)config.primary.r.module_id, + (uint32_t)config.primary.r.instance_id, + config.extension.r.init_block, + config.extension.r.final_block, + config.extension.r.data_off_size, + (const char *)MAILBOX_HOSTBOX_BASE); + } else { + ret = drv->ops.set_large_config(dev, config.extension.r.large_param_id, + config.extension.r.init_block, config.extension.r.final_block, + config.extension.r.data_off_size, (const char *)MAILBOX_HOSTBOX_BASE); + if (ret < 0) { + ipc_cmd_err(&ipc_tr, "failed to set large_config_module_instance %x : %x", + (uint32_t)config.primary.r.module_id, + (uint32_t)config.primary.r.instance_id); + ret = IPC4_INVALID_RESOURCE_ID; + } } return ret; @@ -1275,8 +1399,7 @@ void ipc_msg_reply(struct sof_ipc_reply *reply) void ipc_cmd(struct ipc_cmd_hdr *_hdr) { - /* ignoring _hdr as it does not contain valid data in IPC4/IDC case */ - struct ipc4_message_request *in = ipc_from_hdr(&msg_data.msg_in); + struct ipc4_message_request *in = ipc4_get_message_request(); enum ipc4_message_target target; int err; @@ -1312,7 +1435,6 @@ void ipc_cmd(struct ipc_cmd_hdr *_hdr) /* FW sends an ipc message to host if request bit is clear */ if (in->primary.r.rsp == SOF_IPC4_MESSAGE_DIR_MSG_REQUEST) { struct ipc *ipc = ipc_get(); - char *data = ipc->comp_data; struct ipc4_message_reply reply; /* Process flow and time stamp for IPC4 msg processed on secondary core : @@ -1399,6 +1521,6 @@ void ipc_cmd(struct ipc_cmd_hdr *_hdr) tr_dbg(&ipc_tr, "tx-reply\t: %#x|%#x", msg_reply.header, msg_reply.extension); - ipc_msg_send(&msg_reply, data, true); + ipc4_send_reply(&reply); } } diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 46a4ff1e3f1b..91babe75b97d 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -74,12 +74,28 @@ void ipc_build_trace_posn(struct sof_ipc_dma_trace_posn *posn) posn->rhdr.hdr.size = 0; } +#if CONFIG_LIBRARY +static inline char *ipc4_get_comp_new_data(void) +{ + struct ipc *ipc = ipc_get(); + char *data = (char *)ipc->comp_data + sizeof(struct ipc4_module_init_instance); + + return data; +} +#else +static inline char *ipc4_get_comp_new_data(void) +{ + return (char *)MAILBOX_HOSTBOX_BASE; +} +#endif + struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init) { struct comp_ipc_config ipc_config; const struct comp_driver *drv; struct comp_dev *dev; uint32_t comp_id; + char *data; comp_id = IPC4_COMP_ID(module_init->primary.r.module_id, module_init->primary.r.instance_id); @@ -119,15 +135,17 @@ struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init) dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, MAILBOX_HOSTBOX_SIZE); + data = ipc4_get_comp_new_data(); if (drv->type == SOF_COMP_MODULE_ADAPTER) { const struct ipc_config_process spec = { - .data = (const unsigned char *)MAILBOX_HOSTBOX_BASE, + .data = (const unsigned char *)data, /* spec_size in IPC4 is in DW. Convert to bytes. */ .size = module_init->extension.r.param_block_size * sizeof(uint32_t), }; + dev = drv->ops.create(drv, &ipc_config, (const void *)&spec); } else { - dev = drv->ops.create(drv, &ipc_config, (const void *)MAILBOX_HOSTBOX_BASE); + dev = drv->ops.create(drv, &ipc_config, (const void *)data); } if (!dev) return NULL; @@ -241,14 +259,11 @@ static int ipc_pipeline_module_free(uint32_t pipeline_id) /* free sink buffer allocated by current component in bind function */ list_for_item_safe(list, _list, &icd->cd->bsink_list) { - struct comp_buffer __sparse_cache *buffer_c; struct comp_dev *sink; buffer = container_of(list, struct comp_buffer, source_list); pipeline_disconnect(icd->cd, buffer, PPL_CONN_DIR_COMP_TO_BUFFER); - buffer_c = buffer_acquire(buffer); - sink = buffer_c->sink; - buffer_release(buffer_c); + sink = buffer->sink; /* free the buffer only when the sink module has also been disconnected */ if (!sink) @@ -257,14 +272,11 @@ static int ipc_pipeline_module_free(uint32_t pipeline_id) /* free source buffer allocated by current component in bind function */ list_for_item_safe(list, _list, &icd->cd->bsource_list) { - struct comp_buffer __sparse_cache *buffer_c; struct comp_dev *source; buffer = container_of(list, struct comp_buffer, sink_list); pipeline_disconnect(icd->cd, buffer, PPL_CONN_DIR_BUFFER_TO_COMP); - buffer_c = buffer_acquire(buffer); - source = buffer_c->source; - buffer_release(buffer_c); + source = buffer->source; /* free the buffer only when the source module has also been disconnected */ if (!source) @@ -315,29 +327,24 @@ int ipc_pipeline_free(struct ipc *ipc, uint32_t comp_id) return IPC4_SUCCESS; } -static struct comp_buffer *ipc4_create_buffer(struct comp_dev *src, struct comp_dev *sink, - uint32_t src_obs, uint32_t src_queue, +static struct comp_buffer *ipc4_create_buffer(struct comp_dev *src, bool is_shared, + uint32_t buf_size, uint32_t src_queue, uint32_t dst_queue) { struct sof_ipc_buffer ipc_buf; - int buf_size; - - /* double it since obs is single buffer size */ - buf_size = src_obs * 2; memset(&ipc_buf, 0, sizeof(ipc_buf)); ipc_buf.size = buf_size; ipc_buf.comp.id = IPC4_COMP_ID(src_queue, dst_queue); ipc_buf.comp.pipeline_id = src->ipc_config.pipeline_id; ipc_buf.comp.core = src->ipc_config.core; - return buffer_new(&ipc_buf); + return buffer_new(&ipc_buf, is_shared); } int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) { struct ipc4_module_bind_unbind *bu; struct comp_buffer *buffer; - struct comp_buffer __sparse_cache *buffer_c; struct comp_dev *source; struct comp_dev *sink; struct ipc4_base_module_cfg source_src_cfg; @@ -357,8 +364,12 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) return IPC4_INVALID_RESOURCE_ID; } - /* Pass IPC to target core if both modules has the same target core */ - if (!cpu_is_me(source->ipc_config.core) && source->ipc_config.core == sink->ipc_config.core) + bool is_shared = source->ipc_config.core != sink->ipc_config.core; + + /* Pass IPC to target core if the buffer won't be shared and will be used + * on different core + */ + if (!cpu_is_me(source->ipc_config.core) && !is_shared) return ipc4_process_on_core(source->ipc_config.core, false); ret = comp_get_attribute(source, COMP_ATTR_BASE_CONFIG, &source_src_cfg); @@ -373,7 +384,20 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) return IPC4_FAILURE; } - buffer = ipc4_create_buffer(source, sink, source_src_cfg.obs, bu->extension.r.src_queue, + /* create a buffer + * in case of LL -> LL or LL->DP + * size = 2*obs of source module (obs is single buffer size) + * in case of DP -> LL + * size = 2*ibs of destination (LL) module. DP queue will handle obs of DP module + */ + uint32_t buf_size; + + if (source->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) + buf_size = source_src_cfg.obs * 2; + else + buf_size = sink_src_cfg.ibs * 2; + + buffer = ipc4_create_buffer(source, is_shared, buf_size, bu->extension.r.src_queue, bu->extension.r.dst_queue); if (!buffer) { tr_err(&ipc_tr, "failed to allocate buffer to bind %d to %d", src_id, sink_id); @@ -381,15 +405,17 @@ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) } /* - * set ibs and obs in sink/src api of created buffer - * IBS of a buffer is OBS of source component - * OBS of a buffer is IBS of destination component + * set min_free_space and min_available in sink/src api of created buffer. + * buffer is connected like: + * source_module -> (sink_ifc) BUFFER (source_ifc) -> sink_module + * + * source_module needs to set its OBS (out buffer size) + * as min_free_space in buffer's sink ifc + * sink_module needs to set its IBS (input buffer size) + * as min_available in buffer's source ifc */ - - buffer_c = buffer_acquire(buffer); - source_set_ibs(audio_stream_get_source(&buffer_c->stream), source_src_cfg.obs); - sink_set_obs(audio_stream_get_sink(&buffer_c->stream), sink_src_cfg.ibs); - buffer_release(buffer_c); + sink_set_min_free_space(audio_stream_get_sink(&buffer->stream), source_src_cfg.obs); + source_set_min_available(audio_stream_get_source(&buffer->stream), sink_src_cfg.ibs); /* * Connect and bind the buffer to both source and sink components with the interrupts @@ -488,10 +514,7 @@ int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) buffer_id = IPC4_COMP_ID(bu->extension.r.src_queue, bu->extension.r.dst_queue); list_for_item(sink_list, &src->bsink_list) { struct comp_buffer *buf = container_of(sink_list, struct comp_buffer, source_list); - struct comp_buffer __sparse_cache *buf_c = buffer_acquire(buf); - bool found = buf_c->id == buffer_id; - - buffer_release(buf_c); + bool found = buf->id == buffer_id; if (found) { buffer = buf; @@ -628,7 +651,7 @@ static int ipc4_update_comps_direction(struct ipc *ipc, uint32_t ppl_id) return 0; } -int ipc4_pipeline_complete(struct ipc *ipc, uint32_t comp_id) +int ipc4_pipeline_complete(struct ipc *ipc, uint32_t comp_id, uint32_t cmd) { struct ipc_comp_dev *ipc_pipe; int ret; @@ -647,9 +670,11 @@ int ipc4_pipeline_complete(struct ipc *ipc, uint32_t comp_id) * pipeline w/o connection to gateway, so direction is not configured in binding phase. * Need to update direction for such modules when pipeline is completed. */ - ret = ipc4_update_comps_direction(ipc, comp_id); - if (ret < 0) - return ret; + if (cmd != SOF_IPC4_PIPELINE_STATE_RESET) { + ret = ipc4_update_comps_direction(ipc, comp_id); + if (ret < 0) + return ret; + } return ipc_pipeline_complete(ipc, comp_id); } @@ -710,6 +735,47 @@ const struct comp_driver *ipc4_get_drv(uint8_t *uuid) return drv; } +#if CONFIG_LIBRARY +struct ipc4_module_uuid { + int module_id; + struct sof_uuid uuid; +}; + +/* Hardcoded table mapping UUIDs with module ID's. TODO: replace this with a scalable solution */ +static const struct ipc4_module_uuid uuid_map[] = { + {0x6, {.a = 0x61bca9a8, .b = 0x18d0, .c = 0x4a18, + .d = { 0x8e, 0x7b, 0x26, 0x39, 0x21, 0x98, 0x04, 0xb7 }}}, /* gain */ + {0x2, {.a = 0x39656eb2, .b = 0x3b71, .c = 0x4049, + .d = { 0x8d, 0x3f, 0xf9, 0x2c, 0xd5, 0xc4, 0x3c, 0x09 }}}, /* mixin */ + {0x3, {.a = 0x3c56505a, .b = 0x24d7, .c = 0x418f, + .d = { 0xbd, 0xdc, 0xc1, 0xf5, 0xa3, 0xac, 0x2a, 0xe0 }}}, /* mixout */ + {0x96, {.a = 0xe2b6031c, .b = 0x47e8, .c = 0x11ed, + .d = { 0x07, 0xa9, 0x7f, 0x80, 0x1b, 0x6e, 0xfa, 0x6c }}}, /* host SHM write */ + {0x98, {.a = 0xdabe8814, .b = 0x47e8, .c = 0x11ed, + .d = { 0xa5, 0x8b, 0xb3, 0x09, 0x97, 0x4f, 0xec, 0xce }}}, /* host SHM read */ + {0x97, {.a = 0x72cee996, .b = 0x39f2, .c = 0x11ed, + .d = { 0xa0, 0x8f, 0x97, 0xfc, 0xc4, 0x2e, 0xaa, 0xeb }}}, /* ALSA aplay */ + {0x99, {.a = 0x66def9f0, .b = 0x39f2, .c = 0x11ed, + .d = { 0xf7, 0x89, 0xaf, 0x98, 0xa6, 0x44, 0x0c, 0xc4 }}}, /* ALSA arecord */ +}; + +static const struct comp_driver *ipc4_library_get_drv(int module_id) +{ + const struct ipc4_module_uuid *mod_uuid; + int i; + + for (i = 0; i < ARRAY_SIZE(uuid_map); i++) { + mod_uuid = &uuid_map[i]; + + if (mod_uuid->module_id == module_id) + return ipc4_get_drv((uint8_t *)&mod_uuid->uuid); + } + + tr_err(&comp_tr, "ipc4_library_get_drv(): Unsupported module ID %#x\n", module_id); + return NULL; +} +#endif + const struct comp_driver *ipc4_get_comp_drv(int module_id) { struct sof_man_fw_desc *desc = NULL; @@ -717,6 +783,10 @@ const struct comp_driver *ipc4_get_comp_drv(int module_id) struct sof_man_module *mod; int entry_index; +#if CONFIG_LIBRARY + return ipc4_library_get_drv(module_id); +#endif + #ifdef RIMAGE_MANIFEST desc = (struct sof_man_fw_desc *)IMR_BOOT_LDR_MANIFEST_BASE; #else @@ -839,7 +909,7 @@ void ipc4_base_module_cfg_to_stream_params(const struct ipc4_base_module_cfg *ba params->chmap[i] = (base_cfg->audio_fmt.ch_map >> i * 4) & 0xf; } -void ipc4_update_buffer_format(struct comp_buffer __sparse_cache *buf_c, +void ipc4_update_buffer_format(struct comp_buffer *buf_c, const struct ipc4_audio_format *fmt) { enum sof_ipc_frame valid_fmt, frame_fmt; diff --git a/src/ipc/ipc4/logging.c b/src/ipc/ipc4/logging.c index 08cbfa870727..15ee85560f4b 100644 --- a/src/ipc/ipc4/logging.c +++ b/src/ipc/ipc4/logging.c @@ -4,18 +4,27 @@ // // Author: Kai Vehmanen +#if CONFIG_LOG_BACKEND_SOF_PROBE && CONFIG_LOG_BACKEND_ADSP_MTRACE +#error Cannot have both backends enabled +#endif + #include #include #include #include #include #include +#if !CONFIG_LIBRARY +#include +#include +#endif +#if CONFIG_LOG_BACKEND_SOF_PROBE +#include +#endif #ifdef CONFIG_LOG_BACKEND_ADSP_MTRACE -#include #include -#include #include #include @@ -150,16 +159,45 @@ int ipc4_logging_enable_logs(bool first_block, return 0; } -int ipc4_logging_shutdown(void) +#elif CONFIG_LOG_BACKEND_SOF_PROBE + +int ipc4_logging_enable_logs(bool first_block, + bool last_block, + uint32_t data_offset_or_size, + const char *data) { - struct ipc4_log_state_info log_state = { 0 }; + const struct log_backend *log_backend = log_backend_probe_get(); + const struct ipc4_log_state_info *log_state; - /* log_state.enable set to 0 above */ + if (!(first_block && last_block)) + return -EINVAL; - return ipc4_logging_enable_logs(true, true, sizeof(log_state), (char *)&log_state); + if (data_offset_or_size < sizeof(struct ipc4_log_state_info)) + return -EINVAL; + + /* Make sure we work on correct ipc data by invalidating cache + * data may be taken from different core to the one we are working + * on right now. + */ + dcache_invalidate_region((__sparse_force void __sparse_cache *)data, data_offset_or_size); + + log_state = (const struct ipc4_log_state_info *)data; + + if (log_state->enable) { + if (!probe_is_backend_configured()) + return -EINVAL; + + log_backend_activate(log_backend, probe_logging_hook); + + } else { + log_backend_deactivate(log_backend); + } + + return 0; } -#else +#else /* unsupported logging method */ + int ipc4_logging_enable_logs(bool first_block, bool last_block, uint32_t data_offset_or_size, @@ -168,9 +206,13 @@ int ipc4_logging_enable_logs(bool first_block, return IPC4_UNKNOWN_MESSAGE_TYPE; } +#endif + int ipc4_logging_shutdown(void) { - return 0; -} + struct ipc4_log_state_info log_state = { 0 }; -#endif + /* log_state.enable set to 0 above */ + + return ipc4_logging_enable_logs(true, true, sizeof(log_state), (char *)&log_state); +} diff --git a/src/lib/dma.c b/src/lib/dma.c index 6115cfba1e85..f124a040c4c3 100644 --- a/src/lib/dma.c +++ b/src/lib/dma.c @@ -321,11 +321,11 @@ void dma_sg_free(struct dma_sg_elem_array *elem_array) dma_sg_init(elem_array); } -int dma_buffer_copy_from(struct comp_buffer __sparse_cache *source, - struct comp_buffer __sparse_cache *sink, +int dma_buffer_copy_from(struct comp_buffer *source, + struct comp_buffer *sink, dma_process_func process, uint32_t source_bytes) { - struct audio_stream __sparse_cache *istream = &source->stream; + struct audio_stream *istream = &source->stream; uint32_t samples = source_bytes / audio_stream_sample_bytes(istream); uint32_t sink_bytes = audio_stream_sample_bytes(&sink->stream) * @@ -350,11 +350,11 @@ int dma_buffer_copy_from(struct comp_buffer __sparse_cache *source, return ret; } -int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, - struct comp_buffer __sparse_cache *sink, +int dma_buffer_copy_to(struct comp_buffer *source, + struct comp_buffer *sink, dma_process_func process, uint32_t sink_bytes) { - struct audio_stream __sparse_cache *ostream = &sink->stream; + struct audio_stream *ostream = &sink->stream; uint32_t samples = sink_bytes / audio_stream_sample_bytes(ostream); uint32_t source_bytes = audio_stream_sample_bytes(&source->stream) * @@ -379,11 +379,11 @@ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, return ret; } -int dma_buffer_copy_from_no_consume(struct comp_buffer __sparse_cache *source, - struct comp_buffer __sparse_cache *sink, +int dma_buffer_copy_from_no_consume(struct comp_buffer *source, + struct comp_buffer *sink, dma_process_func process, uint32_t source_bytes) { - struct audio_stream __sparse_cache *istream = &source->stream; + struct audio_stream *istream = &source->stream; uint32_t samples = source_bytes / audio_stream_sample_bytes(istream); uint32_t sink_bytes = audio_stream_sample_bytes(&sink->stream) * diff --git a/src/logging/log_backend_probe.c b/src/logging/log_backend_probe.c index b99da2e0a795..6baf22df2e14 100644 --- a/src/logging/log_backend_probe.c +++ b/src/logging/log_backend_probe.c @@ -109,3 +109,13 @@ void probe_logging_init(probe_logging_hook_t fn) { probe_hook = fn; } + +const struct log_backend *log_backend_probe_get(void) +{ + return &log_backend_adsp_probe; +} + +bool probe_is_backend_configured(void) +{ + return probe_hook != NULL; +} diff --git a/src/math/CMakeLists.txt b/src/math/CMakeLists.txt index d27063c80b0d..899810544864 100644 --- a/src/math/CMakeLists.txt +++ b/src/math/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause if(BUILD_LIBRARY) + add_local_sources(sof numbers.c) return() endif() diff --git a/src/platform/Kconfig b/src/platform/Kconfig index f36c5ac2b7e4..d4787c140293 100644 --- a/src/platform/Kconfig +++ b/src/platform/Kconfig @@ -100,6 +100,7 @@ config IMX8M select XT_WAITI_DELAY select IMX select IMX_SDMA + select IMX_MICFIL select SCHEDULE_DMA_MULTI_CHANNEL select IMX_INTERRUPT_IRQSTEER help diff --git a/src/platform/imx8m/include/platform/lib/memory.h b/src/platform/imx8m/include/platform/lib/memory.h index 7d285dbfc463..6b2c00f89bad 100644 --- a/src/platform/imx8m/include/platform/lib/memory.h +++ b/src/platform/imx8m/include/platform/lib/memory.h @@ -59,6 +59,9 @@ #define SAI_7_BASE 0x30c80000 #define SAI_7_SIZE 0x00010000 +#define MICFIL_BASE 0x30ca0000 +#define MICFIL_SIZE 0x00010000 + #define UUID_ENTRY_ELF_BASE 0x1FFFA000 #define UUID_ENTRY_ELF_SIZE 0x6000 diff --git a/src/platform/imx8m/lib/dai.c b/src/platform/imx8m/lib/dai.c index 1096740e4f58..3c684d0c2c6e 100644 --- a/src/platform/imx8m/lib/dai.c +++ b/src/platform/imx8m/lib/dai.c @@ -6,6 +6,8 @@ #include #include +#include + #include #include #include @@ -142,12 +144,37 @@ static SHARED_DATA struct dai sai[] = { }; +static SHARED_DATA struct dai micfil[] = { +{ + .index = 2, + .plat_data = { + .base = MICFIL_BASE, + .fifo[SOF_IPC_STREAM_PLAYBACK] = { + .offset = 0, /* No playback */ + .handshake = 0, + }, + .fifo[SOF_IPC_STREAM_CAPTURE] = { + .offset = MICFIL_BASE + REG_MICFIL_DATACH0, + .handshake = 24, + }, + }, + + .drv = &micfil_driver, +}, +}; + const struct dai_type_info dti[] = { { .type = SOF_DAI_IMX_SAI, .dai_array = cache_to_uncache_init((struct dai *)sai), .num_dais = ARRAY_SIZE(sai) }, + { + .type = SOF_DAI_IMX_MICFIL, + .dai_array = cache_to_uncache_init((struct dai *)micfil), + .num_dais = ARRAY_SIZE(micfil) + }, + }; const struct dai_info lib_dai = { diff --git a/src/platform/imx8m/lib/dma.c b/src/platform/imx8m/lib/dma.c index 12403f92809e..ca02d52904ad 100644 --- a/src/platform/imx8m/lib/dma.c +++ b/src/platform/imx8m/lib/dma.c @@ -31,7 +31,7 @@ static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { * enabled as it is unneeded */ .dir = DMA_DIR_MEM_TO_DEV | DMA_DIR_DEV_TO_MEM, - .devs = DMA_DEV_SAI, + .devs = DMA_DEV_SAI | DMA_DEV_MICFIL, .base = SDMA3_BASE, .channels = 32, .irq = SDMA3_IRQ, diff --git a/src/platform/library/include/platform/drivers/idc.h b/src/platform/library/include/platform/drivers/idc.h index 8738c87324dd..e538884bbb5f 100644 --- a/src/platform/library/include/platform/drivers/idc.h +++ b/src/platform/library/include/platform/drivers/idc.h @@ -5,7 +5,7 @@ * Author: Tomasz Lauda */ -#if defined(__XTOS_RTOS_IDC_H__) || defined(__ZEPHYR_RTOS_IDC_H__) +#ifdef __POSIX_RTOS_IDC_H__ #ifndef __PLATFORM_DRIVERS_IDC_H__ #define __PLATFORM_DRIVERS_IDC_H__ diff --git a/src/platform/library/include/platform/lib/clk.h b/src/platform/library/include/platform/lib/clk.h index 7c089ebac4f9..6d389a6152af 100644 --- a/src/platform/library/include/platform/lib/clk.h +++ b/src/platform/library/include/platform/lib/clk.h @@ -18,6 +18,22 @@ #define NUM_CLOCKS 2 +#define CPU_WOVCRO_FREQ_IDX 0 + +#define CPU_LPRO_FREQ_IDX 1 + +#define CPU_HPRO_FREQ_IDX 2 + +#define CPU_LOWEST_FREQ_IDX CPU_WOVCRO_FREQ_IDX + +#define CPU_DEFAULT_IDX CPU_HPRO_FREQ_IDX + +#define SSP_DEFAULT_IDX 1 + +#define NUM_CPU_FREQ 3 + +#define NUM_SSP_FREQ 3 + #endif /* __PLATFORM_LIB_CLK_H__ */ #else diff --git a/src/platform/library/include/platform/lib/dai.h b/src/platform/library/include/platform/lib/dai.h index 45065e86c3b9..5fb740e32270 100644 --- a/src/platform/library/include/platform/lib/dai.h +++ b/src/platform/library/include/platform/lib/dai.h @@ -10,6 +10,22 @@ #ifndef __PLATFORM_LIB_DAI_H__ #define __PLATFORM_LIB_DAI_H__ +#define DAI_NUM_SSP_BASE 6 + +/** \brief Number of HD/A Link Outputs */ +#define DAI_NUM_HDA_OUT 6 + +/** \brief Number of HD/A Link Inputs */ +#define DAI_NUM_HDA_IN 7 + +/* ALH */ + +/** \brief Number of ALH bi-directional links */ +#define DAI_NUM_ALH_BI_DIR_LINKS 16 + +/** \brief Number of contiguous ALH bi-dir links */ +#define DAI_NUM_ALH_BI_DIR_LINKS_GROUP 4 + #endif /* __PLATFORM_LIB_DAI_H__ */ #else diff --git a/src/platform/library/include/platform/lib/mailbox.h b/src/platform/library/include/platform/lib/mailbox.h index fbfbc3719b96..04470a43e66e 100644 --- a/src/platform/library/include/platform/lib/mailbox.h +++ b/src/platform/library/include/platform/lib/mailbox.h @@ -52,6 +52,13 @@ static inline void mailbox_sw_reg_write(size_t offset, uint32_t src) { } +static inline void mailbox_sw_regs_write(size_t offset, const void *src, size_t bytes) {} + +static inline uint32_t mailbox_sw_reg_read(size_t offset) +{ + return 0; +} + #endif /* __PLATFORM_LIB_MAILBOX_H__ */ #else diff --git a/src/platform/library/include/platform/lib/memory.h b/src/platform/library/include/platform/lib/memory.h index f57e31617da3..fafb3df303f7 100644 --- a/src/platform/library/include/platform/lib/memory.h +++ b/src/platform/library/include/platform/lib/memory.h @@ -182,6 +182,8 @@ static inline uint32_t arch_get_stack_size(void) #define host_to_local(addr) (addr) #define local_to_host(addr) (addr) +#define IMR_BOOT_LDR_MANIFEST_BASE NULL + #endif /* __PLATFORM_LIB_MEMORY_H__ */ #else diff --git a/src/platform/library/include/platform/platform.h b/src/platform/library/include/platform/platform.h index b1912049d4ec..2b1b4f31fa0c 100644 --- a/src/platform/library/include/platform/platform.h +++ b/src/platform/library/include/platform/platform.h @@ -56,6 +56,8 @@ struct timer; */ #define DMA_TRACE_RESCHEDULE_TIME 100 +#define HW_CFG_VERSION 0 + static inline void platform_panic(uint32_t p) {} /** diff --git a/src/platform/library/lib/trace.c b/src/platform/library/lib/trace.c index fdd00b7777b6..7ca847afabec 100644 --- a/src/platform/library/lib/trace.c +++ b/src/platform/library/lib/trace.c @@ -12,8 +12,7 @@ #include /* enable trace by default in testbench */ -int test_bench_trace = 1; -int debug; +int host_trace_level = LOG_LEVEL_ERROR; /* look up subsystem class name from table */ char *get_trace_class(uint32_t trace_class) diff --git a/src/platform/lunarlake/include/platform/lib/clk.h b/src/platform/lunarlake/include/platform/lib/clk.h index fe8f140ff0a6..77e72d8c6ccd 100644 --- a/src/platform/lunarlake/include/platform/lib/clk.h +++ b/src/platform/lunarlake/include/platform/lib/clk.h @@ -14,21 +14,19 @@ #include -#define CLK_MAX_CPU_HZ 400000000 +#define CLK_MAX_CPU_HZ CONFIG_XTENSA_CCOUNT_HZ #define CPU_WOVCRO_FREQ_IDX 0 -#define CPU_LPRO_FREQ_IDX 1 - -#define CPU_HPRO_FREQ_IDX 2 +#define CPU_IPLL_FREQ_IDX 1 #define CPU_LOWEST_FREQ_IDX CPU_WOVCRO_FREQ_IDX -#define CPU_DEFAULT_IDX CPU_HPRO_FREQ_IDX +#define CPU_DEFAULT_IDX CPU_IPLL_FREQ_IDX #define SSP_DEFAULT_IDX 1 -#define NUM_CPU_FREQ 3 +#define NUM_CPU_FREQ 2 #define NUM_SSP_FREQ 3 diff --git a/src/platform/lunarlake/include/platform/lib/memory.h b/src/platform/lunarlake/include/platform/lib/memory.h index 5f7ced26f922..f968da8c50f0 100644 --- a/src/platform/lunarlake/include/platform/lib/memory.h +++ b/src/platform/lunarlake/include/platform/lib/memory.h @@ -56,7 +56,7 @@ /** * size of HPSRAM system heap */ -#define HEAPMEM_SIZE 0x40000 +#define HEAPMEM_SIZE 0xD0000 #endif /* __PLATFORM_LIB_MEMORY_H__ */ diff --git a/src/platform/lunarlake/lib/clk.c b/src/platform/lunarlake/lib/clk.c index ed2936b5efc4..7ad664c94118 100644 --- a/src/platform/lunarlake/lib/clk.c +++ b/src/platform/lunarlake/lib/clk.c @@ -9,9 +9,8 @@ #include static const struct freq_table platform_cpu_freq[] = { - { 38400000, 38400 }, - { 120000000, 120000 }, - { CLK_MAX_CPU_HZ, 400000 }, + { CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000 }, + { CLK_MAX_CPU_HZ, CLK_MAX_CPU_HZ / 1000 }, }; STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, invalid_number_of_cpu_frequencies); diff --git a/src/platform/meteorlake/include/platform/lib/clk.h b/src/platform/meteorlake/include/platform/lib/clk.h index 2eb1732aad55..fec0a582ab7e 100644 --- a/src/platform/meteorlake/include/platform/lib/clk.h +++ b/src/platform/meteorlake/include/platform/lib/clk.h @@ -14,21 +14,19 @@ #include -#define CLK_MAX_CPU_HZ 400000000 +#define CLK_MAX_CPU_HZ CONFIG_XTENSA_CCOUNT_HZ #define CPU_WOVCRO_FREQ_IDX 0 -#define CPU_LPRO_FREQ_IDX 1 - -#define CPU_HPRO_FREQ_IDX 2 +#define CPU_IPLL_FREQ_IDX 1 #define CPU_LOWEST_FREQ_IDX CPU_WOVCRO_FREQ_IDX -#define CPU_DEFAULT_IDX CPU_HPRO_FREQ_IDX +#define CPU_DEFAULT_IDX CPU_IPLL_FREQ_IDX #define SSP_DEFAULT_IDX 1 -#define NUM_CPU_FREQ 3 +#define NUM_CPU_FREQ 2 #define NUM_SSP_FREQ 3 diff --git a/src/platform/meteorlake/lib/clk.c b/src/platform/meteorlake/lib/clk.c index 227bc9fd9366..20221b89d790 100644 --- a/src/platform/meteorlake/lib/clk.c +++ b/src/platform/meteorlake/lib/clk.c @@ -9,9 +9,8 @@ #include static const struct freq_table platform_cpu_freq[] = { - { 38400000, 38400 }, - { 120000000, 120000 }, - { CLK_MAX_CPU_HZ, 400000 }, + { CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000 }, + { CLK_MAX_CPU_HZ, CLK_MAX_CPU_HZ / 1000 }, }; STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, invalid_number_of_cpu_frequencies); diff --git a/src/platform/posix/include/platform/lib/clk.h b/src/platform/posix/include/platform/lib/clk.h index 3c9ff3b96950..7d396330a0cb 100644 --- a/src/platform/posix/include/platform/lib/clk.h +++ b/src/platform/posix/include/platform/lib/clk.h @@ -5,6 +5,7 @@ #define CLK_MAX_CPU_HZ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC #define CPU_LPRO_FREQ_IDX 1 +#define CPU_LOWEST_FREQ_IDX CPU_LPRO_FREQ_IDX /* This is not a platform function, it's defined in src/lib/clk.c. * But the declaration has historically been in the platform layer, so diff --git a/src/probe/probe.c b/src/probe/probe.c index 91344e08c56a..933cea584f6d 100644 --- a/src/probe/probe.c +++ b/src/probe/probe.c @@ -841,7 +841,7 @@ static void kick_probe_task(struct probe_pdata *_probe) } #if CONFIG_LOG_BACKEND_SOF_PROBE -static void probe_logging_hook(uint8_t *buffer, size_t length) +void probe_logging_hook(uint8_t *buffer, size_t length) { struct probe_pdata *_probe = probe_get(); uint64_t checksum; @@ -879,7 +879,7 @@ static void probe_cb_produce(void *arg, enum notify_id type, void *data) { struct probe_pdata *_probe = probe_get(); struct buffer_cb_transact *cb_data = data; - struct comp_buffer __sparse_cache *buffer = cb_data->buffer; + struct comp_buffer *buffer = cb_data->buffer; struct probe_dma_ext *dma; uint32_t buffer_id; uint32_t head, tail; @@ -1066,7 +1066,6 @@ static bool probe_purpose_needs_ext_dma(uint32_t purpose) static struct comp_buffer *ipc4_get_buffer(struct ipc_comp_dev *dev, probe_point_id_t probe_point) { struct comp_buffer *buf; - struct comp_buffer __sparse_cache *buf_c; struct list_item *sink_list, *source_list; unsigned int queue_id; @@ -1074,9 +1073,7 @@ static struct comp_buffer *ipc4_get_buffer(struct ipc_comp_dev *dev, probe_point case PROBE_TYPE_INPUT: list_for_item(source_list, &dev->cd->bsource_list) { buf = container_of(source_list, struct comp_buffer, sink_list); - buf_c = buffer_acquire(buf); - queue_id = IPC4_SRC_QUEUE_ID(buf_c->id); - buffer_release(buf_c); + queue_id = IPC4_SRC_QUEUE_ID(buf->id); if (queue_id == probe_point.fields.index) return buf; @@ -1085,9 +1082,7 @@ static struct comp_buffer *ipc4_get_buffer(struct ipc_comp_dev *dev, probe_point case PROBE_TYPE_OUTPUT: list_for_item(sink_list, &dev->cd->bsink_list) { buf = container_of(sink_list, struct comp_buffer, source_list); - buf_c = buffer_acquire(buf); - queue_id = IPC4_SINK_QUEUE_ID(buf_c->id); - buffer_release(buf_c); + queue_id = IPC4_SINK_QUEUE_ID(buf->id); if (queue_id == probe_point.fields.index) return buf; diff --git a/src/samples/audio/detect_test.c b/src/samples/audio/detect_test.c index 55058f6ca047..88a32301cf2a 100644 --- a/src/samples/audio/detect_test.c +++ b/src/samples/audio/detect_test.c @@ -101,7 +101,7 @@ struct comp_data { struct ipc_msg *msg; /**< host notification */ void (*detect_func)(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, uint32_t frames); + const struct audio_stream *source, uint32_t frames); struct sof_ipc_comp_event event; #if CONFIG_AMS @@ -209,7 +209,7 @@ void detect_test_notify(const struct comp_dev *dev) } static void default_detect_test(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, + const struct audio_stream *source, uint32_t frames) { struct comp_data *cd = comp_get_drvdata(dev); @@ -797,7 +797,6 @@ static int test_keyword_params(struct comp_dev *dev, { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sourceb; - struct comp_buffer __sparse_cache *source_c; unsigned int channels, rate; enum sof_ipc_frame frame_fmt; int err; @@ -815,11 +814,9 @@ static int test_keyword_params(struct comp_dev *dev, /* keyword components will only ever have 1 source */ sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(sourceb); - channels = audio_stream_get_channels(&source_c->stream); - frame_fmt = audio_stream_get_frm_fmt(&source_c->stream); - rate = audio_stream_get_rate(&source_c->stream); - buffer_release(source_c); + channels = audio_stream_get_channels(&sourceb->stream); + frame_fmt = audio_stream_get_frm_fmt(&sourceb->stream); + rate = audio_stream_get_rate(&sourceb->stream); if (channels != 1) { comp_err(dev, "test_keyword_params(): only single-channel supported"); @@ -881,7 +878,6 @@ static int test_keyword_copy(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *source; - struct comp_buffer __sparse_cache *source_c; uint32_t frames; comp_dbg(dev, "test_keyword_copy()"); @@ -889,23 +885,18 @@ static int test_keyword_copy(struct comp_dev *dev) /* keyword components will only ever have 1 source */ source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - source_c = buffer_acquire(source); - if (!audio_stream_get_avail(&source_c->stream)) { - buffer_release(source_c); + if (!audio_stream_get_avail(&source->stream)) return PPL_STATUS_PATH_STOP; - } - frames = audio_stream_get_avail_frames(&source_c->stream); + frames = audio_stream_get_avail_frames(&source->stream); /* copy and perform detection */ - buffer_stream_invalidate(source_c, audio_stream_get_avail_bytes(&source_c->stream)); - cd->detect_func(dev, &source_c->stream, frames); + buffer_stream_invalidate(source, audio_stream_get_avail_bytes(&source->stream)); + cd->detect_func(dev, &source->stream, frames); /* calc new available */ - comp_update_buffer_consume(source_c, audio_stream_get_avail_bytes(&source_c->stream)); - - buffer_release(source_c); + comp_update_buffer_consume(source, audio_stream_get_avail_bytes(&source->stream)); return 0; } diff --git a/src/samples/audio/kwd_nn_detect_test.c b/src/samples/audio/kwd_nn_detect_test.c index df0a8c80af98..ef71a441580b 100644 --- a/src/samples/audio/kwd_nn_detect_test.c +++ b/src/samples/audio/kwd_nn_detect_test.c @@ -35,7 +35,7 @@ static int kwd_nn_detect_postprocess(uint8_t confidences[KWD_NN_CONFIDENCES_SIZE } void kwd_nn_detect_test(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, + const struct audio_stream *source, uint32_t frames) { void *src; diff --git a/src/samples/audio/smart_amp_test_ipc3.c b/src/samples/audio/smart_amp_test_ipc3.c index b2056c6cb7d0..ce03381d5bbe 100644 --- a/src/samples/audio/smart_amp_test_ipc3.c +++ b/src/samples/audio/smart_amp_test_ipc3.c @@ -28,8 +28,8 @@ DECLARE_TR_CTX(smart_amp_comp_tr, SOF_UUID(smart_amp_comp_uuid), LOG_LEVEL_INFO); typedef int(*smart_amp_proc)(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, uint32_t frames, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames, int8_t *chan_map); struct smart_amp_data { @@ -316,9 +316,7 @@ static int smart_amp_trigger(struct comp_dev *dev, int cmd) case COMP_TRIGGER_START: case COMP_TRIGGER_RELEASE: if (sad->feedback_buf) { - struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); - buffer_zero(buf); - buffer_release(buf); + buffer_zero(sad->feedback_buf); } break; case COMP_TRIGGER_PAUSE: @@ -332,8 +330,8 @@ static int smart_amp_trigger(struct comp_dev *dev, int cmd) } static int smart_amp_process_s16(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames, int8_t *chan_map) { struct smart_amp_data *sad = comp_get_drvdata(dev); @@ -364,8 +362,8 @@ static int smart_amp_process_s16(struct comp_dev *dev, } static int smart_amp_process_s32(struct comp_dev *dev, - const struct audio_stream __sparse_cache *source, - const struct audio_stream __sparse_cache *sink, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames, int8_t *chan_map) { struct smart_amp_data *sad = comp_get_drvdata(dev); @@ -397,7 +395,7 @@ static int smart_amp_process_s32(struct comp_dev *dev, } static smart_amp_proc get_smart_amp_process(struct comp_dev *dev, - struct comp_buffer __sparse_cache *buf) + struct comp_buffer *buf) { switch (audio_stream_get_frm_fmt(&buf->stream)) { case SOF_IPC_FRAME_S16_LE: @@ -414,8 +412,8 @@ static smart_amp_proc get_smart_amp_process(struct comp_dev *dev, static int smart_amp_copy(struct comp_dev *dev) { struct smart_amp_data *sad = comp_get_drvdata(dev); - struct comp_buffer __sparse_cache *source_buf = buffer_acquire(sad->source_buf); - struct comp_buffer __sparse_cache *sink_buf = buffer_acquire(sad->sink_buf); + struct comp_buffer *source_buf = sad->source_buf; + struct comp_buffer *sink_buf = sad->sink_buf; uint32_t avail_passthrough_frames; uint32_t avail_feedback_frames; uint32_t avail_frames = 0; @@ -431,7 +429,7 @@ static int smart_amp_copy(struct comp_dev *dev) &sink_buf->stream); if (sad->feedback_buf) { - struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); + struct comp_buffer *buf = sad->feedback_buf; if (buf->source && comp_get_state(dev, buf->source) == dev->state) { /* feedback */ @@ -454,8 +452,6 @@ static int smart_amp_copy(struct comp_dev *dev) comp_update_buffer_consume(buf, feedback_bytes); } - - buffer_release(buf); } if (!avail_frames) @@ -477,9 +473,6 @@ static int smart_amp_copy(struct comp_dev *dev) comp_update_buffer_consume(source_buf, source_bytes); comp_update_buffer_produce(sink_buf, sink_bytes); - buffer_release(sink_buf); - buffer_release(source_buf); - return 0; } @@ -496,7 +489,6 @@ static int smart_amp_prepare(struct comp_dev *dev) { struct smart_amp_data *sad = comp_get_drvdata(dev); struct comp_buffer *source_buffer; - struct comp_buffer __sparse_cache *buffer_c; struct list_item *blist; int ret; @@ -513,43 +505,33 @@ static int smart_amp_prepare(struct comp_dev *dev) list_for_item(blist, &dev->bsource_list) { source_buffer = container_of(blist, struct comp_buffer, sink_list); - buffer_c = buffer_acquire(source_buffer); /* FIXME: how often can this loop be run? */ - if (buffer_c->source->ipc_config.type == SOF_COMP_DEMUX) + if (source_buffer->source->ipc_config.type == SOF_COMP_DEMUX) sad->feedback_buf = source_buffer; else sad->source_buf = source_buffer; - - buffer_release(buffer_c); } sad->sink_buf = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - buffer_c = buffer_acquire(sad->sink_buf); - sad->out_channels = audio_stream_get_channels(&buffer_c->stream); - buffer_release(buffer_c); + sad->out_channels = audio_stream_get_channels(&sad->sink_buf->stream); - buffer_c = buffer_acquire(sad->source_buf); - sad->in_channels = audio_stream_get_channels(&buffer_c->stream); + sad->in_channels = audio_stream_get_channels(&sad->source_buf->stream); if (sad->feedback_buf) { - struct comp_buffer __sparse_cache *buf = buffer_acquire(sad->feedback_buf); - - audio_stream_set_channels(&buf->stream, sad->config.feedback_channels); - audio_stream_set_rate(&buf->stream, audio_stream_get_rate(&buffer_c->stream)); - buffer_release(buf); + audio_stream_set_channels(&sad->feedback_buf->stream, + sad->config.feedback_channels); + audio_stream_set_rate(&sad->feedback_buf->stream, + audio_stream_get_rate(&sad->source_buf->stream)); } - sad->process = get_smart_amp_process(dev, buffer_c); + sad->process = get_smart_amp_process(dev, sad->source_buf); if (!sad->process) { comp_err(dev, "smart_amp_prepare(): get_smart_amp_process failed"); ret = -EINVAL; } - - buffer_release(buffer_c); - return ret; } diff --git a/src/samples/audio/smart_amp_test_ipc4.c b/src/samples/audio/smart_amp_test_ipc4.c index a256de9c3d28..c743513b1ad5 100644 --- a/src/samples/audio/smart_amp_test_ipc4.c +++ b/src/samples/audio/smart_amp_test_ipc4.c @@ -92,7 +92,6 @@ static void smart_amp_set_params(struct processing_module *mod) struct comp_dev *dev = mod->dev; struct smart_amp_data *sad = module_get_private_data(mod); struct comp_buffer *sink; - struct comp_buffer __sparse_cache *sink_c; ipc4_base_module_cfg_to_stream_params(&mod->priv.cfg.base_cfg, params); @@ -102,11 +101,9 @@ static void smart_amp_set_params(struct processing_module *mod) struct ipc4_audio_format out_fmt = sink_fmt->audio_fmt; sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sink_c = buffer_acquire(sink); - ipc4_update_buffer_format(sink_c, &out_fmt); - params->frame_fmt = audio_stream_get_frm_fmt(&sink_c->stream); - buffer_release(sink_c); + ipc4_update_buffer_format(sink, &out_fmt); + params->frame_fmt = audio_stream_get_frm_fmt(&sink->stream); } } @@ -196,8 +193,8 @@ static int smart_amp_process_s16(struct processing_module *mod, uint32_t frames, int8_t *chan_map) { struct smart_amp_data *sad = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int16_t *src; int16_t *dest; uint32_t in_frag = 0; @@ -229,8 +226,8 @@ static int smart_amp_process_s32(struct processing_module *mod, uint32_t frames, int8_t *chan_map) { struct smart_amp_data *sad = module_get_private_data(mod); - struct audio_stream __sparse_cache *source = bsource->data; - struct audio_stream __sparse_cache *sink = bsink->data; + struct audio_stream *source = bsource->data; + struct audio_stream *sink = bsink->data; int32_t *src; int32_t *dest; uint32_t in_frag = 0; @@ -258,7 +255,7 @@ static int smart_amp_process_s32(struct processing_module *mod, } static smart_amp_proc get_smart_amp_process(struct comp_dev *dev, - struct comp_buffer __sparse_cache *buf) + struct comp_buffer *buf) { switch (audio_stream_get_frm_fmt(&buf->stream)) { case SOF_IPC_FRAME_S16_LE: @@ -278,9 +275,8 @@ static int smart_amp_process(struct processing_module *mod, { struct smart_amp_data *sad = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct comp_buffer __sparse_cache *fb_buf_c; - struct comp_buffer __sparse_cache *buf; - struct module_source_info __sparse_cache *mod_source_info; + struct comp_buffer *fb_buf_c; + struct comp_buffer *buf; struct input_stream_buffer *fb_input = NULL; /* if there is only one input stream, it should be the source input */ struct input_stream_buffer *src_input = &input_buffers[0]; @@ -289,13 +285,9 @@ static int smart_amp_process(struct processing_module *mod, uint32_t sink_bytes; uint32_t i; - mod_source_info = module_source_info_acquire(mod->source_info); - if (num_input_buffers == SMART_AMP_NUM_IN_PINS) for (i = 0; i < num_input_buffers; i++) { - buf = attr_container_of(input_buffers[i].data, - struct comp_buffer __sparse_cache, - stream, __sparse_cache); + buf = container_of(input_buffers[i].data, struct comp_buffer, stream); if (IPC4_SINK_QUEUE_ID(buf->id) == SOF_SMART_AMP_FEEDBACK_QUEUE_ID) { fb_input = &input_buffers[i]; @@ -331,7 +323,6 @@ static int smart_amp_process(struct processing_module *mod, output_buffers[0].size = sink_bytes; - module_source_info_release(mod_source_info); return 0; } @@ -345,14 +336,13 @@ static int smart_amp_reset(struct processing_module *mod) } static int smart_amp_prepare(struct processing_module *mod, - struct sof_source __sparse_cache **sources, int num_of_sources, - struct sof_sink __sparse_cache **sinks, int num_of_sinks) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct smart_amp_data *sad = module_get_private_data(mod); struct comp_dev *dev = mod->dev; struct comp_buffer *source_buffer; struct comp_buffer *sink_buffer; - struct comp_buffer __sparse_cache *buffer_c; struct list_item *blist; int ret; @@ -365,22 +355,19 @@ static int smart_amp_prepare(struct processing_module *mod, list_for_item(blist, &dev->bsource_list) { source_buffer = container_of(blist, struct comp_buffer, sink_list); - buffer_c = buffer_acquire(source_buffer); - audio_stream_init_alignment_constants(1, 1, &buffer_c->stream); - if (IPC4_SINK_QUEUE_ID(buffer_c->id) == SOF_SMART_AMP_FEEDBACK_QUEUE_ID) { - audio_stream_set_channels(&buffer_c->stream, sad->config.feedback_channels); - audio_stream_set_rate(&buffer_c->stream, + audio_stream_init_alignment_constants(1, 1, &source_buffer->stream); + if (IPC4_SINK_QUEUE_ID(source_buffer->id) == SOF_SMART_AMP_FEEDBACK_QUEUE_ID) { + audio_stream_set_channels(&source_buffer->stream, + sad->config.feedback_channels); + audio_stream_set_rate(&source_buffer->stream, mod->priv.cfg.base_cfg.audio_fmt.sampling_frequency); } - buffer_release(buffer_c); } sink_buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - buffer_c = buffer_acquire(sink_buffer); - sad->out_channels = audio_stream_get_channels(&buffer_c->stream); - audio_stream_init_alignment_constants(1, 1, &buffer_c->stream); - sad->process = get_smart_amp_process(dev, buffer_c); - buffer_release(buffer_c); + sad->out_channels = audio_stream_get_channels(&sink_buffer->stream); + audio_stream_init_alignment_constants(1, 1, &sink_buffer->stream); + sad->process = get_smart_amp_process(dev, sink_buffer); if (!sad->process) { comp_err(dev, "smart_amp_prepare(): get_smart_amp_process failed"); @@ -389,8 +376,8 @@ static int smart_amp_prepare(struct processing_module *mod, return ret; } -static struct module_interface smart_amp_interface = { - .init = smart_amp_init, +static const struct module_interface smart_amp_interface = { + .init = smart_amp_init, .prepare = smart_amp_prepare, .process_audio_stream = smart_amp_process, .set_configuration = smart_amp_set_config, diff --git a/src/schedule/zephyr_dp_schedule.c b/src/schedule/zephyr_dp_schedule.c index a51304e9a6db..cdc5e6a8ad32 100644 --- a/src/schedule/zephyr_dp_schedule.c +++ b/src/schedule/zephyr_dp_schedule.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -29,15 +30,15 @@ DECLARE_TR_CTX(dp_tr, SOF_UUID(dp_sched_uuid), LOG_LEVEL_INFO); struct scheduler_dp_data { struct list_item tasks; /* list of active dp tasks */ - struct task task; /* LL task - source of DP tick */ + struct task ll_tick_src; /* LL task - source of DP tick */ }; struct task_dp_pdata { k_tid_t thread_id; /* zephyr thread ID */ + uint32_t period_clock_ticks; /* period the task should be scheduled in Zephyr ticks */ k_thread_stack_t __sparse_cache *p_stack; /* pointer to thread stack */ - uint32_t ticks_period; /* period the task should be scheduled in LL ticks */ - uint32_t ticks_to_trigger; /* number of ticks the task should be triggered after */ struct k_sem sem; /* semaphore for task scheduling */ + struct processing_module *mod; /* the module to be scheduled */ }; /* Single CPU-wide lock @@ -63,9 +64,154 @@ static enum task_state scheduler_dp_ll_tick_dummy(void *data) /* * function called after every LL tick * - * TODO: - * the scheduler should here calculate deadlines of all task and tell Zephyr about them - * Currently there's an assumption that the task is always ready to run + * This function checks if the queued DP tasks are ready to processing (meaning + * the module run by the task has enough data at all sources and enough free space + * on all sinks) + * + * if the task becomes ready, a deadline is set allowing Zephyr to schedule threads + * in right order + * + * TODO: currently there's a limitation - DP module must be surrounded by LL modules. + * it simplifies algorithm - there's no need to browse through DP chains calculating + * deadlines for each module in function of all modules execution status. + * Now is simple - modules deadline is its start + tick time. + * + * example: + * Lets assume we do have a pipeline: + * + * LL1 -> DP1 -> LL2 -> DP2 -> LL3 -> DP3 -> LL4 + * + * all LLs starts in 1ms tick + * + * for simplification lets assume + * - all LLs are on primary core, all DPs on secondary (100% CPU is for DP) + * - context switching requires 0 cycles + * + * DP1 - starts every 1ms, needs 0.5ms to finish processing + * DP2 - starts every 2ms, needs 0.6ms to finish processing + * DP3 - starts every 10ms, needs 0.3ms to finish processing + * + * TICK0 + * only LL1 is ready to run + * LL1 processing (producing data chunk for DP1) + * + * TICK1 + * LL1 is ready to run + * DP1 is ready tu run (has data from LL1) set deadline to TICK2 + * LL1 processing (producing second data chunk for DP1) + * DP1 processing for 0.5ms (consuming first data chunk, producing data chunk for LL2) + * CPU is idle for 0.5ms + * + * TICK2 + * LL1 is ready to run + * DP1 is ready tu run set deadline to TICK3 + * LL2 is ready to run + * LL1 processing (producing data chunk for DP1) + * LL2 processing (producing 50% data chunk for DP2) + * DP1 processing for 0.5ms (producing data chunk for LL2) + * CPU is idle for 0.5ms + * + * TICK3 + * LL1 is ready to run + * DP1 is ready tu run set deadline to TICK4 + * LL2 is ready to run + * LL1 processing (producing data chunk for DP1) + * LL2 processing (producing rest of data chunk for DP2) + * DP1 processing for 0.5ms (producing data chunk for LL2) + * CPU is idle for 0.5ms + * + * TICK4 + * LL1 is ready to run + * DP1 is ready tu run set deadline to TICK5 + * LL2 is ready to run + * DP2 is ready to run set deadline to TICK6 + * LL1 processing (producing data chunk for DP1) + * LL2 processing (producing 50% of second data chunk for DP2) + * DP1 processing for 0.5ms (producing data chunk for LL2) + * DP2 processing for 0.5ms (no data produced as DP2 has 0.1ms to go) + * 100% CPU used + * + * !!!!!! Note here - DP1 must do before DP2 as it MUST finish in this tick. DP2 can wait + * >>>>>>> this is what we call EDF - EARIEST DEADLINE FIRST <<<<<< + * + * TICK5 + * LL1 is ready to run + * DP1 is ready tu run set deadline to TICK6 + * LL2 is ready to run + * DP2 is in progress, deadline is set to TICK6 + * LL1 processing (producing data chunk for DP1) + * LL2 processing (producing rest of second data chunk for DP2) + * DP1 processing for 0.5ms (producing data chunk for LL2) + * DP2 processing for 0.1ms (producing TWO data chunks for LL3) + * CPU is idle for 0.4ms (60% used) + * + * TICK6 + * LL1 is ready to run + * DP1 is ready tu run set deadline to TICK7 + * LL2 is ready to run + * DP2 is ready to run set deadline to TICK8 + * LL3 is ready to run + * LL1 processing (producing data chunk for DP1) + * LL2 processing (producing 50% of second data chunk for DP2) + * LL3 processing (producing 10% of first data chunk for DP3) + * DP1 processing for 0.5ms (producing data chunk for LL2) + * DP2 processing for 0.5ms (no data produced as DP2 has 0.1ms to go) + * 100% CPU used + * + * + * + * (........ 9 more cycles - LL3 procuces 100% of data for DP3......) + * + * + * TICK15 + * LL1 is ready to run + * DP1 is ready tu run set deadline to TICK16 + * LL2 is ready to run + * DP2 is ready to run set deadline to TICK17 + * LL3 is ready to run + * DP3 is ready to run set deadline to TICK25 + * LL1 processing (producing data chunk for DP1) + * LL2 processing (producing 50% of data chunk for DP2) + * LL3 processing (producing 10% of second data chunk for DP3) + * DP1 processing for 0.5ms (producing data chunk for LL2) + * DP2 processing for 0.5ms (no data produced as DP2 has 0.1ms to go) + * 100% CPU used - + * !!! note that DP3 is ready but has no chance to get CPU in this cycle + * + * TICK16 + * LL1 is ready to run set deadline to TICK17 + * DP1 is ready tu run + * LL2 is ready to run + * DP2 is in progress, deadline is set to TICK17 + * LL3 is ready to run + * DP3 is in progress, deadline is set to TICK25 + * LL1 processing (producing data chunk for DP1) + * LL2 processing (producing rest of data chunk for DP2) + * LL3 processing (producing 10% of second data chunk for DP3) + * DP1 processing for 0.5ms (producing data chunk for LL2) + * DP2 processing for 0.1ms (producing data) + * DP3 processing for 0.2ms (producing 10 data chunks for LL4) + * 90% CPU used + * + * TICK17 + * LL1 is ready to run + * DP1 is ready tu run + * LL2 is ready to run + * DP2 is ready to run + * LL3 is ready to run + * LL4 is ready to run + * !! NOTE that DP3 is not ready - it will be ready again in TICK25 + * LL1 processing (producing data chunk for DP1) + * LL2 processing (producing rest of data chunk for DP2) + * LL3 processing (producing next 10% of second data chunk for DP3) + * LL4 processing (consuming 10% of data prepared by DP3) + * DP1 processing for 0.5ms (producing data chunk for LL2) + * DP2 processing for 0.5ms (no data produced as DP2 has 0.1ms to go) + * 100% CPU used + * + * + * Now - pipeline is in stable state, CPU used almost in 100% (it would be 100% if DP3 + * needed 1.2ms for processing - but the example would be too complicated) */ void scheduler_dp_ll_tick(void *receiver_data, enum notify_id event_type, void *caller_data) { @@ -81,20 +227,25 @@ void scheduler_dp_ll_tick(void *receiver_data, enum notify_id event_type, void * lock_key = scheduler_dp_lock(); list_for_item(tlist, &dp_sch->tasks) { curr_task = container_of(tlist, struct task, list); - pdata = curr_task->priv_data; - if (pdata->ticks_to_trigger == 0) { - if (curr_task->state == SOF_TASK_STATE_QUEUED) { - /* set new trigger time, start the thread */ - pdata->ticks_to_trigger = pdata->ticks_period; + /* step 1 - check if the module is ready for processing */ + if (curr_task->state == SOF_TASK_STATE_QUEUED) { + pdata = curr_task->priv_data; + struct processing_module *mod = pdata->mod; + bool mod_ready; + + mod_ready = module_is_ready_to_process(mod, mod->sources, + mod->num_of_sources, + mod->sinks, + mod->num_of_sinks); + if (mod_ready) { + /* set a deadline for given num of ticks, starting now */ + k_thread_deadline_set(pdata->thread_id, pdata->period_clock_ticks); + + /* trigger the task */ curr_task->state = SOF_TASK_STATE_RUNNING; k_sem_give(&pdata->sem); } - } else { - if (curr_task->state == SOF_TASK_STATE_QUEUED || - curr_task->state == SOF_TASK_STATE_RUNNING) - /* decrease num of ticks to re-schedule */ - pdata->ticks_to_trigger--; } } scheduler_dp_unlock(lock_key); @@ -103,6 +254,7 @@ void scheduler_dp_ll_tick(void *receiver_data, enum notify_id event_type, void * static int scheduler_dp_task_cancel(void *data, struct task *task) { unsigned int lock_key; + struct scheduler_dp_data *dp_sch = (struct scheduler_dp_data *)data; /* this is asyn cancel - mark the task as canceled and remove it from scheduling */ lock_key = scheduler_dp_lock(); @@ -110,6 +262,10 @@ static int scheduler_dp_task_cancel(void *data, struct task *task) task->state = SOF_TASK_STATE_CANCEL; list_item_del(&task->list); + /* if there're no more DP task, stop LL tick source */ + if (list_is_empty(&dp_sch->tasks)) + schedule_task_cancel(&dp_sch->ll_tick_src); + scheduler_dp_unlock(lock_key); return 0; @@ -117,18 +273,12 @@ static int scheduler_dp_task_cancel(void *data, struct task *task) static int scheduler_dp_task_free(void *data, struct task *task) { - unsigned int lock_key; struct task_dp_pdata *pdata = task->priv_data; + scheduler_dp_task_cancel(data, task); + /* abort the execution of the thread */ k_thread_abort(pdata->thread_id); - - lock_key = scheduler_dp_lock(); - list_item_del(&task->list); - task->priv_data = NULL; - task->state = SOF_TASK_STATE_FREE; - scheduler_dp_unlock(lock_key); - /* free task stack */ rfree((__sparse_force void *)pdata->p_stack); @@ -202,6 +352,7 @@ static int scheduler_dp_task_shedule(void *data, struct task *task, uint64_t sta struct scheduler_dp_data *dp_sch = (struct scheduler_dp_data *)data; struct task_dp_pdata *pdata = task->priv_data; unsigned int lock_key; + uint64_t period_clock_ticks; lock_key = scheduler_dp_lock(); @@ -212,27 +363,24 @@ static int scheduler_dp_task_shedule(void *data, struct task *task, uint64_t sta return -EINVAL; } - /* calculate period and start time in LL ticks */ - pdata->ticks_period = period / LL_TIMER_PERIOD_US; + /* if there's no DP tasks scheduled yet, run ll tick source task */ + if (list_is_empty(&dp_sch->tasks)) + schedule_task(&dp_sch->ll_tick_src, 0, 0); /* add a task to DP scheduler list */ + task->state = SOF_TASK_STATE_QUEUED; list_item_prepend(&task->list, &dp_sch->tasks); - if (start == SCHEDULER_DP_RUN_TASK_IMMEDIATELY) { - /* trigger the task immediately, don't wait for LL tick */ - pdata->ticks_to_trigger = 0; - task->state = SOF_TASK_STATE_RUNNING; - k_sem_give(&pdata->sem); - } else { - /* wait for tick */ - pdata->ticks_to_trigger = start / LL_TIMER_PERIOD_US; - task->state = SOF_TASK_STATE_QUEUED; - } + period_clock_ticks = period * CONFIG_SYS_CLOCK_TICKS_PER_SEC; + /* period is in us - convert to seconds in next step + * or it always will be zero because of fixed point calculation + */ + period_clock_ticks /= 1000000; + pdata->period_clock_ticks = period_clock_ticks; scheduler_dp_unlock(lock_key); - /* start LL task - run DP tick start and period are irrelevant for LL (that's bad)*/ - schedule_task(&dp_sch->task, 0, 0); + tr_dbg(&dp_tr, "DP task scheduled with period %u [us]", (uint32_t)period); return 0; } @@ -255,7 +403,7 @@ int scheduler_dp_init(void) scheduler_init(SOF_SCHEDULE_DP, &schedule_dp_ops, dp_sch); /* init src of DP tick */ - ret = schedule_task_init_ll(&dp_sch->task, + ret = schedule_task_init_ll(&dp_sch->ll_tick_src, SOF_UUID(dp_sched_uuid), SOF_SCHEDULE_LL_TIMER, 0, scheduler_dp_ll_tick_dummy, dp_sch, @@ -272,7 +420,7 @@ int scheduler_dp_init(void) int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid, const struct task_ops *ops, - void *data, + struct processing_module *mod, uint16_t core, size_t stack_size, uint32_t task_priority) @@ -335,7 +483,7 @@ int scheduler_dp_task_init(struct task **task, /* internal SOF task init */ ret = schedule_task_init(&task_memory->task, uid, SOF_SCHEDULE_DP, 0, ops->run, - data, core, 0); + mod, core, 0); if (ret < 0) { tr_err(&dp_tr, "zephyr_dp_task_init(): schedule_task_init failed"); goto err; @@ -354,6 +502,7 @@ int scheduler_dp_task_init(struct task **task, task_memory->task.priv_data = &task_memory->pdata; task_memory->pdata.thread_id = thread_id; task_memory->pdata.p_stack = p_stack; + task_memory->pdata.mod = mod; *task = &task_memory->task; /* start the thread - it will immediately stop at a semaphore */ diff --git a/test/cmocka/src/audio/buffer/buffer_copy.c b/test/cmocka/src/audio/buffer/buffer_copy.c index 1983d92edfdf..be1500cb66f0 100644 --- a/test/cmocka/src/audio/buffer/buffer_copy.c +++ b/test/cmocka/src/audio/buffer/buffer_copy.c @@ -29,8 +29,8 @@ static void test_audio_buffer_copy_underrun(void **state) .size = 256 }; - struct comp_buffer *src = buffer_new(&test_buf_desc); - struct comp_buffer *snk = buffer_new(&test_buf_desc); + struct comp_buffer *src = buffer_new(&test_buf_desc, false); + struct comp_buffer *snk = buffer_new(&test_buf_desc, false); assert_non_null(src); assert_non_null(snk); @@ -56,8 +56,8 @@ static void test_audio_buffer_copy_overrun(void **state) .size = 256 }; - struct comp_buffer *src = buffer_new(&test_buf_desc); - struct comp_buffer *snk = buffer_new(&test_buf_desc); + struct comp_buffer *src = buffer_new(&test_buf_desc, false); + struct comp_buffer *snk = buffer_new(&test_buf_desc, false); assert_non_null(src); assert_non_null(snk); @@ -85,8 +85,8 @@ static void test_audio_buffer_copy_success(void **state) .size = 256 }; - struct comp_buffer *src = buffer_new(&test_buf_desc); - struct comp_buffer *snk = buffer_new(&test_buf_desc); + struct comp_buffer *src = buffer_new(&test_buf_desc, false); + struct comp_buffer *snk = buffer_new(&test_buf_desc, false); assert_non_null(src); assert_non_null(snk); @@ -111,8 +111,8 @@ static void test_audio_buffer_copy_fit_space_constraint(void **state) .size = 256 }; - struct comp_buffer *src = buffer_new(&test_buf_desc); - struct comp_buffer *snk = buffer_new(&test_buf_desc); + struct comp_buffer *src = buffer_new(&test_buf_desc, false); + struct comp_buffer *snk = buffer_new(&test_buf_desc, false); assert_non_null(src); assert_non_null(snk); @@ -139,8 +139,8 @@ static void test_audio_buffer_copy_fit_no_space_constraint(void **state) .size = 256 }; - struct comp_buffer *src = buffer_new(&test_buf_desc); - struct comp_buffer *snk = buffer_new(&test_buf_desc); + struct comp_buffer *src = buffer_new(&test_buf_desc, false); + struct comp_buffer *snk = buffer_new(&test_buf_desc, false); assert_non_null(src); assert_non_null(snk); diff --git a/test/cmocka/src/audio/buffer/buffer_new.c b/test/cmocka/src/audio/buffer/buffer_new.c index 2f78033a5fc1..e2ce0c274b57 100644 --- a/test/cmocka/src/audio/buffer/buffer_new.c +++ b/test/cmocka/src/audio/buffer/buffer_new.c @@ -27,7 +27,7 @@ static void test_audio_buffer_new(void **state) .size = 256 }; - struct comp_buffer *buf = buffer_new(&test_buf_desc); + struct comp_buffer *buf = buffer_new(&test_buf_desc, false); assert_non_null(buf); assert_int_equal(audio_stream_get_avail_bytes(&buf->stream), 0); diff --git a/test/cmocka/src/audio/buffer/buffer_wrap.c b/test/cmocka/src/audio/buffer/buffer_wrap.c index 210bce1a2ef0..b0c7d11ce555 100644 --- a/test/cmocka/src/audio/buffer/buffer_wrap.c +++ b/test/cmocka/src/audio/buffer/buffer_wrap.c @@ -27,7 +27,7 @@ static void test_audio_buffer_write_fill_10_bytes_and_write_5(void **state) .size = 10 }; - struct comp_buffer *buf = buffer_new(&test_buf_desc); + struct comp_buffer *buf = buffer_new(&test_buf_desc, false); assert_non_null(buf); assert_int_equal(audio_stream_get_avail_bytes(&buf->stream), 0); diff --git a/test/cmocka/src/audio/buffer/buffer_write.c b/test/cmocka/src/audio/buffer/buffer_write.c index 8c4fc185c2db..8c3e437d612a 100644 --- a/test/cmocka/src/audio/buffer/buffer_write.c +++ b/test/cmocka/src/audio/buffer/buffer_write.c @@ -28,7 +28,7 @@ static void test_audio_buffer_write_10_bytes_out_of_256_and_read_back .size = 256 }; - struct comp_buffer *buf = buffer_new(&test_buf_desc); + struct comp_buffer *buf = buffer_new(&test_buf_desc, false); assert_non_null(buf); assert_int_equal(audio_stream_get_avail_bytes(&buf->stream), 0); @@ -63,7 +63,7 @@ static void test_audio_buffer_fill_10_bytes(void **state) .size = 10 }; - struct comp_buffer *buf = buffer_new(&test_buf_desc); + struct comp_buffer *buf = buffer_new(&test_buf_desc, false); assert_non_null(buf); assert_int_equal(audio_stream_get_avail_bytes(&buf->stream), 0); diff --git a/test/cmocka/src/audio/eq_fir/CMakeLists.txt b/test/cmocka/src/audio/eq_fir/CMakeLists.txt index af9fa80d0b60..3369f2b97b06 100644 --- a/test/cmocka/src/audio/eq_fir/CMakeLists.txt +++ b/test/cmocka/src/audio/eq_fir/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(audio_for_eq_fir STATIC ${PROJECT_SOURCE_DIR}/src/math/fir_hifi3.c ${PROJECT_SOURCE_DIR}/src/math/numbers.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c ${PROJECT_SOURCE_DIR}/src/audio/buffer.c ${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c diff --git a/test/cmocka/src/audio/eq_iir/CMakeLists.txt b/test/cmocka/src/audio/eq_iir/CMakeLists.txt index a72903d1c1df..a520a22fa441 100644 --- a/test/cmocka/src/audio/eq_iir/CMakeLists.txt +++ b/test/cmocka/src/audio/eq_iir/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(audio_for_eq_iir STATIC ${PROJECT_SOURCE_DIR}/src/math/iir_df2t_hifi3.c ${PROJECT_SOURCE_DIR}/src/math/numbers.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c ${PROJECT_SOURCE_DIR}/src/audio/buffer.c ${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c diff --git a/test/cmocka/src/audio/mixer/CMakeLists.txt b/test/cmocka/src/audio/mixer/CMakeLists.txt index e422dd6ebf96..01aebc99223e 100644 --- a/test/cmocka/src/audio/mixer/CMakeLists.txt +++ b/test/cmocka/src/audio/mixer/CMakeLists.txt @@ -11,6 +11,7 @@ cmocka_test(mixer ${PROJECT_SOURCE_DIR}/src/ipc/ipc-common.c ${PROJECT_SOURCE_DIR}/src/ipc/ipc-helper.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c ${PROJECT_SOURCE_DIR}/src/audio/buffer.c ${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c diff --git a/test/cmocka/src/audio/mux/CMakeLists.txt b/test/cmocka/src/audio/mux/CMakeLists.txt index 59e3752599fc..c6f67ae89127 100644 --- a/test/cmocka/src/audio/mux/CMakeLists.txt +++ b/test/cmocka/src/audio/mux/CMakeLists.txt @@ -23,6 +23,7 @@ add_library( ${PROJECT_SOURCE_DIR}/src/ipc/ipc-helper.c ${PROJECT_SOURCE_DIR}/test/cmocka/src/notifier_mocks.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c ) sof_append_relative_path_definitions(audio_mux) diff --git a/test/cmocka/src/audio/volume/CMakeLists.txt b/test/cmocka/src/audio/volume/CMakeLists.txt index a1cd1fd8cab2..f6530bc2b3b0 100644 --- a/test/cmocka/src/audio/volume/CMakeLists.txt +++ b/test/cmocka/src/audio/volume/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(audio_for_volume STATIC ${PROJECT_SOURCE_DIR}/src/audio/volume/volume_hifi3_with_peakvol.c ${PROJECT_SOURCE_DIR}/src/audio/volume/volume_hifi4_with_peakvol.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c ${PROJECT_SOURCE_DIR}/src/audio/buffer.c ${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c diff --git a/test/cmocka/src/common_mocks.c b/test/cmocka/src/common_mocks.c index 180c2028b019..630bdd0a0d13 100644 --- a/test/cmocka/src/common_mocks.c +++ b/test/cmocka/src/common_mocks.c @@ -41,6 +41,8 @@ WEAK struct tr_ctx buffer_tr; WEAK struct tr_ctx comp_tr; WEAK struct tr_ctx ipc_tr; +int host_trace_level = 1; + void WEAK *rballoc_align(uint32_t flags, uint32_t caps, size_t bytes, uint32_t alignment) { diff --git a/test/cmocka/src/math/fft/fft.c b/test/cmocka/src/math/fft/fft.c index 653212c7bfc2..cfb2ec8d98bb 100644 --- a/test/cmocka/src/math/fft/fft.c +++ b/test/cmocka/src/math/fft/fft.c @@ -265,8 +265,8 @@ static void test_math_fft_256(void **state) struct sof_ipc_buffer test_buf_desc = { .size = 256 * 2 * sizeof(int32_t), }; - struct comp_buffer *source = buffer_new(&test_buf_desc); - struct comp_buffer *sink = buffer_new(&test_buf_desc); + struct comp_buffer *source = buffer_new(&test_buf_desc, false); + struct comp_buffer *sink = buffer_new(&test_buf_desc, false); struct icomplex32 *out = (struct icomplex32 *)sink->stream.addr; int32_t *in = (int32_t *)source->stream.addr; int fft_size = 256; @@ -307,8 +307,8 @@ static void test_math_fft_512(void **state) struct sof_ipc_buffer test_buf_desc = { .size = 512 * 2 * sizeof(int32_t), }; - struct comp_buffer *source = buffer_new(&test_buf_desc); - struct comp_buffer *sink = buffer_new(&test_buf_desc); + struct comp_buffer *source = buffer_new(&test_buf_desc, false); + struct comp_buffer *sink = buffer_new(&test_buf_desc, false); struct icomplex32 *out = (struct icomplex32 *)sink->stream.addr; int32_t *in = (int32_t *)source->stream.addr; int fft_size = 512; @@ -349,8 +349,8 @@ static void test_math_fft_1024(void **state) struct sof_ipc_buffer test_buf_desc = { .size = 1024 * 2 * sizeof(int32_t), }; - struct comp_buffer *source = buffer_new(&test_buf_desc); - struct comp_buffer *sink = buffer_new(&test_buf_desc); + struct comp_buffer *source = buffer_new(&test_buf_desc, false); + struct comp_buffer *sink = buffer_new(&test_buf_desc, false); struct icomplex32 *out = (struct icomplex32 *)sink->stream.addr; int32_t *in = (int32_t *)source->stream.addr; int fft_size = 1024; @@ -391,9 +391,9 @@ static void test_math_fft_1024_ifft(void **state) struct sof_ipc_buffer test_buf_desc = { .size = 1024 * 4 * 2, }; - struct comp_buffer *source = buffer_new(&test_buf_desc); - struct comp_buffer *intm = buffer_new(&test_buf_desc); - struct comp_buffer *sink = buffer_new(&test_buf_desc); + struct comp_buffer *source = buffer_new(&test_buf_desc, false); + struct comp_buffer *intm = buffer_new(&test_buf_desc, false); + struct comp_buffer *sink = buffer_new(&test_buf_desc, false); struct icomplex32 *out = (struct icomplex32 *)sink->stream.addr; float db; int64_t signal = 0; @@ -432,9 +432,9 @@ static void test_math_fft_512_2ch(void **state) struct sof_ipc_buffer test_buf_desc = { .size = 512 * 4 * 2, }; - struct comp_buffer *source = buffer_new(&test_buf_desc); - struct comp_buffer *sink1 = buffer_new(&test_buf_desc); - struct comp_buffer *sink2 = buffer_new(&test_buf_desc); + struct comp_buffer *source = buffer_new(&test_buf_desc, false); + struct comp_buffer *sink1 = buffer_new(&test_buf_desc, false); + struct comp_buffer *sink2 = buffer_new(&test_buf_desc, false); struct icomplex32 *out1 = (struct icomplex32 *)sink1->stream.addr; struct icomplex32 *out2 = (struct icomplex32 *)sink2->stream.addr; uint32_t fft_size = 512; @@ -625,8 +625,8 @@ static void test_math_fft_256_16(void **state) struct sof_ipc_buffer test_buf_desc = { .size = 256 * 2 * sizeof(int16_t), }; - struct comp_buffer *source = buffer_new(&test_buf_desc); - struct comp_buffer *sink = buffer_new(&test_buf_desc); + struct comp_buffer *source = buffer_new(&test_buf_desc, false); + struct comp_buffer *sink = buffer_new(&test_buf_desc, false); struct icomplex16 *out = (struct icomplex16 *)sink->stream.addr; int16_t *in = (int16_t *)source->stream.addr; int fft_size = 256; @@ -667,8 +667,8 @@ static void test_math_fft_512_16(void **state) struct sof_ipc_buffer test_buf_desc = { .size = 512 * 2 * sizeof(int16_t), }; - struct comp_buffer *source = buffer_new(&test_buf_desc); - struct comp_buffer *sink = buffer_new(&test_buf_desc); + struct comp_buffer *source = buffer_new(&test_buf_desc, false); + struct comp_buffer *sink = buffer_new(&test_buf_desc, false); struct icomplex16 *out = (struct icomplex16 *)sink->stream.addr; int16_t *in = (int16_t *)source->stream.addr; int fft_size = 512; @@ -709,8 +709,8 @@ static void test_math_fft_1024_16(void **state) struct sof_ipc_buffer test_buf_desc = { .size = 1024 * 2 * sizeof(int16_t), }; - struct comp_buffer *source = buffer_new(&test_buf_desc); - struct comp_buffer *sink = buffer_new(&test_buf_desc); + struct comp_buffer *source = buffer_new(&test_buf_desc, false); + struct comp_buffer *sink = buffer_new(&test_buf_desc, false); struct icomplex16 *out = (struct icomplex16 *)sink->stream.addr; int16_t *in = (int16_t *)source->stream.addr; int fft_size = 1024; @@ -751,9 +751,9 @@ static void test_math_fft_1024_ifft_16(void **state) struct sof_ipc_buffer test_buf_desc = { .size = 1024 * 2 * sizeof(int16_t), }; - struct comp_buffer *source = buffer_new(&test_buf_desc); - struct comp_buffer *intm = buffer_new(&test_buf_desc); - struct comp_buffer *sink = buffer_new(&test_buf_desc); + struct comp_buffer *source = buffer_new(&test_buf_desc, false); + struct comp_buffer *intm = buffer_new(&test_buf_desc, false); + struct comp_buffer *sink = buffer_new(&test_buf_desc, false); struct icomplex16 *out = (struct icomplex16 *)sink->stream.addr; float db; int64_t signal = 0; diff --git a/test/cmocka/src/util.h b/test/cmocka/src/util.h index be540359395c..5ef231ceba64 100644 --- a/test/cmocka/src/util.h +++ b/test/cmocka/src/util.h @@ -23,7 +23,7 @@ static inline struct comp_buffer *create_test_sink(struct comp_dev *dev, }, .size = buffer_size, }; - struct comp_buffer *buffer = buffer_new(&desc); + struct comp_buffer *buffer = buffer_new(&desc, false); memset(buffer->stream.addr, 0, buffer_size); @@ -58,7 +58,7 @@ static inline struct comp_buffer *create_test_source(struct comp_dev *dev, }, .size = buffer_size, }; - struct comp_buffer *buffer = buffer_new(&desc); + struct comp_buffer *buffer = buffer_new(&desc, false); memset(buffer->stream.addr, 0, buffer_size); diff --git a/tools/logger/CMakeLists.txt b/tools/logger/CMakeLists.txt index 0c7b2d8d914b..271f54e559c9 100644 --- a/tools/logger/CMakeLists.txt +++ b/tools/logger/CMakeLists.txt @@ -35,7 +35,7 @@ target_compile_options(sof-logger PRIVATE target_include_directories(sof-logger PRIVATE "${SOF_ROOT_SOURCE_DIRECTORY}/src/include" - "${SOF_ROOT_SOURCE_DIRECTORY}/rimage/src/include" + "${SOF_ROOT_SOURCE_DIRECTORY}/tools/rimage/src/include" "${SOF_ROOT_SOURCE_DIRECTORY}" ) diff --git a/tools/logger/convert.c b/tools/logger/convert.c index 417d3ee6e8b4..e393f828e1b1 100644 --- a/tools/logger/convert.c +++ b/tools/logger/convert.c @@ -60,8 +60,7 @@ struct proc_ldc_entry { uintptr_t params[TRACE_MAX_PARAMS_COUNT]; }; -static const char *BAD_PTR_STR = ""; - +#define BAD_PTR_STR "" #define UUID_LOWER "%s%s%s<%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x>%s%s%s" #define UUID_UPPER "%s%s%s<%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X>%s%s%s" @@ -325,7 +324,7 @@ static unsigned int timestamp_width(unsigned int precision) * gcc 9.3, this avoids a very long precision causing snprintf() * to truncate time_fmt */ - assert(precision >= 0 && precision < 20); + assert(precision < 20); /* * 12 digits for units is enough for 1M seconds = 11 days which * should be enough for most test runs. @@ -339,7 +338,6 @@ static inline void print_table_header(void) { FILE *out_fd = global_config->out_fd; int hide_location = global_config->hide_location; - char time_fmt[32]; char date_string[64]; const time_t epoc_secs = time(NULL); @@ -349,16 +347,14 @@ static inline void print_table_header(void) if (gettime_ret) { log_err("clock_gettime() failed: %s\n", - strerror(gettime_ret)); + strerror(errno)); exit(1); } if (global_config->time_precision >= 0) { - const unsigned int ts_width = - timestamp_width(global_config->time_precision); - snprintf(time_fmt, sizeof(time_fmt), "%%-%ds(us)%%%ds ", - ts_width, ts_width); - fprintf(out_fd, time_fmt, " TIMESTAMP", "DELTA"); + const unsigned int ts_width = timestamp_width(global_config->time_precision); + + fprintf(out_fd, "%*s(us)%*s ", -ts_width, " TIMESTAMP", ts_width, "DELTA"); } fprintf(out_fd, "%2s %-18s ", "C#", "COMPONENT"); @@ -476,7 +472,6 @@ static void print_entry_params(const struct log_entry_header *dma_log, char ids[TRACE_MAX_IDS_STR]; float dt = to_usecs(dma_log->timestamp - last_timestamp); struct proc_ldc_entry proc_entry; - static char time_fmt[64]; int ret; if (raw_output) @@ -517,13 +512,7 @@ static void print_entry_params(const struct log_entry_header *dma_log, ids[0] = '\0'; if (raw_output) { /* "raw" means script-friendly (not all hex) */ - const char *entry_fmt = "%s%u %u %s%s%s "; - - if (time_precision >= 0) - snprintf(time_fmt, sizeof(time_fmt), "%%.%df %%.%df ", - time_precision, time_precision); - - fprintf(out_fd, entry_fmt, + fprintf(out_fd, "%s%u %u %s%s%s ", entry->header.level == use_colors ? (LOG_LEVEL_CRITICAL ? KRED : KNRM) : "", dma_log->core_id, @@ -531,9 +520,12 @@ static void print_entry_params(const struct log_entry_header *dma_log, get_component_name(entry->header.component_class, dma_log->uid), raw_output && strlen(ids) ? "-" : "", ids); + if (time_precision >= 0) - fprintf(out_fd, time_fmt, - to_usecs(dma_log->timestamp - timestamp_origin), dt); + fprintf(out_fd, "%.*f %.*f ", + time_precision, to_usecs(dma_log->timestamp - timestamp_origin), + time_precision, dt); + if (!hide_location) fprintf(out_fd, "(%s:%u) ", format_file_name(entry->file_name, raw_output), @@ -542,13 +534,11 @@ static void print_entry_params(const struct log_entry_header *dma_log, if (time_precision >= 0) { const unsigned int ts_width = timestamp_width(time_precision); - snprintf(time_fmt, sizeof(time_fmt), - "%%s[%%%d.%df] (%%%d.%df)%%s ", - ts_width, time_precision, ts_width, time_precision); - - fprintf(out_fd, time_fmt, + fprintf(out_fd, "%s[%*.*f] (%*.*f)%s ", use_colors ? KGRN : "", - to_usecs(dma_log->timestamp - timestamp_origin), dt, + ts_width, time_precision, + to_usecs(dma_log->timestamp - timestamp_origin), + ts_width, time_precision, dt, use_colors ? KNRM : ""); } @@ -624,7 +614,13 @@ static int read_entry_from_ldc_file(struct ldc_entry *entry, uint32_t log_entry_ entry->params = NULL; /* set file position to beginning of processed entry */ - fseek(global_config->ldc_fd, entry_offset, SEEK_SET); + ret = fseek(global_config->ldc_fd, entry_offset, SEEK_SET); + if (ret) { + log_err("Failed to seek to entry header for offset 0x%x in dictionary.\n", + entry_offset); + ret = -errno; + goto out; + } /* fetching elf header params */ ret = fread(&entry->header, sizeof(entry->header), 1, global_config->ldc_fd); @@ -640,7 +636,7 @@ static int read_entry_from_ldc_file(struct ldc_entry *entry, uint32_t log_entry_ ret = -EINVAL; goto out; } - entry->file_name = (char *)malloc(entry->header.file_name_len); + entry->file_name = (char *)malloc(entry->header.file_name_len + 1); if (!entry->file_name) { log_err("can't allocate %d byte for entry.file_name\n", @@ -651,6 +647,8 @@ static int read_entry_from_ldc_file(struct ldc_entry *entry, uint32_t log_entry_ ret = fread(entry->file_name, sizeof(char), entry->header.file_name_len, global_config->ldc_fd); + entry->file_name[entry->header.file_name_len] = '\0'; + if (ret != entry->header.file_name_len) { log_err("Failed to read source filename for offset 0x%x in dictionary.\n", entry_offset); @@ -664,7 +662,7 @@ static int read_entry_from_ldc_file(struct ldc_entry *entry, uint32_t log_entry_ ret = -EINVAL; goto out; } - entry->text = (char *)malloc(entry->header.text_len); + entry->text = (char *)malloc(entry->header.text_len + 1); if (!entry->text) { log_err("can't allocate %d byte for entry.text\n", entry->header.text_len); ret = -ENOMEM; @@ -677,6 +675,7 @@ static int read_entry_from_ldc_file(struct ldc_entry *entry, uint32_t log_entry_ ret = -1; goto out; } + entry->text[entry->header.text_len] = '\0'; return 0; @@ -915,8 +914,13 @@ static int logger_read(void) /* When the address is not correct, move forward by one DWORD (not * entire struct dma_log) */ - fseek(global_config->in_fd, -(sizeof(dma_log) - sizeof(uint32_t)), - SEEK_CUR); + ret = fseek(global_config->in_fd, -(sizeof(dma_log) - sizeof(uint32_t)), + SEEK_CUR); + if (ret) { + log_err("fetch_entry() failed on seek, aborting\n"); + ret = -errno; + break; + } skipped_dwords++; continue; @@ -1013,7 +1017,7 @@ static int dump_ldc_info(void) if (global_config->version_fd) { struct sof_ipc_fw_version ver; - if (fread(&ver, sizeof(ver), 1, global_config->version_fd)) + if (fread(&ver, sizeof(ver), 1, global_config->version_fd) == 1) fprintf(out_fd, "Loaded FW expects checksum\t0x%08x\n", ver.src_hash); } @@ -1101,7 +1105,12 @@ int convert(void) } /* read uuid section header */ - fseek(config->ldc_fd, logs_hdr->data_offset + logs_hdr->data_length, SEEK_SET); + ret = fseek(config->ldc_fd, logs_hdr->data_offset + logs_hdr->data_length, SEEK_SET); + if (ret) { + log_err("Error while seeking to uuids header from %s.\n", config->ldc_file); + return -errno; + } + count = fread(&uids_hdr, sizeof(uids_hdr), 1, config->ldc_fd); if (!count) { log_err("Error while reading uuids header from %s.\n", config->ldc_file); diff --git a/tools/logger/logger.c b/tools/logger/logger.c index 14f3fc88f657..b6c2b26bd629 100644 --- a/tools/logger/logger.c +++ b/tools/logger/logger.c @@ -104,8 +104,8 @@ static int snapshot(const char *name) for (i = 0; i < ARRAY_SIZE(debugfs); i++) { - sprintf(pinname, "%s/%s", path, debugfs[i]); - sprintf(poutname, "%s.%s.txt", name, debugfs[i]); + snprintf(pinname, sizeof(pinname), "%s/%s", path, debugfs[i]); + snprintf(poutname, sizeof(poutname), "%s.%s.txt", name, debugfs[i]); /* open debugfs for reading */ in_fd = fopen(pinname, "rb"); @@ -132,9 +132,14 @@ static int snapshot(const char *name) if (count != 4) break; - sprintf(buffer, "0x%6.6x: 0x%8.8x\n", addr, val); + snprintf(buffer, sizeof(buffer), "0x%6.6x: 0x%8.8x\n", addr, val); - count = fwrite(buffer, 1, strlen(buffer), out_fd); + i = strlen(buffer); + count = fwrite(buffer, 1, i, out_fd); + if (count != i) { + fprintf(stderr, "error: an error occurred during write to %s: %s\n", + poutname, strerror(errno)); + } addr += 4; } @@ -164,7 +169,12 @@ static int configure_uart(const char *file, unsigned int baud) tio.c_cc[VMIN] = 1; ret = tcsetattr(fd, TCSANOW, &tio); - return ret < 0 ? -errno : fd; + if (ret < 0) { + close(fd); + return -errno; + } + + return fd; } /* Concantenate `config->filter_config` with `input` + `\n` */ @@ -220,17 +230,15 @@ static void *wait_open(const char *watched_dir, const char *expected_file) const int dwatch = inotify_add_watch(iqueue, watched_dir, IN_CREATE); struct stat expected_stat; void *ret_stream = NULL; - - char * const fpath = malloc(strlen(watched_dir) + 1 + strlen(expected_file) + 1); + const int fpath_len = strlen(watched_dir) + 1 + strlen(expected_file) + 1; + char * const fpath = malloc(fpath_len); if (!fpath) { fprintf(stderr, "error: can't allocate memory\n"); exit(EXIT_FAILURE); } - strcpy(fpath, watched_dir); - strcat(fpath, "/"); - strcat(fpath, expected_file); + snprintf(fpath, fpath_len, "%s/%s", watched_dir, expected_file); /* Not racy because the inotify watch was set first. */ if (!access(fpath, F_OK)) @@ -268,7 +276,9 @@ static void *wait_open(const char *watched_dir, const char *expected_file) } fopenit: - stat(fpath, &expected_stat); + if (stat(fpath, &expected_stat)) + goto cleanup; + if ((expected_stat.st_mode & S_IFMT) == S_IFDIR) ret_stream = opendir(fpath); else @@ -364,7 +374,8 @@ int main(int argc, char *argv[]) if (i < 0 || 1 < i) { fprintf(stderr, "%s: invalid option: -e %s\n", APP_NAME, optarg); - return -EINVAL; + ret = -EINVAL; + goto out; } config.relative_timestamps = i; break; @@ -373,7 +384,8 @@ int main(int argc, char *argv[]) config.time_precision = atoi(optarg); if (config.time_precision < 0) { usage(); - return -EINVAL; + ret = -EINVAL; + goto out; } break; case 'g': @@ -403,8 +415,10 @@ int main(int argc, char *argv[]) usage(); } - if (snapshot_file) - return baud ? EINVAL : -snapshot(snapshot_file); + if (snapshot_file) { + ret = baud ? EINVAL : -snapshot(snapshot_file); + goto out; + } if (!config.ldc_file) { fprintf(stderr, "error: Missing ldc file\n"); diff --git a/tools/plugin/CMakeLists.txt b/tools/plugin/CMakeLists.txt new file mode 100644 index 000000000000..f5a8ade5f8cc --- /dev/null +++ b/tools/plugin/CMakeLists.txt @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.13) + +project(SOF_PLUGIN C) + +include(../../scripts/cmake/misc.cmake) +include(CheckCCompilerFlag) + +set(sof_source_directory "${PROJECT_SOURCE_DIR}/../..") +set(sof_install_directory "${PROJECT_BINARY_DIR}/sof_ep/install") +set(sof_binary_directory "${PROJECT_BINARY_DIR}/sof_ep/build") + +set(config_h ${sof_binary_directory}/library_autoconfig.h) + +set(parser_source_directory "${PROJECT_SOURCE_DIR}/../tplg_parser") +set(parser_install_dir "${PROJECT_BINARY_DIR}/sof_parser/install") + +message("ipc4 build") +set(tplg_ipc plugin_ipc4_defconfig) + +include(ExternalProject) + +# External project for SOF library +ExternalProject_Add(sof_ep + DOWNLOAD_COMMAND "" + SOURCE_DIR "${sof_source_directory}" + PREFIX "${PROJECT_BINARY_DIR}/sof_ep" + BINARY_DIR "${sof_binary_directory}" + CMAKE_ARGS -DCONFIG_LIBRARY=ON + -DCMAKE_INSTALL_PREFIX=${sof_install_directory} + -DCMAKE_VERBOSE_MAKEFILE=${CMAKE_VERBOSE_MAKEFILE} + -DINIT_CONFIG=${tplg_ipc} + -DCONFIG_H_PATH=${config_h} + -DCONFIG_LIBRARY_STATIC=ON + -DOPTIMIZE_FOR_DEBUG=ON + BUILD_ALWAYS 1 + BUILD_BYPRODUCTS "${sof_install_directory}/lib/libsof.a" +) + +add_library(sof_library STATIC IMPORTED) +set_target_properties(sof_library PROPERTIES IMPORTED_LOCATION "${sof_install_directory}/lib/libsof.a") +add_dependencies(sof_library sof_ep) + +# External project for topology parser +ExternalProject_Add(parser_ep + SOURCE_DIR "${parser_source_directory}" + PREFIX "${PROJECT_BINARY_DIR}/sof_parser" + BINARY_DIR "${PROJECT_BINARY_DIR}/sof_parser/build" + CMAKE_ARGS -DCONFIG_LIBRARY=ON + -DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}/sof_parser/install + -DCMAKE_VERBOSE_MAKEFILE=${CMAKE_VERBOSE_MAKEFILE} + -DCONFIG_LIBRARY_STATIC=ON + -DOPTIMIZE_FOR_DEBUG=ON + BUILD_ALWAYS 1 + BUILD_BYPRODUCTS "${parser_install_dir}/lib/libsof_tplg_parser.a" +) + +add_library(sof_parser_lib STATIC IMPORTED) +set_target_properties(sof_parser_lib PROPERTIES IMPORTED_LOCATION "${parser_install_dir}/lib/libsof_tplg_parser.a") +add_dependencies(sof_parser_lib parser_ep) + +add_subdirectory(alsaconf) +add_subdirectory(alsaplug) +add_subdirectory(modules) +add_subdirectory(pipe) + +add_dependencies(asound_module_pcm_sof sof_parser_lib) +add_dependencies(asound_module_ctl_sof sof_parser_lib) + +add_dependencies(sof-pipe sof_mod_shm) +add_dependencies(sof-pipe sof_mod_alsa) diff --git a/tools/plugin/README.md b/tools/plugin/README.md new file mode 100644 index 000000000000..0d4822388e70 --- /dev/null +++ b/tools/plugin/README.md @@ -0,0 +1,83 @@ +##ALSA Plugin + +The SOF ALSA plugin allows SOF topologies to be run on the host. The plugin +is still WIP with many rough edges that need refined before production +deployment, however the plugin is usable today as a rapid development +framework for SOF infrastructure and processing. + +#Features + * aplay & arecord usage working today + * alsamixer & amixer usage not working today + * modules are loaded as SO shared libraries. + * topology is parsed by the plugin and pipelines associated with the requested PCM ID are loaded + * pipelines run as individual userspace threads + * pipelines can be pinned to efficency cores + * pipelines can use realtime priority. + * alsa sink and alsa source modules available. + * pipelines can block (non blocking and mmap todo) + +#License +Code is a mixture of LGPL and BSD 3c. + +#Usage +Please build as cmake project, for IPC4 (functional) +IPC3 is not functional and not supported + +``` +cd sof +mkdir build_plugin +cd build_plugin +cmake ../tools/plugin -DPLUGIN_IPC4=ON +``` +then (use default ALSA prefix atm) + +``` +sudo make install + +Make sure to set the LD_LIBRARY_PATH to include directory where the SOF modules are installed +Ex: "~/work/sof/sof/build_plugin/sof_ep/install/lib:~/work/sof/sof/build_plugin/modules/" +And set the environment variable SOF_PLUGIN_TOPOLOGY_PATH to point to the directory containing the topology binary +``` + +Code can then be run by starting sof-pipe with your desired topology + +``` + ./sof-pipe -T sof-tgl-nocodec.tplg +``` + +At this point the sof-pipe daemon is waiting for IPC. Audio applications can now invoke sof-pipe processing via + +``` +aplay -Dsof:tgl-nocodec:1:default:default:48k2c16b -f dat some48kHz.wav +``` +The command line is parsed as follows: +- "sof" is the plugin name +- "tgl-nocodec" is the topology name. The "sof-" prefix and ".tplg" suffix will be appended by the plugin +- "1" is the PCM ID for render/capture +- "default": The first default is the card name +- "default": The second default is the device name +- "48k2c16b" is the config name for 48K, stereo, 16bit + +This renders audio to the sof-pipe daemon using the tgl-nocodec topology playback PCM ID 1. +The above example needs to be 48k as example pipe has no SRC/ASRC. + +Likewise + +``` +arecord -Dsof:tgl-nocodec:1:default:default:48k2c16b -f dat file.wav +``` +Will record audio using the tgl-nocodec topology and PCM ID 1. + +Mixer settings can be adjusted for bdw-nocodec by (Not functional yet) + +``` +alsamixer -Dsof:tgl-nocodec:1 +``` + +#TODO Items (and T-shirt size) for single pipeline E2E audio + * IPC4 support in tplg parser (M) + * IPC4 support in plugin (pipe/ipc4.c) (M) + * Fix ALSA -Dhw: device support (S), currently only default ALSA device works + * Deprecate POSIX message queues for IPC and use UNIX sockets.(S) + * Make better build system for modules i.e. remove hack-install.sh (S) + * Need a simpler aplay/arecord cmd line. diff --git a/tools/plugin/alsaconf/50-sof.conf b/tools/plugin/alsaconf/50-sof.conf new file mode 100644 index 000000000000..4d0232ecc596 --- /dev/null +++ b/tools/plugin/alsaconf/50-sof.conf @@ -0,0 +1,84 @@ +# Invoke a SOF pipeline and route it to a sound card or another plugin +# To use the PCM 0 on the SOF "volume" topology and route it to hw:1,2 then run +# aplay -Dsof:volume:0,hw,1,2 +# tplg:pipe:[pipe:card:dev:config[pipe:card:dev:config]...] +# +# TPLG SOF topology configuration (mandatory) + +pcm.sof { + @args [ TPLG ] + @args.TPLG { + type string + default "passthrough" + } + + type sof + tplg $TPLG + + hint { + show { + @func refer + name defaults.namehint.basic + } + description "SOF Topology and PCM" + } + + config.48k2c16b { + rate 48000 + channels 2 + format S16_LE + period_time 0 + period_frames 48 + buffer_time 0 + buffer_frames 192 + } + + config.48k8c16b { + rate 48000 + channels 8 + format S16_LE + period_time 0 + period_frames 1024 + buffer_time 0 + buffer_frames 5120 + } + + config.8k8c16b { + rate 8000 + channels 8 + format S16_LE + period_time 0 + period_frames 1024 + buffer_time 0 + buffer_frames 5120 + } + + config.48k2c32b { + rate 48000 + channels 2 + format S32_LE + period_time 0 + period_frames 6000 + buffer_time 0 + buffer_frames 24000 + } +} + +ctl.sof { + @args [ TPLG ] + @args.TPLG { + type string + default "passthrough" + } + + type sof + tplg $TPLG + + hint { + show { + @func refer + name defaults.namehint.basic + } + description "SOF Topology" + } +} diff --git a/tools/plugin/alsaconf/CMakeLists.txt b/tools/plugin/alsaconf/CMakeLists.txt new file mode 100644 index 000000000000..3a58c514f522 --- /dev/null +++ b/tools/plugin/alsaconf/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: BSD-3-Clause + +install(FILES 50-sof.conf DESTINATION /usr/share/alsa/alsa.conf.d) +# HACK needs to link to above +install(FILES 50-sof.conf DESTINATION /etc/alsa/conf.d) diff --git a/tools/plugin/alsaplug/CMakeLists.txt b/tools/plugin/alsaplug/CMakeLists.txt new file mode 100644 index 000000000000..c982d90d6106 --- /dev/null +++ b/tools/plugin/alsaplug/CMakeLists.txt @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: BSD-3-Clause + +# PCM ALSA module +add_library(asound_module_pcm_sof MODULE + pcm.c + plugin.c + ../common.c + tplg.c +) + +sof_append_relative_path_definitions(asound_module_pcm_sof) + +target_include_directories(asound_module_pcm_sof PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${sof_source_directory}/src/audio) + +target_compile_options(asound_module_pcm_sof PRIVATE -DPIC -g -O3 -Wl,-EL -Wmissing-prototypes + -Wimplicit-fallthrough -DCONFIG_LIBRARY -imacros${config_h}) + +install(TARGETS asound_module_pcm_sof DESTINATION /usr/lib/x86_64-linux-gnu/alsa-lib) + +target_link_options(asound_module_pcm_sof PRIVATE -Wl,--export-dynamic,--no-undefined) +target_link_libraries(asound_module_pcm_sof PRIVATE sof_library) +target_link_libraries(asound_module_pcm_sof PRIVATE sof_parser_lib) +target_link_libraries(asound_module_pcm_sof PRIVATE pthread) +target_link_libraries(asound_module_pcm_sof PRIVATE -lasound -ldl -lm -lasound -lrt) + +target_include_directories(asound_module_pcm_sof PRIVATE ${sof_install_directory}/include) +target_include_directories(asound_module_pcm_sof PRIVATE ${parser_install_dir}/include) + +set_target_properties(asound_module_pcm_sof + PROPERTIES + INSTALL_RPATH "${sof_install_directory}/alsa-lib" + INSTALL_RPATH_USE_LINK_PATH TRUE +) + +# CTL ALSA module +add_library(asound_module_ctl_sof MODULE + ctl.c + plugin.c + ../common.c +) +sof_append_relative_path_definitions(asound_module_ctl_sof) +target_include_directories(asound_module_ctl_sof PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${sof_source_directory}/src/audio) + +target_compile_options(asound_module_ctl_sof PRIVATE -DPIC -g -O3 -Wl,-EL -Wmissing-prototypes + -Wimplicit-fallthrough -Wall -Werror -DCONFIG_LIBRARY -imacros${config_h}) + +install(TARGETS asound_module_ctl_sof DESTINATION /usr/lib/x86_64-linux-gnu/alsa-lib) + +target_link_options(asound_module_ctl_sof PRIVATE -Wl,--export-dynamic,--no-undefined) +target_link_libraries(asound_module_ctl_sof PRIVATE sof_library) +target_link_libraries(asound_module_ctl_sof PRIVATE sof_parser_lib) +target_link_libraries(asound_module_ctl_sof PRIVATE pthread) +target_link_libraries(asound_module_ctl_sof PRIVATE -lasound -ldl -lm -lasound -lrt) + +target_include_directories(asound_module_ctl_sof PRIVATE ${sof_install_directory}/include) +target_include_directories(asound_module_ctl_sof PRIVATE ${parser_install_dir}/include) + +set_target_properties(asound_module_ctl_sof + PROPERTIES + INSTALL_RPATH "${sof_install_directory}/alsa-lib" + INSTALL_RPATH_USE_LINK_PATH TRUE +) diff --git a/tools/plugin/alsaplug/conf.c b/tools/plugin/alsaplug/conf.c new file mode 100644 index 000000000000..5b259bf6885a --- /dev/null +++ b/tools/plugin/alsaplug/conf.c @@ -0,0 +1,47 @@ +/*-*- linux-c -*-*/ + +/* + * ALSA <-> SOF Config plugin + * + * Copyright(c) 2022 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + */ + +#include +#include +#include "plugin.h" + +/* Not actually part of the alsa api.... */ +extern int +snd_config_hook_load(snd_config_t *root, snd_config_t *config, + snd_config_t **dst, snd_config_t *private_data); + +/* manifest file could be loaded as a hook */ +int sofplug_load_hook(snd_config_t *root, snd_config_t *config, + snd_config_t **dst, snd_config_t *private_data) +{ + int ret = 0; + + *dst = NULL; + + /* TODO: load hook when SOF ready */ + return snd_config_hook_load(root, config, dst, private_data); +} + +SND_DLSYM_BUILD_VERSION(sofplug_load_hook, + SND_CONFIG_DLSYM_VERSION_HOOK); diff --git a/tools/plugin/alsaplug/ctl.c b/tools/plugin/alsaplug/ctl.c new file mode 100644 index 000000000000..7e4f34e4cbda --- /dev/null +++ b/tools/plugin/alsaplug/ctl.c @@ -0,0 +1,685 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// TODO remove parsing and read ctls from sof-pipe SHM glb context +#include + +#include +#include + +#include "plugin.h" +#include "common.h" + +typedef struct snd_sof_ctl { + struct plug_shm_glb_state *glb; + snd_ctl_ext_t ext; + struct plug_mq_desc ipc; + struct plug_shm_desc shm_ctx; + int subscribed; + int updated[MAX_CTLS]; + +} snd_sof_ctl_t; + +#define CTL_GET_TPLG_HDR(_ctl, _key) \ + (&_ctl->glb->ctl[_key].mixer_ctl.hdr) + +#define CTL_GET_TPLG_MIXER(_ctl, _key) \ + (&_ctl->glb->ctl[_key].mixer_ctl) + +#define CTL_GET_TPLG_ENUM(_ctl, _key) \ + (&_ctl->glb->ctl[_key].enum_ctl) + +#define CTL_GET_TPLG_BYTES(_ctl, _key) \ + (&_ctl->glb->ctl[_key].bytes_ctl) + +/* number of ctls */ +static int plug_ctl_elem_count(snd_ctl_ext_t *ext) +{ + snd_sof_ctl_t *ctl = ext->private_data; + + /* TODO: get count of elems from topology */ + return ctl->glb->num_ctls; +} + +static int plug_ctl_elem_list(snd_ctl_ext_t *ext, unsigned int offset, snd_ctl_elem_id_t *id) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_ctl_hdr *hdr; + + if (offset >= ctl->glb->num_ctls) + return -EINVAL; + + hdr = CTL_GET_TPLG_HDR(ctl, offset); + + snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); + snd_ctl_elem_id_set_name(id, hdr->name); + + return 0; +} + +static snd_ctl_ext_key_t plug_ctl_find_elem(snd_ctl_ext_t *ext, const snd_ctl_elem_id_t *id) +{ + snd_sof_ctl_t *ctl = ext->private_data; + unsigned int numid; + + numid = snd_ctl_elem_id_get_numid(id); + + if (numid > ctl->glb->num_ctls) + return SND_CTL_EXT_KEY_NOT_FOUND; + + return numid - 1; +} + +static int plug_ctl_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + int *type, unsigned int *acc, unsigned int *count) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_ctl_hdr *hdr = CTL_GET_TPLG_HDR(ctl, key); + struct snd_soc_tplg_mixer_control *mixer_ctl; + struct snd_soc_tplg_enum_control *enum_ctl; + struct snd_soc_tplg_bytes_control *bytes_ctl; + int err = 0; + + switch (hdr->type) { + case SND_SOC_TPLG_CTL_VOLSW: + case SND_SOC_TPLG_CTL_VOLSW_SX: + case SND_SOC_TPLG_CTL_VOLSW_XR_SX: + mixer_ctl = (struct snd_soc_tplg_mixer_control *)hdr; + + /* check for type - boolean should be binary values */ + if (mixer_ctl->max == 1 && mixer_ctl->min == 0) + *type = SND_CTL_ELEM_TYPE_BOOLEAN; + else + *type = SND_CTL_ELEM_TYPE_INTEGER; + *count = 2;//mixer_ctl->num_channels; ///// WRONG is 0 !!! + + //printf("mixer %d %d\n", __LINE__, mixer_ctl->num_channels); + break; + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_CTL_ENUM_VALUE: + enum_ctl = (struct snd_soc_tplg_enum_control *)hdr; + *type = SND_CTL_ELEM_TYPE_ENUMERATED; + *count = enum_ctl->num_channels; + break; + case SND_SOC_TPLG_CTL_RANGE: + case SND_SOC_TPLG_CTL_STROBE: + // TODO: ?? + break; + case SND_SOC_TPLG_CTL_BYTES: + printf("%s %d\n", __func__, __LINE__); + bytes_ctl = (struct snd_soc_tplg_bytes_control *)hdr; + *type = SND_CTL_ELEM_TYPE_BYTES; + *count = bytes_ctl->size; // Not sure if size is correct + break; + } + + *acc = hdr->access; + + /* access needs the callback to decode the data */ + if ((hdr->access & SND_CTL_EXT_ACCESS_TLV_READ) || + (hdr->access & SND_CTL_EXT_ACCESS_TLV_WRITE)) + *acc |= SND_CTL_EXT_ACCESS_TLV_CALLBACK; + return err; +} + +/* + * Integer ops + */ +static int plug_ctl_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *imin, + long *imax, long *istep) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_ctl_hdr *hdr = CTL_GET_TPLG_HDR(ctl, key); + struct snd_soc_tplg_mixer_control *mixer_ctl = + CTL_GET_TPLG_MIXER(ctl, key); + int err = 0; + + switch (hdr->type) { + case SND_SOC_TPLG_CTL_VOLSW: + case SND_SOC_TPLG_CTL_VOLSW_SX: + case SND_SOC_TPLG_CTL_VOLSW_XR_SX: + /* TLV uses the fields differently */ + if ((hdr->access & SND_CTL_EXT_ACCESS_TLV_READ) || + (hdr->access & SND_CTL_EXT_ACCESS_TLV_WRITE)) { + *istep = mixer_ctl->hdr.tlv.scale.step; + *imin = (int32_t)mixer_ctl->hdr.tlv.scale.min; + *imax = mixer_ctl->max; + } else { + *istep = 1; + *imin = mixer_ctl->min; + *imax = mixer_ctl->max; + } + break; + default: + SNDERR("invalid ctl type for integer using key %d", key); + err = -EINVAL; + break; + } + + return err; +} + +static int plug_ctl_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_mixer_control *mixer_ctl = + CTL_GET_TPLG_MIXER(ctl, key); + struct sof_ipc_ctrl_data *ctl_data; + struct sof_ipc_ctrl_value_chan *chanv; + int err, i; + + // TODO: set generic max size + ctl_data = calloc(IPC3_MAX_MSG_SIZE, 1); + if (!ctl_data) + return -ENOMEM; + chanv = ctl_data->chanv; + + /* setup the IPC message */ + ctl_data->comp_id = ctl->glb->ctl[key].comp_id; + ctl_data->cmd = SOF_CTRL_CMD_VOLUME; + ctl_data->type = SOF_CTRL_TYPE_VALUE_COMP_GET; + ctl_data->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | SOF_IPC_COMP_GET_VALUE; + ctl_data->rhdr.hdr.size = sizeof(ctl_data); + ctl_data->num_elems = mixer_ctl->num_channels; + + /* send message and wait for reply */ + err = plug_mq_cmd(&ctl->ipc, ctl_data, IPC3_MAX_MSG_SIZE, ctl_data, IPC3_MAX_MSG_SIZE); + if (err < 0) { + SNDERR("error: can't read CTL %d message\n", + ctl_data->comp_id); + return err; + } + + /* did IPC succeed ? */ + if (ctl_data->rhdr.error != 0) { + SNDERR("error: can't read CTL %d failed: error %d\n", + ctl_data->comp_id, ctl_data->rhdr.error); + return ctl_data->rhdr.error; + } + + /* get data from IPC */ + for (i = 0; i < mixer_ctl->num_channels; i++) + value[i] = chanv[i].value; + + free(ctl_data); + + return err; +} + +static int plug_ctl_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_mixer_control *mixer_ctl = + CTL_GET_TPLG_MIXER(ctl, key); + struct sof_ipc_ctrl_data *ctl_data; + struct sof_ipc_ctrl_value_chan *chanv; + int err; + int i; + + // TODO: set generic max size + ctl_data = calloc(IPC3_MAX_MSG_SIZE, 1); + if (!ctl_data) + return -ENOMEM; + chanv = ctl_data->chanv; + + /* setup the IPC message */ + ctl_data->comp_id = ctl->glb->ctl[key].comp_id; + ctl_data->cmd = SOF_CTRL_CMD_VOLUME; + ctl_data->type = SOF_CTRL_TYPE_VALUE_COMP_SET; + ctl_data->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | SOF_IPC_COMP_SET_VALUE; + ctl_data->rhdr.hdr.size = sizeof(ctl_data); + ctl_data->num_elems = mixer_ctl->num_channels; + + /* set data for IPC */ + for (i = 0; i < mixer_ctl->num_channels; i++) + chanv[i].value = value[i]; + + err = plug_mq_cmd(&ctl->ipc, ctl_data, IPC3_MAX_MSG_SIZE, + ctl_data, IPC3_MAX_MSG_SIZE); + if (err < 0) { + SNDERR("error: can't write CTL %d message\n", ctl_data->comp_id); + return err; + } + + /* did IPC succeed ? */ + if (ctl_data->rhdr.error != 0) { + SNDERR("error: can't write CTL %d failed: error %d\n", + ctl_data->comp_id, ctl_data->rhdr.error); + return ctl_data->rhdr.error; + } + + free(ctl_data); + + return err; +} + +/* + * Enum ops + */ +static int plug_ctl_get_enumerated_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + unsigned int *items) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_ctl_hdr *hdr = CTL_GET_TPLG_HDR(ctl, key); + struct snd_soc_tplg_enum_control *enum_ctl = + (struct snd_soc_tplg_enum_control *)hdr; + int err = 0; + + switch (hdr->type) { + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_CTL_ENUM_VALUE: + *items = enum_ctl->items; + break; + default: + SNDERR("invalid ctl type for enum using key %d", key); + err = -EINVAL; + break; + } + + return err; +} + +static int plug_ctl_get_enumerated_name(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + unsigned int item, char *name, size_t name_max_len) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_ctl_hdr *hdr = CTL_GET_TPLG_HDR(ctl, key); + struct snd_soc_tplg_enum_control *enum_ctl = + (struct snd_soc_tplg_enum_control *)hdr; + + printf("%s %d\n", __func__, __LINE__); + + if (item >= enum_ctl->count) { + SNDERR("invalid item %d for enum using key %d", item, key); + return -EINVAL; + } + + strncpy(name, enum_ctl->texts[item], name_max_len); + return 0; +} + +static int plug_ctl_read_enumerated(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + unsigned int *items) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_enum_control *enum_ctl = + CTL_GET_TPLG_ENUM(ctl, key); + struct sof_ipc_ctrl_data *ctl_data; + struct sof_ipc_ctrl_value_comp *compv; + int err, i; + + // TODO: set generic max size + ctl_data = calloc(IPC3_MAX_MSG_SIZE, 1); + if (!ctl_data) + return -ENOMEM; + compv = ctl_data->compv; + + /* setup the IPC message */ + ctl_data->comp_id = ctl->glb->ctl[key].comp_id; + ctl_data->cmd = SOF_CTRL_CMD_ENUM; + ctl_data->type = SOF_CTRL_TYPE_VALUE_COMP_GET; + ctl_data->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | SOF_IPC_COMP_GET_VALUE; + ctl_data->rhdr.hdr.size = sizeof(ctl_data); + + /* send message and wait for reply */ + err = plug_mq_cmd(&ctl->ipc, ctl_data, IPC3_MAX_MSG_SIZE, + ctl_data, IPC3_MAX_MSG_SIZE); + if (err < 0) { + SNDERR("error: can't read CTL %d message\n", ctl_data->comp_id); + return err; + } + + /* did IPC succeed ? */ + if (ctl_data->rhdr.error != 0) { + SNDERR("error: can't read CTL %d failed: error %d\n", + ctl_data->comp_id, ctl_data->rhdr.error); + return ctl_data->rhdr.error; + } + + /* get data from IPC */ + for (i = 0; i < enum_ctl->num_channels; i++) + items[i] = compv[i].uvalue; + + free(ctl_data); + + return err; +} + +static int plug_ctl_write_enumerated(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + unsigned int *items) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_enum_control *enum_ctl = + CTL_GET_TPLG_ENUM(ctl, key); + struct sof_ipc_ctrl_data *ctl_data; + struct sof_ipc_ctrl_value_comp *compv; + int err, i; + + // TODO: set generic max size + ctl_data = calloc(IPC3_MAX_MSG_SIZE, 1); + if (!ctl_data) + return -ENOMEM; + compv = ctl_data->compv; + + printf("%s %d\n", __func__, __LINE__); + + /* setup the IPC message */ + ctl_data->comp_id = ctl->glb->ctl[key].comp_id; + ctl_data->cmd = SOF_CTRL_CMD_ENUM; + ctl_data->type = SOF_CTRL_TYPE_VALUE_COMP_SET; + ctl_data->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | SOF_IPC_COMP_SET_VALUE; + ctl_data->rhdr.hdr.size = sizeof(ctl_data); + + /* set data for IPC */ + for (i = 0; i < enum_ctl->num_channels; i++) + compv[i].uvalue = items[i]; + + /* send message and wait for reply */ + err = plug_mq_cmd(&ctl->ipc, ctl_data, IPC3_MAX_MSG_SIZE, + ctl_data, IPC3_MAX_MSG_SIZE); + if (err < 0) { + SNDERR("error: can't read CTL %d message\n", ctl_data->comp_id); + goto out; + } + + /* did IPC succeed ? */ + if (ctl_data->rhdr.error != 0) { + SNDERR("error: can't read CTL %d failed: error %d\n", + ctl_data->comp_id, ctl_data->rhdr.error); + err = ctl_data->rhdr.error; + } + +out: + free(ctl_data); + return err; +} + +/* + * Bytes ops - TODO handle large blobs + */ + +static int plug_ctl_read_bytes(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + unsigned char *data, size_t max_bytes) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_bytes_control *binary_ctl = + CTL_GET_TPLG_BYTES(ctl, key); + struct sof_ipc_ctrl_data *ctl_data; + int err; + + // TODO: set generic max size + ctl_data = calloc(IPC3_MAX_MSG_SIZE, 1); + if (!ctl_data) + return -ENOMEM; + + /* setup the IPC message */ + ctl_data->comp_id = ctl->glb->ctl[key].comp_id; + ctl_data->cmd = SOF_CTRL_CMD_BINARY; + ctl_data->type = SOF_CTRL_TYPE_VALUE_COMP_GET; + ctl_data->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | SOF_IPC_COMP_GET_VALUE; + ctl_data->rhdr.hdr.size = sizeof(ctl_data); + + /* send message and wait for reply */ + err = plug_mq_cmd(&ctl->ipc, ctl_data, IPC3_MAX_MSG_SIZE, + ctl_data, IPC3_MAX_MSG_SIZE); + if (err < 0) { + SNDERR("error: can't read CTL %d message\n", ctl_data->comp_id); + return err; + } + + /* did IPC succeed ? */ + if (ctl_data->rhdr.error != 0) { + SNDERR("error: can't read CTL %d failed: error %d\n", + ctl_data->comp_id, ctl_data->rhdr.error); + return ctl_data->rhdr.error; + } + + /* get data for IPC */ + memcpy(data, &ctl_data->data, MIN(binary_ctl->max, max_bytes)); + free(ctl_data); + + return err; +} + +static int plug_ctl_write_bytes(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + unsigned char *data, size_t max_bytes) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_bytes_control *binary_ctl = + CTL_GET_TPLG_BYTES(ctl, key); + struct sof_ipc_ctrl_data *ctl_data; + int err; + + // TODO: set generic max size + ctl_data = calloc(IPC3_MAX_MSG_SIZE, 1); + if (!ctl_data) + return -ENOMEM; + + printf("%s %d\n", __func__, __LINE__); + + /* setup the IPC message */ + ctl_data->comp_id = ctl->glb->ctl[key].comp_id; + ctl_data->cmd = SOF_CTRL_CMD_BINARY; + ctl_data->type = SOF_CTRL_TYPE_VALUE_COMP_SET; + ctl_data->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | SOF_IPC_COMP_SET_VALUE; + ctl_data->rhdr.hdr.size = sizeof(ctl_data); + + /* set data for IPC */ + memcpy(&ctl_data->data, data, MIN(binary_ctl->max, max_bytes)); + + /* send message and wait for reply */ + err = plug_mq_cmd(&ctl->ipc, ctl_data, IPC3_MAX_MSG_SIZE, + ctl_data, IPC3_MAX_MSG_SIZE); + if (err < 0) { + SNDERR("error: can't read CTL %d message\n", ctl_data->comp_id); + return err; + } + + /* did IPC succeed ? */ + if (ctl_data->rhdr.error != 0) { + SNDERR("error: can't read CTL %d failed: error %d\n", + ctl_data->comp_id, ctl_data->rhdr.error); + return ctl_data->rhdr.error; + } + + free(ctl_data); + + return err; +} + +/* + * TLV ops + * + * The format of an array of \a tlv argument is: + * tlv[0]: Type. One of SND_CTL_TLVT_XXX. + * tlv[1]: Length. The length of value in units of byte. + * tlv[2..]: Value. Depending on the type. + */ +static int plug_tlv_rw(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int op_flag, + unsigned int numid, unsigned int *tlv, unsigned int tlv_size) +{ + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_ctl_hdr *hdr = CTL_GET_TPLG_HDR(ctl, key); + + //TODO: alsamixer showing wrong dB scales + tlv[0] = hdr->tlv.type; + tlv[1] = hdr->tlv.size - sizeof(uint32_t) * 2; + memcpy(&tlv[2], hdr->tlv.data, hdr->tlv.size - sizeof(uint32_t) * 2); + + return 0; +} + +static void plug_ctl_subscribe_events(snd_ctl_ext_t *ext, int subscribe) +{ + snd_sof_ctl_t *ctl = ext->private_data; + + ctl->subscribed = !!(subscribe & SND_CTL_EVENT_MASK_VALUE); +} + +static int plug_ctl_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id, + unsigned int *event_mask) +{ + snd_sof_ctl_t *ctl = ext->private_data; + int numid; + int err = 0; + + numid = snd_ctl_elem_id_get_numid(id); + + // TODO: we need a notify() or listening thread to take async/volatile ctl + // notifications from sof-pipe and notify userspace via events of the ctl change. + if (!ctl->updated[numid - 1] || !ctl->subscribed) { + err = -EAGAIN; + goto out; + } + + *event_mask = SND_CTL_EVENT_MASK_VALUE; +out: + return err; +} + +static int plug_ctl_poll_revents(snd_ctl_ext_t *ext, struct pollfd *pfd, + unsigned int nfds, unsigned short *revents) +{ + snd_sof_ctl_t *ctl = ext->private_data; + int i; + + *revents = 0; + + for (i = 0; i < ctl->glb->num_ctls; i++) { + if (ctl->updated[i]) { + *revents = POLLIN; + break; + } + } + + return 0; +} + +static void plug_ctl_close(snd_ctl_ext_t *ext) +{ + snd_sof_ctl_t *ctl = ext->private_data; + + /* TODO: munmap */ + free(ctl); +} + +static const snd_ctl_ext_callback_t sof_ext_callback = { + .elem_count = plug_ctl_elem_count, + .elem_list = plug_ctl_elem_list, + .find_elem = plug_ctl_find_elem, + .get_attribute = plug_ctl_get_attribute, + .get_integer_info = plug_ctl_get_integer_info, + .read_integer = plug_ctl_read_integer, + .write_integer = plug_ctl_write_integer, + .get_enumerated_info = plug_ctl_get_enumerated_info, + .get_enumerated_name = plug_ctl_get_enumerated_name, + .read_enumerated = plug_ctl_read_enumerated, + .write_enumerated = plug_ctl_write_enumerated, + .read_bytes = plug_ctl_read_bytes, + .write_bytes = plug_ctl_write_bytes, + .subscribe_events = plug_ctl_subscribe_events, + .read_event = plug_ctl_read_event, + .poll_revents = plug_ctl_poll_revents, + .close = plug_ctl_close, +}; + +SND_CTL_PLUGIN_DEFINE_FUNC(sof) +{ + snd_sof_plug_t *plug; + int err; + snd_sof_ctl_t *ctl; + + /* create context */ + plug = calloc(1, sizeof(*plug)); + if (!plug) + return -ENOMEM; + + ctl = calloc(1, sizeof(*ctl)); + if (!ctl) + return -ENOMEM; + plug->module_prv = ctl; + + /* parse the ALSA configuration file for sof plugin */ + err = plug_parse_conf(plug, name, root, conf); + if (err < 0) { + SNDERR("failed to parse config: %s", strerror(err)); + goto error; + } + + /* create message queue for IPC */ + err = plug_mq_init(&ctl->ipc, plug->tplg_file, "ipc", 0); + if (err < 0) + goto error; + + /* open message queue for IPC */ + err = plug_mq_open(&ctl->ipc); + if (err < 0) { + SNDERR("failed to open IPC message queue: %s", strerror(err)); + SNDERR("The PCM needs to be open for mixers to connect to pipeline"); + goto error; + } + + /* create a SHM mapping for low latency stream position */ + err = plug_shm_init(&ctl->shm_ctx, plug->tplg_file, "ctx", 0); + if (err < 0) + goto error; + + // TODO: make this open/close per operation for shared access + /* create a SHM mapping for low latency stream position */ + err = plug_shm_open(&ctl->shm_ctx); + if (err < 0) + goto error; + + /* get global context for kcontrol lookup */ + ctl->glb = ctl->shm_ctx.addr; + + /* TODO: add some flavour to the names based on the topology */ + ctl->ext.version = SND_CTL_EXT_VERSION; + ctl->ext.card_idx = 0; + strncpy(ctl->ext.id, "sof", sizeof(ctl->ext.id) - 1); + strncpy(ctl->ext.driver, "SOF plugin", + sizeof(ctl->ext.driver) - 1); + strncpy(ctl->ext.name, "SOF", sizeof(ctl->ext.name) - 1); + strncpy(ctl->ext.mixername, "SOF", + sizeof(ctl->ext.mixername) - 1); + + /* polling on message queue - supported on Linux but not portable */ + ctl->ext.poll_fd = ctl->ipc.mq; + + ctl->ext.callback = &sof_ext_callback; + ctl->ext.private_data = ctl; + ctl->ext.tlv.c = plug_tlv_rw; + + err = snd_ctl_ext_create(&ctl->ext, name, mode); + if (err < 0) + goto error; + + *handlep = ctl->ext.handle; + + return 0; + +error: + free(ctl); + + return err; +} + +SND_CTL_PLUGIN_SYMBOL(sof); diff --git a/tools/plugin/alsaplug/pcm.c b/tools/plugin/alsaplug/pcm.c new file mode 100644 index 000000000000..f6aef645ce56 --- /dev/null +++ b/tools/plugin/alsaplug/pcm.c @@ -0,0 +1,1038 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "plugin.h" +#include "common.h" + +typedef struct snd_sof_pcm { + snd_pcm_ioplug_t io; + size_t frame_size; + struct timespec wait_timeout; + int capture; + int events; + + /* PCM flow control */ + struct plug_sem_desc ready[TPLG_MAX_PCM_PIPELINES]; + struct plug_sem_desc done[TPLG_MAX_PCM_PIPELINES]; + /* pipeline IPC tx queues */ + struct plug_mq_desc pipeline_ipc_tx[TPLG_MAX_PCM_PIPELINES]; + /* pipeline IPC response queues */ + struct plug_mq_desc pipeline_ipc_rx[TPLG_MAX_PCM_PIPELINES]; + + struct plug_shm_desc glb_ctx; + struct plug_shm_desc shm_pcm; + + int frame_us; +} snd_sof_pcm_t; + +static int plug_pipeline_set_state(snd_sof_plug_t *plug, int state, + struct ipc4_pipeline_set_state *pipe_state, + struct tplg_pipeline_info *pipe_info, + struct plug_mq_desc *ipc_tx, struct plug_mq_desc *ipc_rx) +{ + struct ipc4_message_reply reply = {{ 0 }}; + int ret; + + pipe_state->primary.r.ppl_id = pipe_info->instance_id; + + ret = plug_mq_cmd_tx_rx(ipc_tx, ipc_rx, pipe_state, sizeof(*pipe_state), + &reply, sizeof(reply)); + if (ret < 0) + SNDERR("failed pipeline %d set state %d\n", pipe_info->instance_id, state); + + return ret; +} + +static int plug_pipelines_set_state(snd_sof_plug_t *plug, int state) +{ + snd_sof_pcm_t *pcm = plug->module_prv; + struct ipc4_pipeline_set_state pipe_state = {{ 0 }}; + struct tplg_pipeline_list *pipeline_list; + int i; + + if (pcm->capture) + pipeline_list = &plug->pcm_info->capture_pipeline_list; + else + pipeline_list = &plug->pcm_info->playback_pipeline_list; + + pipe_state.primary.r.ppl_state = state; + pipe_state.primary.r.type = SOF_IPC4_GLB_SET_PIPELINE_STATE; + pipe_state.primary.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG; + pipe_state.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST; + + /* + * pipeline list is populated starting from the host to DAI. So traverse the list in + * the reverse order for capture to start the source pipeline first. + */ + if (pcm->capture) { + for (i = pipeline_list->count - 1; i >= 0; i--) { + struct tplg_pipeline_info *pipe_info = pipeline_list->pipelines[i]; + int ret; + + ret = plug_pipeline_set_state(plug, state, &pipe_state, pipe_info, + &pcm->pipeline_ipc_tx[i], + &pcm->pipeline_ipc_rx[i]); + if (ret < 0) + return ret; + } + + return 0; + } + + for (i = 0; i < pipeline_list->count; i++) { + struct tplg_pipeline_info *pipe_info = pipeline_list->pipelines[i]; + int ret; + + ret = plug_pipeline_set_state(plug, state, &pipe_state, pipe_info, + &pcm->pipeline_ipc_tx[i], &pcm->pipeline_ipc_rx[i]); + if (ret < 0) + return ret; + } + + return 0; +} + +static int plug_pcm_start(snd_pcm_ioplug_t *io) +{ + snd_sof_plug_t *plug = io->private_data; + snd_sof_pcm_t *pcm = plug->module_prv; + struct plug_shm_endpoint *ctx = pcm->shm_pcm.addr; + int err; + + switch (ctx->state) { + case SOF_PLUGIN_STATE_READY: + err = plug_pipelines_set_state(plug, SOF_IPC4_PIPELINE_STATE_RUNNING); + if (err < 0) + return err; + break; + case SOF_PLUGIN_STATE_STREAM_RUNNING: + { + struct tplg_pipeline_list *pipeline_list; + int i, delay; + + if (!pcm->capture) + break; + + pipeline_list = &plug->pcm_info->capture_pipeline_list; + + /* start the first period copy for capture */ + for (i = pipeline_list->count - 1; i >= 0; i--) { + sem_post(pcm->ready[i].sem); + + /* wait for sof-pipe reader to consume data or timeout */ + err = clock_gettime(CLOCK_REALTIME, &pcm->wait_timeout); + if (err == -1) { + SNDERR("write: cant get time: %s", strerror(errno)); + return -EPIPE; + } + + /* work out delay TODO: fix ALSA reader */ + delay = pcm->frame_us * io->period_size / 500; + plug_timespec_add_ms(&pcm->wait_timeout, delay); + + /* wait for sof-pipe writer to produce data or timeout */ + err = sem_timedwait(pcm->done[i].sem, &pcm->wait_timeout); + if (err == -1) { + SNDERR("read: waited %d ms for %ld frames fatal timeout: %s", + delay, io->period_size, strerror(errno)); + return -errno; + } + } + } + break; + case SOF_PLUGIN_STATE_INIT: + case SOF_PLUGIN_STATE_STREAM_ERROR: + case SOF_PLUGIN_STATE_DEAD: + default: + /* some error */ + SNDERR("pcm start: invalid pipe state: %d", ctx->state); + return -EINVAL; + } + + return 0; +} + +static int plug_pcm_stop(snd_pcm_ioplug_t *io) +{ + snd_sof_plug_t *plug = io->private_data; + snd_sof_pcm_t *pcm = plug->module_prv; + struct plug_shm_endpoint *ctx = pcm->shm_pcm.addr; + int err; + + printf("%s %d state %ld\n", __func__, __LINE__, ctx->state); + switch (ctx->state) { + case SOF_PLUGIN_STATE_STREAM_ERROR: + case SOF_PLUGIN_STATE_STREAM_RUNNING: + { + err = plug_pipelines_set_state(plug, SOF_IPC4_PIPELINE_STATE_PAUSED); + if (err < 0) + return err; + break; + } + case SOF_PLUGIN_STATE_READY: + /* already stopped */ + break; + case SOF_PLUGIN_STATE_INIT: + case SOF_PLUGIN_STATE_DEAD: + default: + /* some error */ + SNDERR("pcm stop: invalid pipe state: %d", ctx->state); + return -EINVAL; + } + + return 0; +} + +/* buffer position up to buffer_size */ +static snd_pcm_sframes_t plug_pcm_pointer(snd_pcm_ioplug_t *io) +{ + snd_sof_plug_t *plug = io->private_data; + snd_sof_pcm_t *pcm = plug->module_prv; + struct plug_shm_endpoint *ctx = pcm->shm_pcm.addr; + snd_pcm_sframes_t ptr = 0; + int err; + + if (io->state == SND_PCM_STATE_XRUN) + return -EPIPE; + + if (io->state != SND_PCM_STATE_RUNNING) + return 0; + + switch (ctx->state) { + case SOF_PLUGIN_STATE_STREAM_RUNNING: + case SOF_PLUGIN_STATE_STREAM_ERROR: + if (pcm->capture) + ptr = ctx->wtotal / pcm->frame_size; + else + ptr = ctx->rtotal / pcm->frame_size; + break; + case SOF_PLUGIN_STATE_READY: + /* not running */ + return 0; + case SOF_PLUGIN_STATE_INIT: + case SOF_PLUGIN_STATE_DEAD: + default: + /* some error */ + SNDERR("pointer: invalid pipe state: %d", ctx->state); + ptr = -EPIPE; + } + + return ptr; +} + +/* get the delay for the running PCM; optional; since v1.0.1 */ +static int plug_pcm_delay(snd_pcm_ioplug_t *io, snd_pcm_sframes_t *delayp) +{ + snd_sof_plug_t *plug = io->private_data; + snd_sof_pcm_t *pcm = plug->module_prv; + struct plug_shm_endpoint *ctx = pcm->shm_pcm.addr; + int err = 0; + + switch (ctx->state) { + case SOF_PLUGIN_STATE_STREAM_RUNNING: + case SOF_PLUGIN_STATE_READY: + // TODO: is capture delay correct here ??? + if (pcm->capture) + *delayp = (ctx->wtotal - ctx->rtotal) / pcm->frame_size; + else + *delayp = (ctx->rtotal - ctx->wtotal) / pcm->frame_size; + /* sanitize delay */ + if (*delayp < pcm->io.period_size || *delayp > io->buffer_size) + *delayp = pcm->io.period_size; + return 0; + case SOF_PLUGIN_STATE_STREAM_ERROR: + snd_pcm_ioplug_set_state(io, SND_PCM_STATE_XRUN); + return 0; + case SOF_PLUGIN_STATE_INIT: + case SOF_PLUGIN_STATE_DEAD: + default: + /* some error */ + SNDERR("delay: invalid pipe state: %d", ctx->state); + return -EPIPE; + } +} + +/* return frames written */ +static snd_pcm_sframes_t plug_pcm_write(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, snd_pcm_uframes_t size) +{ + snd_sof_plug_t *plug = io->private_data; + snd_sof_pcm_t *pcm = plug->module_prv; + struct plug_shm_endpoint *ctx = pcm->shm_pcm.addr; + struct tplg_pipeline_list *pipeline_list; + snd_pcm_sframes_t frames = 0; + int i; + ssize_t bytes; + const char *buf; + int err, delay; + + pipeline_list = &plug->pcm_info->playback_pipeline_list; + + /* calculate the buffer position and size from application */ + buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8; + bytes = size * pcm->frame_size; + + /* now check what the pipe has free */ + bytes = MIN(plug_ep_get_free(ctx), bytes); + + frames = bytes / pcm->frame_size; + + if (frames == 0) + return frames; + + /* write audio data to the pipe */ + memcpy(plug_ep_wptr(ctx), buf, bytes); + + plug_ep_produce(ctx, bytes); + + /* tell the pipelines data is ready starting at the source pipeline */ + for (i = 0; i < pipeline_list->count; i++) { + struct tplg_pipeline_info *pipe_info = pipeline_list->pipelines[i]; + + sem_post(pcm->ready[i].sem); + + /* wait for sof-pipe reader to consume data or timeout */ + err = clock_gettime(CLOCK_REALTIME, &pcm->wait_timeout); + if (err == -1) { + SNDERR("write: cant get time: %s", strerror(errno)); + return -EPIPE; + } + + /* work out delay */ + delay = pcm->frame_us * frames / 500; + plug_timespec_add_ms(&pcm->wait_timeout, delay); + + /* now block caller on pipeline IO to PCM device */ + err = sem_timedwait(pcm->done[i].sem, &pcm->wait_timeout); + if (err == -1) { + SNDERR("write: waited %d ms for %ld frames, fatal timeout: %s", + delay, frames, strerror(errno)); + return -errno; + } + } + + return frames; +} + +/* return frames read */ +static snd_pcm_sframes_t plug_pcm_read(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, snd_pcm_uframes_t size) +{ + snd_sof_plug_t *plug = io->private_data; + snd_sof_pcm_t *pcm = plug->module_prv; + snd_pcm_sframes_t frames; + struct plug_shm_endpoint *ctx = pcm->shm_pcm.addr; + struct tplg_pipeline_list *pipeline_list; + ssize_t bytes; + char *buf; + int err, delay, i; + + pipeline_list = &plug->pcm_info->capture_pipeline_list; + + /* calculate the buffer position and size */ + buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8; + bytes = size * pcm->frame_size; + + /* check what the pipe has avail */ + bytes = MIN(plug_ep_get_avail(ctx), bytes); + frames = bytes / pcm->frame_size; + + if (!frames) + return 0; + + /* tell the pipe ready we are ready for next period */ + for (i = pipeline_list->count - 1; i >= 0; i--) { + sem_post(pcm->ready[i].sem); + + /* wait for sof-pipe reader to consume data or timeout */ + err = clock_gettime(CLOCK_REALTIME, &pcm->wait_timeout); + if (err == -1) { + SNDERR("write: cant get time: %s", strerror(errno)); + return -EPIPE; + } + + /* work out delay TODO: fix ALSA reader */ + delay = pcm->frame_us * frames / 500; + plug_timespec_add_ms(&pcm->wait_timeout, delay); + + /* wait for sof-pipe writer to produce data or timeout */ + err = sem_timedwait(pcm->done[i].sem, &pcm->wait_timeout); + if (err == -1) { + SNDERR("read: waited %d ms for %ld frames fatal timeout: %s", + delay, frames, strerror(errno)); + return -errno; + } + } + + /* copy audio data from pipe */ + memcpy(buf, plug_ep_rptr(ctx), bytes); + plug_ep_consume(ctx, bytes); + + return frames; +} + +static int plug_pcm_prepare(snd_pcm_ioplug_t *io) +{ + snd_sof_plug_t *plug = io->private_data; + snd_sof_pcm_t *pcm = plug->module_prv; + struct plug_shm_endpoint *ctx = pcm->shm_pcm.addr; + int err = 0; + + ctx->wtotal = 0; + ctx->rtotal = 0; + ctx->rpos = 0; + ctx->rwrap = 0; + ctx->wpos = 0; + ctx->wwrap = 0; + + /* start the pipeline threads + * + * We do this during prepare so that pipelines can consume/produce + * any start threshold worth of data with the pipeline in a running + * state + */ + switch (ctx->state) { + case SOF_PLUGIN_STATE_INIT: + /* set pipelines to PAUSED state to prepare them */ + err = plug_pipelines_set_state(plug, SOF_IPC4_PIPELINE_STATE_PAUSED); + if (err < 0) + return err; + + fprintf(stdout, "pipelines complete now\n"); + + /* set pipelines to RUNNING state */ + err = plug_pipelines_set_state(plug, SOF_IPC4_PIPELINE_STATE_RUNNING); + if (err < 0) + return err; + break; + case SOF_PLUGIN_STATE_STREAM_ERROR: + case SOF_PLUGIN_STATE_DEAD: + /* some error */ + SNDERR("write: invalid pipe state: %d", ctx->state); + return -EINVAL; + case SOF_PLUGIN_STATE_READY: + case SOF_PLUGIN_STATE_STREAM_RUNNING: + default: + /* do nothing */ + break; + } + + fprintf(stdout, "PCM prepare done\n"); + + return err; +} + +static int plug_init_shm_ctx(snd_sof_plug_t *plug); + +static int plug_pcm_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) +{ + snd_sof_plug_t *plug = io->private_data; + snd_sof_pcm_t *pcm = plug->module_prv; + struct plug_shm_endpoint *ctx; + struct tplg_pipeline_list *pipeline_list; + int i, err; + + pcm->frame_size = (snd_pcm_format_physical_width(io->format) * io->channels) / 8; + + plug->period_size = io->period_size; + + /* used for wait timeouts */ + pcm->frame_us = ceil(1000000.0 / io->rate); + + /* now send IPCs to set up widgets */ + err = plug_set_up_pipelines(plug, pcm->capture); + if (err < 0) { + fprintf(stderr, "error setting up pipelines\n"); + return err; + } + + if (pcm->capture) + pipeline_list = &plug->pcm_info->capture_pipeline_list; + else + pipeline_list = &plug->pcm_info->playback_pipeline_list; + + /* init and open for PCM ready lock for all pipelines */ + for (i = 0; i < pipeline_list->count; i++) { + struct tplg_pipeline_info *pipe_info = pipeline_list->pipelines[i]; + + /* init IPC message queue name */ + err = plug_mq_init(&pcm->pipeline_ipc_tx[i], plug->tplg_file, "pcm-tx", + pipe_info->instance_id); + if (err < 0) { + SNDERR("error: invalid name for pipeline IPC mq %s\n", plug->tplg_file); + return err; + } + + /* open the sof-pipe IPC message queue */ + err = plug_mq_open(&pcm->pipeline_ipc_tx[i]); + if (err < 0) { + SNDERR("error: failed to open sof-pipe IPC mq %s: %s", + pcm->pipeline_ipc_tx[i].queue_name, strerror(err)); + return -errno; + } + + /* init IPC message queue name */ + err = plug_mq_init(&pcm->pipeline_ipc_rx[i], plug->tplg_file, "pcm-rx", + pipe_info->instance_id); + if (err < 0) { + SNDERR("error: invalid name for pipeline IPC mq %s\n", plug->tplg_file); + return err; + } + + /* open the sof-pipe IPC message queue */ + err = plug_mq_open(&pcm->pipeline_ipc_rx[i]); + if (err < 0) { + SNDERR("error: failed to open sof-pipe IPC mq %s: %s", + pcm->pipeline_ipc_tx[i].queue_name, strerror(err)); + return -errno; + } + + /* init name for pipeline ready lock */ + err = plug_lock_init(&pcm->ready[i], plug->tplg_file, "ready", + pipe_info->instance_id); + if (err < 0) { + SNDERR("error: invalid name for PCM ready lock %s\n", + pipe_info->instance_id); + return err; + } + + /* init name for pipeline done lock */ + err = plug_lock_init(&pcm->done[i], plug->tplg_file, "done", + pipe_info->instance_id); + if (err < 0) { + SNDERR("error: invalid name for PCM done lock %s\n", + pipe_info->instance_id); + return err; + } + + /* open lock "ready" for pipeline audio data */ + err = plug_lock_open(&pcm->ready[i]); + if (err < 0) { + SNDERR("error: failed to open sof-pipe ready lock %s: %s", + pcm->ready[i].name, strerror(err)); + return -errno; + } + + /* open lock "done" for pipeline audio data */ + err = plug_lock_open(&pcm->done[i]); + if (err < 0) { + SNDERR("error: failed to open sof-pipe done lock %s: %s", + pcm->done[i].name, strerror(err)); + return -errno; + } + } + + /* init global status shm name */ + err = plug_shm_init(&pcm->glb_ctx, plug->tplg_file, "ctx", 0); + if (err < 0) { + SNDERR("error: invalid name for global SHM %s\n", plug->tplg_file); + return err; + } + + /* init PCM shm name */ + err = plug_shm_init(&pcm->shm_pcm, plug->tplg_file, "pcm", plug->pcm_id); + if (err < 0) { + SNDERR("error: invalid name for PCM SHM %s\n", plug->tplg_file); + return err; + } + + /* open the global sof-pipe context via SHM */ + pcm->glb_ctx.size = 128 * 1024; + err = plug_shm_open(&pcm->glb_ctx); + if (err < 0) { + SNDERR("error: failed to open sof-pipe context: %s:%s", + pcm->glb_ctx.name, strerror(err)); + return err; + } + + /* open audio PCM SHM data endpoint */ + err = plug_shm_open(&pcm->shm_pcm); + if (err < 0) { + SNDERR("error: failed to open sof-pipe PCM SHM %s: %s", + pcm->shm_pcm.name, strerror(err)); + return -errno; + } + + /* set up the endpoint configs */ + err = plug_init_shm_ctx(plug); + if (err < 0) { + SNDERR("error: failed to init sof-pipe ep context: %s:%s", + pcm->glb_ctx.name, strerror(err)); + return -err; + } + + ctx = pcm->shm_pcm.addr; + ctx->frame_size = pcm->frame_size; + + /* needs to be set here and NOT in SW params as SW params not + * called in capture flow ? + */ + ctx->buffer_size = io->buffer_size * ctx->frame_size; + + if (!ctx->buffer_size) { + SNDERR("Invalid buffer_size io buffer_size %d ctx->frame_size %d\n", + io->buffer_size, ctx->frame_size); + return -EINVAL; + } + + fprintf(stdout, "PCM hw_params done\n"); + + return 0; +} + +// TODO: why not called for arecord +static int plug_pcm_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params) +{ + snd_sof_plug_t *plug = io->private_data; + snd_sof_pcm_t *pcm = plug->module_prv; + snd_pcm_uframes_t start_threshold; + struct plug_shm_endpoint *ctx = pcm->shm_pcm.addr; + int err; + + /* get the stream start threshold */ + err = snd_pcm_sw_params_get_start_threshold(params, &start_threshold); + if (err < 0) { + SNDERR("sw params: failed to get start threshold: %s", strerror(err)); + return err; + } + + /* TODO: this seems to be ignored or overridden by application params ??? */ + if (start_threshold < io->period_size) { + start_threshold = io->period_size; + err = snd_pcm_sw_params_set_start_threshold(pcm->io.pcm, + params, start_threshold); + if (err < 0) { + SNDERR("sw params: failed to set start threshold %d: %s", + start_threshold, strerror(err)); + return err; + } + } + + /* keep running as long as we can */ + err = snd_pcm_sw_params_set_avail_min(pcm->io.pcm, params, 1); + if (err < 0) { + SNDERR("sw params: failed to set avail min %d: %s", 1, strerror(err)); + return err; + } + + fprintf(stdout, "sw_params done\n"); + + return 0; +} + +static int plug_pcm_close(snd_pcm_ioplug_t *io) +{ + snd_sof_plug_t *plug = io->private_data; + snd_sof_pcm_t *pcm = plug->module_prv; + struct plug_shm_glb_state *ctx = pcm->glb_ctx.addr; + int err = 0; + + printf("%s %d\n", __func__, __LINE__); + + ctx->state = SOF_PLUGIN_STATE_INIT; + + plug_free_topology(plug); + + free(plug->tplg_file); + free(plug->module_prv); + free(plug); + + return err; +} + +static int plug_pcm_hw_free(snd_pcm_ioplug_t *io) +{ + struct tplg_pipeline_list *pipeline_list; + snd_sof_plug_t *plug = io->private_data; + snd_sof_pcm_t *pcm = plug->module_prv; + int ret, i; + + /* reset all pipelines */ + ret = plug_pipelines_set_state(plug, SOF_IPC4_PIPELINE_STATE_RESET); + if (ret < 0) { + fprintf(stderr, "failed to reset pipelines\n"); + return ret; + } + + if (pcm->capture) + pipeline_list = &plug->pcm_info->capture_pipeline_list; + else + pipeline_list = &plug->pcm_info->playback_pipeline_list; + + ret = plug_free_pipelines(plug, pipeline_list, pcm->capture); + if (ret < 0) + return ret; + + close(pcm->shm_pcm.fd); + close(pcm->glb_ctx.fd); + + for (i = 0; i < pipeline_list->count; i++) { + struct tplg_pipeline_info *pipe_info = pipeline_list->pipelines[i]; + + mq_close(pcm->pipeline_ipc_tx[pipe_info->instance_id].mq); + mq_close(pcm->pipeline_ipc_rx[pipe_info->instance_id].mq); + sem_close(pcm->ready[pipe_info->instance_id].sem); + sem_close(pcm->done[pipe_info->instance_id].sem); + } +} + +static const snd_pcm_ioplug_callback_t sof_playback_callback = { + .start = plug_pcm_start, + .stop = plug_pcm_stop, + .pointer = plug_pcm_pointer, + .transfer = plug_pcm_write, + .delay = plug_pcm_delay, + .prepare = plug_pcm_prepare, + .hw_params = plug_pcm_hw_params, + .hw_free = plug_pcm_hw_free, + .sw_params = plug_pcm_sw_params, + .close = plug_pcm_close, +}; + +static const snd_pcm_ioplug_callback_t sof_capture_callback = { + .start = plug_pcm_start, + .stop = plug_pcm_stop, + .pointer = plug_pcm_pointer, + .transfer = plug_pcm_read, + .delay = plug_pcm_delay, + .prepare = plug_pcm_prepare, + .hw_params = plug_pcm_hw_params, + .sw_params = plug_pcm_sw_params, + .hw_free = plug_pcm_hw_free, + .close = plug_pcm_close, +}; + +static const snd_pcm_access_t access_list[] = { + SND_PCM_ACCESS_RW_INTERLEAVED +}; + +static const unsigned int formats[] = { + SND_PCM_FORMAT_S16_LE, + SND_PCM_FORMAT_FLOAT_LE, + SND_PCM_FORMAT_S32_LE, + SND_PCM_FORMAT_S24_LE, +}; + +/* + * Set HW constraints for the SOF plugin. This needs to be quite unrestrictive atm + * as we really need to parse topology before the HW constraints can be narrowed + * to a range that will work with the specified pipeline. + * TODO: Align with topology. + */ +static int plug_hw_constraint(snd_sof_plug_t *plug) +{ + snd_sof_pcm_t *pcm = plug->module_prv; + snd_pcm_ioplug_t *io = &pcm->io; + int err; + + err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, + ARRAY_SIZE(access_list), + access_list); + if (err < 0) { + SNDERR("constraints: failed to set access: %s", strerror(err)); + return err; + } + + err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, + ARRAY_SIZE(formats), formats); + if (err < 0) { + SNDERR("constraints: failed to set format: %s", strerror(err)); + return err; + } + + err = + snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, + 1, 8); + if (err < 0) { + SNDERR("constraints: failed to set channels: %s", strerror(err)); + return err; + } + + err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, + 1, 192000); + if (err < 0) { + SNDERR("constraints: failed to set rate: %s", strerror(err)); + return err; + } + + err = + snd_pcm_ioplug_set_param_minmax(io, + SND_PCM_IOPLUG_HW_BUFFER_BYTES, + 1, 4 * 1024 * 1024); + if (err < 0) { + SNDERR("constraints: failed to set buffer bytes: %s", strerror(err)); + return err; + } + + err = + snd_pcm_ioplug_set_param_minmax(io, + SND_PCM_IOPLUG_HW_PERIOD_BYTES, + 128, 2 * 1024 * 1024); + if (err < 0) { + SNDERR("constraints: failed to set period bytes: %s", strerror(err)); + return err; + } + + err = + snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 1, 4); + if (err < 0) { + SNDERR("constraints: failed to set period count: %s", strerror(err)); + return err; + } + + return 0; +} + +/* + * Register the plugin with ALSA and make available for use. + * TODO: setup all audio params + * TODO: setup polling fd for RW or mmap IOs + */ +static int plug_create(snd_sof_plug_t *plug, snd_pcm_t **pcmp, const char *name, + snd_pcm_stream_t stream, int mode) +{ + snd_sof_pcm_t *pcm = plug->module_prv; + int err; + + pcm->io.version = SND_PCM_IOPLUG_VERSION; + pcm->io.name = "ALSA <-> SOF PCM I/O Plugin"; + pcm->io.poll_fd = pcm->shm_pcm.fd; + pcm->io.poll_events = POLLIN; + pcm->io.mmap_rw = 0; + + if (stream == SND_PCM_STREAM_PLAYBACK) + pcm->io.callback = &sof_playback_callback; + else + pcm->io.callback = &sof_capture_callback; + + pcm->io.private_data = plug; + + /* create the plugin */ + err = snd_pcm_ioplug_create(&pcm->io, name, stream, mode); + if (err < 0) { + SNDERR("failed to register plugin %s: %s\n", name, strerror(err)); + return err; + } + + /* set the HW constrainst */ + err = plug_hw_constraint(plug); + if (err < 0) { + snd_pcm_ioplug_delete(&pcm->io); + return err; + } + + *pcmp = pcm->io.pcm; + return 0; +} + +static int plug_init_shm_ctx(snd_sof_plug_t *plug) +{ + snd_sof_pcm_t *pcm = plug->module_prv; + struct plug_shm_glb_state *glb = pcm->glb_ctx.addr; + struct endpoint_hw_config *ep; + struct plug_cmdline_item *ci; + struct plug_config *pc; + int i, j; + + glb->num_ep_configs = 0; + + for (i = 0; i < plug->num_cmdline; i++) { + bool found = false; + + if (glb->num_ep_configs >= NUM_EP_CONFIGS - 1) { + SNDERR("error: too many endpoint configs\n"); + return -EINVAL; + } + + ci = &plug->cmdline[i]; + + for (j = 0; j < plug->num_configs; j++) { + pc = &plug->config[j]; + if (strcmp(pc->name, ci->config_name)) + continue; + + ep = &glb->ep_config[glb->num_ep_configs++]; + ep->buffer_frames = pc->buffer_frames; + ep->buffer_time = pc->buffer_time; + ep->channels = pc->channels; + ep->format = pc->format; + ep->period_frames = pc->period_frames; + ep->period_time = pc->period_time; + ep->rate = pc->rate; + ep->pipeline = ci->pcm; + strncpy(ep->card_name, ci->card_name, + sizeof(ep->card_name)); + strncpy(ep->dev_name, ci->dev_name, + sizeof(ep->dev_name)); + strncpy(ep->config_name, ci->config_name, + sizeof(ep->config_name)); + found = true; + break; + } + + if (!found) { + SNDERR("error: config %s not found\n", ci->config_name); + return -EINVAL; + } + } + + return 0; +} + +/* + * Complete parent initialisation. + * 1. Check if pipe already ready by opening SHM context and IPC. + * 2. TODO: check context state and load topology is needed for core. + */ +static int plug_init_sof_pipe(snd_sof_plug_t *plug, snd_pcm_t **pcmp, + const char *name, snd_pcm_stream_t stream, int mode) +{ + snd_sof_pcm_t *pcm = plug->module_prv; + struct plug_shm_glb_state *ctx; + struct timespec delay; + int err, i; + + /* initialize widget, route and pcm lists */ + list_init(&plug->widget_list); + list_init(&plug->route_list); + list_init(&plug->pcm_list); + + plug->tplg.tplg_file = plug->tplg_file; + + /* plugin only works with IPC4 */ + plug->tplg.ipc_major = 4; + + /* parse topology file */ + err = plug_parse_topology(plug); + if (err < 0) { + fprintf(stderr, "error parsing topology %s\n", plug->tplg.tplg_file); + return err; + } + + fprintf(stdout, "topology parsing complete\n"); + + /* init IPC message queue name */ + err = plug_mq_init(&plug->ipc_tx, "sof", "ipc-tx", 0); + if (err < 0) { + SNDERR("error: invalid name for IPC mq %s\n", plug->tplg_file); + return err; + } + + /* open the sof-pipe IPC message queue */ + err = plug_mq_open(&plug->ipc_tx); + if (err < 0) { + SNDERR("error: failed to open sof-pipe IPC mq %s: %s", + plug->ipc_tx.queue_name, strerror(err)); + return -errno; + } + + err = plug_mq_init(&plug->ipc_rx, "sof", "ipc-rx", 0); + if (err < 0) { + SNDERR("error: invalid name for IPC mq %s\n", plug->tplg_file); + return err; + } + + /* open the sof-pipe IPC message queue */ + err = plug_mq_open(&plug->ipc_rx); + if (err < 0) { + SNDERR("error: failed to open sof-pipe IPC mq %s: %s", + plug->ipc_rx.queue_name, strerror(err)); + return -errno; + } + + /* now register the plugin */ + err = plug_create(plug, pcmp, name, stream, mode); + if (err < 0) { + SNDERR("failed to create plugin: %s", strerror(err)); + return -errno; + } + + return 0; +} + +/* + * ALSA PCM plugin entry point. + */ +SND_PCM_PLUGIN_DEFINE_FUNC(sof) +{ + snd_sof_plug_t *plug; + snd_sof_pcm_t *pcm; + int err; + + fprintf(stdout, "This code is WIP. Cmd args & config will possible change over time\n"); + fprintf(stdout, "\nThe 50-sonf.conf file is parsed for PCM configurations which can\n"); + fprintf(stdout, "be mapped on the cmd line to pipeline endpoints.\n"); + fprintf(stdout, "\ni.e. aplay -Dsof:::: file.wav\n"); + fprintf(stdout, "\nwhich can be used as\n"); + fprintf(stdout, "\ne.g. aplay -Dsof:bdw-nocodec:1:default:default:48k2c16b -f dat ~/audiodump.wav\n\n"); + + /* create context */ + plug = calloc(1, sizeof(*plug)); + if (!plug) + return -ENOMEM; + + pcm = calloc(1, sizeof(*pcm)); + if (!pcm) { + free(plug); + return -ENOMEM; + } + plug->module_prv = pcm; + + if (stream == SND_PCM_STREAM_CAPTURE) + pcm->capture = 1; + + /* parse the ALSA configuration file for sof plugin */ + err = plug_parse_conf(plug, name, root, conf); + if (err < 0) { + SNDERR("failed to parse config: %s", strerror(err)); + goto parse_conf_err; + } + + /* now try and connect to the sof-pipe for this topology */ + err = plug_init_sof_pipe(plug, pcmp, name, stream, mode); + if (err < 0) { + SNDERR("failed to complete plugin init: %s", strerror(err)); + goto pipe_error; + } + + /* everything is good */ + return 0; + +pipe_error: + free(plug->tplg_file); +parse_conf_err: + free(plug->module_prv); +dev_error: + free(plug); + return err; +} + +SND_PCM_PLUGIN_SYMBOL(sof); diff --git a/tools/plugin/alsaplug/plugin.c b/tools/plugin/alsaplug/plugin.c new file mode 100644 index 000000000000..b21e728c69fa --- /dev/null +++ b/tools/plugin/alsaplug/plugin.c @@ -0,0 +1,452 @@ +/*-*- linux-c -*-*/ + +/* + * ALSA <-> SOF PCM I/O plugin + * + * Copyright(c) 2022 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "plugin.h" +#include "common.h" + +int plug_mq_cmd_tx_rx(struct plug_mq_desc *ipc_tx, struct plug_mq_desc *ipc_rx, + void *msg, size_t len, void *reply, size_t rlen) +{ + struct timespec ts; + ssize_t ipc_size; + char mailbox[IPC3_MAX_MSG_SIZE]; + int err; + + if (len > IPC3_MAX_MSG_SIZE) { + SNDERR("ipc: message too big %d\n", len); + return -EINVAL; + } + memset(mailbox, 0, IPC3_MAX_MSG_SIZE); + memcpy(mailbox, msg, len); + + /* wait for sof-pipe reader to consume data or timeout */ + err = clock_gettime(CLOCK_REALTIME, &ts); + if (err == -1) { + SNDERR("ipc: cant get time: %s", strerror(errno)); + return -errno; + } + + /* IPCs should be read under 10ms */ + plug_timespec_add_ms(&ts, 10); + + /* now return message completion status */ + err = mq_timedsend(ipc_tx->mq, mailbox, IPC3_MAX_MSG_SIZE, 0, &ts); + if (err == -1) { + SNDERR("error: timeout can't send IPC message queue %s : %s\n", + ipc_tx->queue_name, strerror(errno)); + return -errno; + } + + /* wait for sof-pipe reader to consume data or timeout */ + err = clock_gettime(CLOCK_REALTIME, &ts); + if (err == -1) { + SNDERR("ipc: cant get time: %s", strerror(errno)); + return -errno; + } + + /* IPCs should be processed under 20ms, but wait longer as + * some can take longer especially in valgrind + */ + plug_timespec_add_ms(&ts, 20); + + ipc_size = mq_timedreceive(ipc_rx->mq, mailbox, IPC3_MAX_MSG_SIZE, NULL, &ts); + if (ipc_size == -1) { + //fprintf(stderr, "dbg: timeout can't read IPC message queue %s : %s retrying\n", + // ipc->queue_name, strerror(errno)); + + /* ok, its a long IPC or valgrind, wait longer */ + plug_timespec_add_ms(&ts, 800); + + ipc_size = mq_timedreceive(ipc_rx->mq, mailbox, IPC3_MAX_MSG_SIZE, NULL, &ts); + if (ipc_size == -1) { + SNDERR("error: timeout can't read IPC message queue %s : %s\n", + ipc_rx->queue_name, strerror(errno)); + return -errno; + } + + /* needed for valgrind to complete MQ op before next client IPC */ + ts.tv_nsec = 20 * 1000 * 1000; + ts.tv_sec = 0; + nanosleep(&ts, NULL); + } + + /* do the message work */ + if (rlen && reply) + memcpy(reply, mailbox, rlen); + + return 0; +} + +int plug_mq_cmd(struct plug_mq_desc *ipc, void *msg, size_t len, void *reply, size_t rlen) +{ + return plug_mq_cmd_tx_rx(ipc, ipc, msg, len, reply, rlen); +} + +/* + * Open an existing message queue using IPC object. + */ +int plug_mq_open(struct plug_mq_desc *ipc) +{ + /* now open new queue for Tx and Rx */ + ipc->mq = mq_open(ipc->queue_name, O_RDWR); + if (ipc->mq < 0) { + // SNDERR("failed to open IPC queue %s: %s\n", + // ipc->queue_name, strerror(errno)); + return -errno; + } + + return 0; +} + +/* + * Open an existing semaphore using lock object. + */ +int plug_lock_open(struct plug_sem_desc *lock) +{ + lock->sem = sem_open(lock->name, O_RDWR); + if (lock->sem == SEM_FAILED) { + SNDERR("failed to open semaphore %s: %s\n", lock->name, strerror(errno)); + return -errno; + } + + return 0; +} + +#define itemsize(type, member) sizeof(((type *)0)->member) + +static int parse_conf_long(snd_config_t *cfg, void *obj, size_t size) +{ + long val; + + if (snd_config_get_integer(cfg, &val) < 0) + return -EINVAL; + + *((long *)obj) = val; + return 0; +} + +static int parse_conf_str(snd_config_t *cfg, void *obj, size_t size) +{ + const char *id; + + if (snd_config_get_id(cfg, &id) < 0) + return -EINVAL; + strncpy(obj, id, size); + + return 0; +} + +static int parse_conf_format(snd_config_t *cfg, void *obj, size_t size) +{ + const char *id; + + if (snd_config_get_string(cfg, &id) < 0) + return -EINVAL; + + if (!strcmp("S16_LE", id)) { + *((long *)obj) = SND_PCM_FORMAT_S16_LE; + return 0; + } + if (!strcmp("S32_LE", id)) { + *((long *)obj) = SND_PCM_FORMAT_S32_LE; + return 0; + } + if (!strcmp("S24_4LE", id)) { + *((long *)obj) = SND_PCM_FORMAT_S24_LE; + return 0; + } + if (!strcmp("FLOAT", id)) { + *((long *)obj) = SND_PCM_FORMAT_FLOAT_LE; + return 0; + } + + /* not found */ + SNDERR("error: cant find format: %s", id); + return -EINVAL; +} + +struct config_item { + char *name; + size_t size; + size_t offset; + int (*copy)(snd_config_t *cfg, void *obj, size_t size); +}; + +struct config_item config_items[] = { + {"name", itemsize(struct plug_config, name), + offsetof(struct plug_config, name), parse_conf_str}, + {"rate", itemsize(struct plug_config, rate), + offsetof(struct plug_config, rate), parse_conf_long}, + {"format", itemsize(struct plug_config, format), + offsetof(struct plug_config, format), parse_conf_format}, + {"channels", itemsize(struct plug_config, channels), + offsetof(struct plug_config, channels), parse_conf_long}, + {"period_time", itemsize(struct plug_config, period_time), + offsetof(struct plug_config, period_time), parse_conf_long}, + {"period_frames", itemsize(struct plug_config, period_frames), + offsetof(struct plug_config, period_frames), parse_conf_long}, + {"buffer_time", itemsize(struct plug_config, buffer_time), + offsetof(struct plug_config, buffer_time), parse_conf_long}, + {"buffer_frames", itemsize(struct plug_config, buffer_frames), + offsetof(struct plug_config, buffer_frames), parse_conf_long}, +}; + +static int parse_item(snd_config_t *cfg, const char *id, struct plug_config *dest_cfg) +{ + void *dest = dest_cfg; + int i; + + for (i = 0; i < ARRAY_SIZE(config_items); i++) { + /* does ID match */ + if (strcmp(id, config_items[i].name)) + continue; + + /* now get the value */ + return config_items[i].copy(cfg, dest + config_items[i].offset, + config_items[i].size); + } + + /* not found - non fatal */ + return 0; +} + +static int parse_slave_configs(snd_sof_plug_t *plug, snd_config_t *n) +{ + snd_config_iterator_t si1, si2, snext1, snext2; + struct plug_config *config; + const char *id; + + fprintf(stdout, "Parsing ALSA conf for configs\n"); + + snd_config_for_each(si1, snext1, n) { + snd_config_t *sn1 = snd_config_iterator_entry(si1); + + config = &plug->config[plug->num_configs]; + + /* get config name */ + if (parse_item(sn1, "name", config) < 0) { + SNDERR("error: cant find config name"); + return -EINVAL; + } + + /* now get item values in each config */ + snd_config_for_each(si2, snext2, sn1) { + snd_config_t *sn2 = snd_config_iterator_entry(si2); + + if (snd_config_get_id(sn2, &id) < 0) + continue; + + if (parse_item(sn2, id, config) < 0) { + SNDERR("error: malformed config: %s", id); + return -EINVAL; + } + } + + fprintf(stdout, " config %d: %s\n", plug->num_configs, + config->name); + + /* next config */ + plug->num_configs++; + if (plug->num_configs >= PLUG_MAX_CONFIG) { + SNDERR("error: too many configs"); + return -EINVAL; + } + } + + return 0; +} + +/* + * Parse the client cmdline. Format is + * tplg:pcm:card:dev:config[dai_pipe:card:dev:config]...] + */ +static int parse_client_cmdline(snd_sof_plug_t *plug, char *cmdline) +{ + struct plug_cmdline_item *cmd_item; + char *tplg, *next, *card, *dev, *config, *pcm; + char *tplg_path = getenv("SOF_PLUGIN_TOPOLOGY_PATH"); + char tplg_file[128]; + int ret; + int i; + + if (!tplg_path) { + SNDERR("Invalid topology path. Please set the SOF_PLUGIN_TOPOLOGY_PATH env variable\n"); + return -EINVAL; + } + + /* get topology file */ + tplg = strtok_r(cmdline, ":", &next); + if (!tplg) { + SNDERR("invalid cmdline, cant find topology %s", cmdline); + return -EINVAL; + } + + /* now convert to filename and add the topology path */ + ret = snprintf(tplg_file, sizeof(tplg_file), "%ssof-%s.tplg", tplg_path, tplg); + if (ret < 0) { + SNDERR("invalid cmdline topology file %s", tplg); + return -EINVAL; + } + plug->tplg_file = strdup(tplg_file); + if (!plug->tplg_file) + return -ENOMEM; + + /* get PCM ID */ + pcm = strtok_r(next, ":", &next); + if (!pcm) { + SNDERR("invalid cmdline, cant find PCM %s", pcm); + return -EINVAL; + } + plug->pcm_id = atoi(pcm); + + fprintf(stdout, "Parsing cmd line\n"); + + cmd_item = &plug->cmdline[plug->num_cmdline]; + card = strtok_r(next, ":", &next); + if (!card) { + SNDERR("Invalid card name\n"); + return -EINVAL; + } + dev = strtok_r(next, ":", &next); + if (!dev) { + SNDERR("Invalid dev name\n"); + return -EINVAL; + } + config = strtok_r(next, ":", &next); + + /* tuple needs all three, any missing ? */ + if (!config) { + SNDERR("invalid cmdline, expected pcm(%s):card(%s):dev(%s):config(%s) from %s", + pcm, card, dev, config, tplg); + return -EINVAL; + } + + cmd_item->pcm = atoi(pcm); + strncpy(cmd_item->card_name, card, sizeof(cmd_item->card_name)); + strncpy(cmd_item->dev_name, dev, sizeof(cmd_item->dev_name)); + strncpy(cmd_item->config_name, config, sizeof(cmd_item->config_name)); + + /* + * dev name is special, we cant use "," in the command line + * so need to replace it with a "." and then later change it + * back to "," + */ + for (i = 0; i < sizeof(cmd_item->dev_name); i++) { + if (cmd_item->dev_name[i] != '.') + continue; + cmd_item->dev_name[i] = ','; + break; + } + + fprintf(stdout, " cmd %d: for pcm %d uses %s with PCM %s:%s\n", + plug->num_cmdline, cmd_item->pcm, cmd_item->config_name, + cmd_item->card_name, cmd_item->dev_name); + + plug->num_cmdline++; + + printf("plug: topology file %s with pipe %ld\n", plug->tplg_file, plug->tplg_pipeline); + return 0; +} + +/* + * Parse the ALSA conf for the SOF plugin and construct the command line options + * to be passed into the SOF pipe executable. + * TODO: verify all args + * TODO: validate all args. + * TODO: contruct sof pipe cmd line. + */ +int plug_parse_conf(snd_sof_plug_t *plug, const char *name, snd_config_t *root, + snd_config_t *conf) +{ + snd_config_iterator_t i, next; + const char *tplg = NULL; + + /* + * The topology filename and topology PCM need to be passed in. + * i.e. aplay -Dsof:tplg:pcm:[card:dev:config]...] + */ + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + + if (snd_config_get_id(n, &id) < 0) + continue; + + /* dont care */ + if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || + strcmp(id, "hint") == 0) + continue; + + /* client command line topology */ + if (strcmp(id, "tplg") == 0) { + if (snd_config_get_string(n, &tplg) < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } else if (!*tplg) { + tplg = NULL; + } + continue; + } + + /* topology PCM configurations */ + if (strcmp(id, "config") == 0) { + if (parse_slave_configs(plug, n)) + return -EINVAL; + continue; + } + + /* not fatal - carry on and verify later */ + SNDERR("Unknown field %s", id); + } + + /* verify mandatory inputs are specified */ + if (!tplg) { + SNDERR("Missing topology topology"); + return -EINVAL; + } + + /* parse the client command line */ + if (parse_client_cmdline(plug, (char *)tplg)) { + SNDERR("invalid sof cmd line"); + return -EINVAL; + } + + return 0; +} diff --git a/tools/plugin/alsaplug/plugin.h b/tools/plugin/alsaplug/plugin.h new file mode 100644 index 000000000000..d0f6c85a1653 --- /dev/null +++ b/tools/plugin/alsaplug/plugin.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022-2023 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOF_PLUGIN_PLUGIN_H__ +#define __SOF_PLUGIN_PLUGIN_H__ + +#include +#include +#include "common.h" + +#include + +#define PLUG_MAX_CONFIG 128 + +typedef struct snd_sof_plug { + /* conf data */ + char *device; + + /* topology info */ + char *tplg_file; + long tplg_pipeline; // HACK, use configs + + /* number of configurations in plugin conf */ + struct plug_config config[PLUG_MAX_CONFIG]; + int num_configs; + + /* command line arguments */ + struct plug_cmdline_item cmdline[PLUG_MAX_CONFIG]; + int num_cmdline; + + /* topology */ + struct tplg_context tplg; + struct list_item widget_list; + struct list_item route_list; + struct list_item pcm_list; + struct list_item pipeline_list; + int instance_ids[SND_SOC_TPLG_DAPM_LAST]; + struct plug_mq_desc ipc_tx; + struct plug_mq_desc ipc_rx; + + int pcm_id; + struct tplg_pcm_info *pcm_info; + + snd_pcm_uframes_t period_size; + + void *module_prv; /* module private data */ +} snd_sof_plug_t; + +/* + * ALSA Conf + */ +int sofplug_load_hook(snd_config_t *root, snd_config_t *config, + snd_config_t **dst, snd_config_t *private_data); + +int plug_parse_conf(snd_sof_plug_t *plug, const char *name, + snd_config_t *root, snd_config_t *conf); +int plug_parse_topology(snd_sof_plug_t *plug); +int plug_set_up_pipelines(snd_sof_plug_t *plug, int dir); +int plug_free_pipelines(snd_sof_plug_t *plug, struct tplg_pipeline_list *pipeline_list, int dir); +void plug_free_topology(snd_sof_plug_t *plug); + +#endif diff --git a/tools/plugin/alsaplug/tplg.c b/tools/plugin/alsaplug/tplg.c new file mode 100644 index 000000000000..5b67b47aedfc --- /dev/null +++ b/tools/plugin/alsaplug/tplg.c @@ -0,0 +1,1479 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Ranjani Sridharan +// Liam Girdwood + +/* Topology loader to set up components and pipeline */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include "plugin.h" + +#define FILE_READ 0 +#define FILE_WRITE 1 + +#define MAX_TPLG_OBJECT_SIZE 4096 + +//#include + +/* temporary - current MAXLEN is not define in UAPI header - fix pending */ +#ifndef SNDRV_CTL_ELEM_ID_NAME_MAXLEN +#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN 44 +#endif +#include + +#define SOF_IPC4_FW_PAGE(x) ((((x) + BIT(12) - 1) & ~(BIT(12) - 1)) >> 12) +#define SOF_IPC4_FW_ROUNDUP(x) (((x) + BIT(6) - 1) & (~(BIT(6) - 1))) +#define SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE 12 +#define SOF_IPC4_PIPELINE_OBJECT_SIZE 448 +#define SOF_IPC4_DATA_QUEUE_OBJECT_SIZE 128 +#define SOF_IPC4_LL_TASK_OBJECT_SIZE 72 +#define SOF_IPC4_LL_TASK_LIST_ITEM_SIZE 12 +#define SOF_IPC4_FW_MAX_QUEUE_COUNT 8 + +static const struct sof_topology_token ipc4_comp_tokens[] = { + {SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, tplg_token_get_uint32_t, + offsetof(struct ipc4_base_module_cfg, is_pages)}, +}; + +static int plug_parse_ipc4_comp_tokens(snd_sof_plug_t *plug, struct ipc4_base_module_cfg *base_cfg) +{ + struct tplg_context *ctx = &plug->tplg; + struct tplg_comp_info *comp_info = ctx->current_comp_info; + struct snd_soc_tplg_vendor_array *array = &ctx->widget->priv.array[0]; + int size = ctx->widget->priv.size; + int ret; + + ret = sof_parse_token_sets(base_cfg, ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens), + array, size, 1, 0); + if (ret < 0) + return ret; + + return sof_parse_tokens(&comp_info->uuid, comp_ext_tokens, + ARRAY_SIZE(comp_ext_tokens), array, size); +} + +static void plug_setup_widget_ipc_msg(struct tplg_comp_info *comp_info) +{ + struct ipc4_module_init_instance *module_init = &comp_info->module_init; + + module_init->primary.r.type = SOF_IPC4_MOD_INIT_INSTANCE; + module_init->primary.r.module_id = comp_info->module_id; + module_init->primary.r.instance_id = comp_info->instance_id; + module_init->primary.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_MODULE_MSG; + module_init->primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST; +} + +static int plug_aif_in_out(snd_sof_plug_t *plug, int dir) +{ + struct tplg_context *ctx = &plug->tplg; + struct tplg_comp_info *comp_info = ctx->current_comp_info; + int ret; + + ret = tplg_parse_widget_audio_formats(ctx); + if (ret < 0) + return ret; + + comp_info->ipc_payload = calloc(sizeof(struct ipc4_base_module_cfg), 1); + if (!comp_info->ipc_payload) + return -ENOMEM; + + comp_info->ipc_size = sizeof(struct ipc4_base_module_cfg); + + if (dir == SOF_IPC_STREAM_PLAYBACK) { + comp_info->module_id = 0x96; + plug_setup_widget_ipc_msg(comp_info); + } else { + comp_info->module_id = 0x98; + plug_setup_widget_ipc_msg(comp_info); + } + + return 0; +} + +static int plug_dai_in_out(snd_sof_plug_t *plug, int dir) +{ + struct tplg_context *ctx = &plug->tplg; + struct tplg_comp_info *comp_info = ctx->current_comp_info; + int ret; + + ret = tplg_parse_widget_audio_formats(ctx); + if (ret < 0) + return ret; + + comp_info->ipc_payload = calloc(sizeof(struct ipc4_base_module_cfg), 1); + if (!comp_info->ipc_payload) + return -ENOMEM; + + comp_info->ipc_size = sizeof(struct ipc4_base_module_cfg); + + if (dir == SOF_IPC_STREAM_PLAYBACK) { + comp_info->module_id = 0x97; + plug_setup_widget_ipc_msg(comp_info); + } else { + comp_info->module_id = 0x99; + plug_setup_widget_ipc_msg(comp_info); + } + + return 0; +} + +static int plug_new_src_ipc(snd_sof_plug_t *plug) +{ + struct tplg_context *ctx = &plug->tplg; + char tplg_object[MAX_TPLG_OBJECT_SIZE] = {0}; + struct sof_ipc_comp_src *src = + (struct sof_ipc_comp_src *)tplg_object; + struct snd_soc_tplg_ctl_hdr *tplg_ctl; + int ret; + + tplg_ctl = calloc(ctx->hdr->payload_size, 1); + if (!tplg_ctl) + return -ENOMEM; + + ret = tplg_new_src(ctx, &src->comp, MAX_TPLG_OBJECT_SIZE, + tplg_ctl, ctx->hdr->payload_size); + if (ret < 0) { + SNDERR("error: failed to create src\n"); + goto out; + } + +out: + free(tplg_ctl); + return ret; +} + +static int plug_new_asrc_ipc(snd_sof_plug_t *plug) +{ + struct tplg_context *ctx = &plug->tplg; + char tplg_object[MAX_TPLG_OBJECT_SIZE] = {0}; + struct sof_ipc_comp_asrc *asrc = + (struct sof_ipc_comp_asrc *)tplg_object; + struct snd_soc_tplg_ctl_hdr *tplg_ctl; + int ret; + + tplg_ctl = calloc(ctx->hdr->payload_size, 1); + if (!tplg_ctl) + return -ENOMEM; + + ret = tplg_new_asrc(ctx, &asrc->comp, MAX_TPLG_OBJECT_SIZE, + tplg_ctl, ctx->hdr->payload_size); + if (ret < 0) { + SNDERR("error: failed to create PGA\n"); + goto out; + } + +out: + free(tplg_ctl); + return ret; +} + +static int plug_new_mixer(snd_sof_plug_t *plug) +{ + struct tplg_context *ctx = &plug->tplg; + struct tplg_comp_info *comp_info = ctx->current_comp_info; + char tplg_object[MAX_TPLG_OBJECT_SIZE] = {0}; + struct sof_ipc_comp_mixer *mixer = + (struct sof_ipc_comp_mixer *)tplg_object; + struct snd_soc_tplg_ctl_hdr *tplg_ctl; + int ret; + + tplg_ctl = calloc(ctx->hdr->payload_size, 1); + if (!tplg_ctl) + return -ENOMEM; + + comp_info->instance_id = plug->instance_ids[SND_SOC_TPLG_DAPM_MIXER]++; + comp_info->ipc_size = sizeof(struct ipc4_base_module_cfg); + comp_info->ipc_payload = calloc(comp_info->ipc_size, 1); + if (!comp_info->ipc_payload) + return -ENOMEM; + + ret = tplg_new_mixer(ctx, &mixer->comp, MAX_TPLG_OBJECT_SIZE, + tplg_ctl, ctx->hdr->payload_size); + if (ret < 0) { + SNDERR("error: failed to create mixer\n"); + goto out; + } + + if (strstr(comp_info->name, "mixin")) { + comp_info->module_id = 0x2; + plug_setup_widget_ipc_msg(comp_info); + } else { + comp_info->module_id = 0x3; + plug_setup_widget_ipc_msg(comp_info); + } +out: + free(tplg_ctl); + return ret; +} + +static int plug_new_pga(snd_sof_plug_t *plug) +{ + struct tplg_context *ctx = &plug->tplg; + struct tplg_comp_info *comp_info = ctx->current_comp_info; + struct ipc4_peak_volume_config volume; + struct snd_soc_tplg_ctl_hdr *tplg_ctl; + int ret; + + comp_info->ipc_size = + sizeof(struct ipc4_peak_volume_config) + sizeof(struct ipc4_base_module_cfg); + comp_info->ipc_payload = calloc(comp_info->ipc_size, 1); + if (!comp_info->ipc_payload) + return -ENOMEM; + + /* FIXME: move this to when the widget is actually set up */ + comp_info->instance_id = plug->instance_ids[SND_SOC_TPLG_DAPM_PGA]++; + comp_info->module_id = 0x6; + + tplg_ctl = calloc(ctx->hdr->payload_size, 1); + if (!tplg_ctl) { + free(comp_info->ipc_payload); + return -ENOMEM; + } + + ret = tplg_new_pga(ctx, &volume, sizeof(struct ipc4_peak_volume_config), + tplg_ctl, ctx->hdr->payload_size); + if (ret < 0) { + SNDERR("%s: failed to create PGA\n", __func__); + goto out; + } + + /* copy volume data to ipc_payload */ + memcpy(comp_info->ipc_payload + sizeof(struct ipc4_base_module_cfg), + &volume, sizeof(struct ipc4_peak_volume_config)); + + /* skip kcontrols for now */ + if (tplg_create_controls(ctx, ctx->widget->num_kcontrols, + tplg_ctl, ctx->hdr->payload_size, &volume) < 0) { + SNDERR("error: loading controls\n"); + goto out; + } + + plug_setup_widget_ipc_msg(comp_info); + + free(tplg_ctl); + + return ret; + +out: + free(tplg_ctl); + free(comp_info->ipc_payload); + + return ret; +} + +static int plug_new_process(snd_sof_plug_t *plug) +{ + struct tplg_context *ctx = &plug->tplg; + struct tplg_comp_info *comp_info = ctx->current_comp_info; + struct sof_ipc_comp_process *process; + struct snd_soc_tplg_ctl_hdr *tplg_ctl; + int ret; + + process = calloc(MAX_TPLG_OBJECT_SIZE, 1); + if (!process) + return -ENOMEM; + + comp_info->ipc_payload = process; + + tplg_ctl = calloc(ctx->hdr->payload_size, 1); + if (!tplg_ctl) { + free(process); + return -ENOMEM; + } + + ret = tplg_new_process(ctx, process, MAX_TPLG_OBJECT_SIZE, + tplg_ctl, ctx->hdr->payload_size); + if (ret < 0) { + SNDERR("error: failed to create PGA\n"); + goto out; + } +out: + free(tplg_ctl); + return ret; +} + +static int plug_new_pipeline(snd_sof_plug_t *plug) +{ + struct tplg_pipeline_info *pipe_info; + struct sof_ipc_pipe_new pipeline = {0}; + struct snd_soc_tplg_ctl_hdr *tplg_ctl; + struct tplg_context *ctx = &plug->tplg; + int ret; + + tplg_ctl = calloc(ctx->hdr->payload_size, 1); + if (!tplg_ctl) + return -ENOMEM; + + pipe_info = calloc(sizeof(struct tplg_pipeline_info), 1); + if (!pipe_info) { + ret = -ENOMEM; + goto out; + } + + pipe_info->name = strdup(ctx->widget->name); + if (!pipe_info->name) { + free(pipe_info); + goto out; + } + + pipe_info->id = ctx->pipeline_id; + + ret = tplg_new_pipeline(ctx, &pipeline, sizeof(pipeline), tplg_ctl); + if (ret < 0) { + SNDERR("error: failed to create pipeline\n"); + free(pipe_info->name); + free(pipe_info); + goto out; + } + + list_item_append(&pipe_info->item, &plug->pipeline_list); + tplg_debug("loading pipeline %s\n", pipe_info->name); +out: + free(tplg_ctl); + return ret; +} + +static int plug_new_buffer(snd_sof_plug_t *plug) +{ + struct ipc4_copier_module_cfg *copier = calloc(sizeof(struct ipc4_copier_module_cfg), 1); + struct tplg_context *ctx = &plug->tplg; + struct tplg_comp_info *comp_info = ctx->current_comp_info; + int ret; + + if (!copier) + return -ENOMEM; + + comp_info->ipc_payload = copier; + + ret = tplg_new_buffer(ctx, copier, sizeof(copier), NULL, 0); + if (ret < 0) { + SNDERR("error: failed to create pipeline\n"); + free(copier); + } + + return ret; +} + +/* Insert new comp info into the list of widgets */ +static inline int plug_insert_comp(snd_sof_plug_t *plug) +{ + struct tplg_context *ctx = &plug->tplg; + struct tplg_comp_info *comp_info; + int comp_id = ctx->comp_id; + int ret; + + if (ctx->widget->id == SND_SOC_TPLG_DAPM_SCHEDULER) + return 0; + + comp_info = calloc(sizeof(struct tplg_comp_info), 1); + if (!comp_info) + return -ENOMEM; + + comp_info->name = strdup(ctx->widget->name); + if (!comp_info->name) { + ret = -ENOMEM; + goto err; + } + + comp_info->stream_name = strdup(ctx->widget->sname); + if (!comp_info->stream_name) { + ret = -ENOMEM; + goto sname_err; + } + + comp_info->id = comp_id; + comp_info->type = ctx->widget->id; + comp_info->pipeline_id = ctx->pipeline_id; + ctx->current_comp_info = comp_info; + + ret = plug_parse_ipc4_comp_tokens(plug, &comp_info->basecfg); + if (ret < 0) + goto sname_err; + + list_item_append(&comp_info->item, &plug->widget_list); + + tplg_debug("debug: loading comp_id %d: widget %s type %d size %d at offset %ld is_pages %d\n", + comp_id, ctx->widget->name, ctx->widget->id, ctx->widget->size, + ctx->tplg_offset, comp_info->basecfg.is_pages); + + return 0; +sname_err: + free(comp_info->name); +err: + free(comp_info); + return ret; +} + +/* load dapm widget */ +static int plug_load_widget(snd_sof_plug_t *plug) +{ + struct tplg_context *ctx = &plug->tplg; + int ret = 0; + + /* get next widget */ + ctx->widget = tplg_get_widget(ctx); + ctx->widget_size = ctx->widget->size; + + /* insert widget into mapping */ + ret = plug_insert_comp(plug); + if (ret < 0) { + SNDERR("plug_load_widget: invalid widget index\n"); + return ret; + } + + /* load widget based on type */ + switch (ctx->widget->id) { + /* load pga widget */ + case SND_SOC_TPLG_DAPM_PGA: + if (plug_new_pga(plug) < 0) { + SNDERR("error: load pga\n"); + ret = -EINVAL; + goto exit; + } + break; + case SND_SOC_TPLG_DAPM_AIF_IN: + if (plug_aif_in_out(plug, SOF_IPC_STREAM_PLAYBACK) < 0) { + SNDERR("error: load AIF IN failed\n"); + ret = -EINVAL; + goto exit; + } + break; + case SND_SOC_TPLG_DAPM_AIF_OUT: + if (plug_aif_in_out(plug, SOF_IPC_STREAM_CAPTURE) < 0) { + SNDERR("error: load AIF OUT failed\n"); + ret = -EINVAL; + goto exit; + } + break; + case SND_SOC_TPLG_DAPM_DAI_IN: + if (plug_dai_in_out(plug, SOF_IPC_STREAM_PLAYBACK) < 0) { + SNDERR("error: load filewrite\n"); + ret = -EINVAL; + goto exit; + } + break; + case SND_SOC_TPLG_DAPM_DAI_OUT: + if (plug_dai_in_out(plug, SOF_IPC_STREAM_CAPTURE) < 0) { + SNDERR("error: load filewrite\n"); + ret = -EINVAL; + goto exit; + } + break; + + case SND_SOC_TPLG_DAPM_BUFFER: + if (plug_new_buffer(plug) < 0) { + SNDERR("error: load pipeline\n"); + ret = -EINVAL; + goto exit; + } + break; + + case SND_SOC_TPLG_DAPM_SCHEDULER: + if (plug_new_pipeline(plug) < 0) { + SNDERR("error: load pipeline\n"); + ret = -EINVAL; + goto exit; + } + break; + case SND_SOC_TPLG_DAPM_SRC: + if (plug_new_src_ipc(plug) < 0) { + SNDERR("error: load src\n"); + ret = -EINVAL; + goto exit; + } + break; + case SND_SOC_TPLG_DAPM_ASRC: + if (plug_new_asrc_ipc(plug) < 0) { + SNDERR("error: load asrc\n"); + ret = -EINVAL; + goto exit; + } + break; + + case SND_SOC_TPLG_DAPM_MIXER: + if (plug_new_mixer(plug) < 0) { + SNDERR("error: load mixer\n"); + ret = -EINVAL; + goto exit; + } + break; + case SND_SOC_TPLG_DAPM_EFFECT: + if (plug_new_process(plug) < 0) { + SNDERR("error: load effect\n"); + ret = -EINVAL; + goto exit; + } + break; + + /* unsupported widgets */ + default: + tplg_debug("info: Widget %s id %d unsupported and skipped: size %d priv size %d\n", + ctx->widget->name, ctx->widget->id, + ctx->widget->size, ctx->widget->priv.size); + +#if 0 + if (fseek(ctx->file, ctx->widget->priv.size, SEEK_CUR)) { + SNDERR("error: fseek unsupported widget\n"); + ret = -errno; + goto exit; + } + ret = tplg_create_controls(ctx->widget->num_kcontrols, ctx->file, NULL, 0); + if (ret < 0) { + SNDERR("error: loading controls\n"); + //goto exit; + } +#endif + ret = 0; + break; + } + + ret = 1; + +exit: + return ret; +} + +static int plug_register_graph(snd_sof_plug_t *plug, int count) +{ + struct tplg_context *ctx = &plug->tplg; + int ret = 0; + int i; + + for (i = 0; i < count; i++) { + ret = tplg_parse_graph(ctx, &plug->widget_list, &plug->route_list); + if (ret < 0) + return ret; + } + + return ret; +} + +static int plug_parse_pcm(snd_sof_plug_t *plug, int count) +{ + struct tplg_context *ctx = &plug->tplg; + int ret, i; + + for (i = 0; i < count; i++) { + ret = tplg_parse_pcm(ctx, &plug->widget_list, &plug->pcm_list); + if (ret < 0) + return ret; + } + + return 0; +} + +static void +plug_pipeline_update_resource_usage(snd_sof_plug_t *plug, struct tplg_comp_info *comp_info) +{ + struct ipc4_base_module_cfg *base_config = &comp_info->basecfg; + struct tplg_pipeline_info *pipe_info = comp_info->pipe_info; + int task_mem, queue_mem; + int ibs, bss, total; + + ibs = base_config->ibs; + bss = base_config->is_pages; + + task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE; + task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss; + + /* LL modules */ + task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE); + task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE; + task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE; + + ibs = SOF_IPC4_FW_ROUNDUP(ibs); + queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE + ibs); + + total = SOF_IPC4_FW_PAGE(task_mem + queue_mem); + + pipe_info->mem_usage += total; +} + +static int plug_is_single_format(struct sof_ipc4_pin_format *fmts, int num_formats) +{ + struct sof_ipc4_pin_format *fmt = &fmts[0]; + uint32_t _rate, _channels, _valid_bits; + int i; + + _rate = fmt->audio_fmt.sampling_frequency; + _channels = fmt->audio_fmt.fmt_cfg & MASK(7, 0); + _valid_bits = (fmt->audio_fmt.fmt_cfg & MASK(15, 8)) >> 8; + for (i = 1; i < num_formats; i++) { + struct sof_ipc4_pin_format *fmt = &fmts[i]; + uint32_t rate, channels, valid_bits; + + rate = fmt->audio_fmt.sampling_frequency; + channels = fmt->audio_fmt.fmt_cfg & MASK(7, 0); + valid_bits = (fmt->audio_fmt.fmt_cfg & MASK(15, 8)) >> 8; + if (rate != _rate || channels != _channels || valid_bits != _valid_bits) + return false; + } + + return true; +} + +static int plug_match_audio_format(snd_sof_plug_t *plug, struct tplg_comp_info *comp_info, + struct plug_config *config) +{ + struct sof_ipc4_available_audio_format *available_fmt = &comp_info->available_fmt; + struct ipc4_base_module_cfg *base_cfg = &comp_info->basecfg; + struct sof_ipc4_pin_format *fmt; + int config_valid_bits; + int i; + + switch (config->format) { + case SND_PCM_FORMAT_S16_LE: + config_valid_bits = 16; + break; + case SND_PCM_FORMAT_S32_LE: + config_valid_bits = 32; + break; + case SND_PCM_FORMAT_S24_LE: + config_valid_bits = 24; + break; + default: + break; + } + + if (plug_is_single_format(available_fmt->input_pin_fmts, + available_fmt->num_input_formats)) { + fmt = &available_fmt->input_pin_fmts[0]; + goto out; + } + + for (i = 0; i < available_fmt->num_input_formats; i++) { + uint32_t rate, channels, valid_bits; + + fmt = &available_fmt->input_pin_fmts[i]; + + rate = fmt->audio_fmt.sampling_frequency; + channels = fmt->audio_fmt.fmt_cfg & MASK(7, 0); + valid_bits = (fmt->audio_fmt.fmt_cfg & MASK(15, 8)) >> 8; + + if (rate == config->rate && channels == config->channels && + valid_bits == config_valid_bits) + break; + } + + if (i == available_fmt->num_input_formats) { + SNDERR("Cannot find matching format for rate %d channels %d valid_bits %d for %s\n", + config->rate, config->channels, config_valid_bits, comp_info->name); + return -EINVAL; + } +out: + + base_cfg->audio_fmt.sampling_frequency = fmt->audio_fmt.sampling_frequency; + base_cfg->audio_fmt.depth = fmt->audio_fmt.bit_depth; + base_cfg->audio_fmt.ch_map = fmt->audio_fmt.ch_map; + base_cfg->audio_fmt.ch_cfg = fmt->audio_fmt.ch_cfg; + base_cfg->audio_fmt.interleaving_style = fmt->audio_fmt.interleaving_style; + base_cfg->audio_fmt.channels_count = fmt->audio_fmt.fmt_cfg & MASK(7, 0); + base_cfg->audio_fmt.valid_bit_depth = + (fmt->audio_fmt.fmt_cfg & MASK(15, 8)) >> 8; + base_cfg->audio_fmt.s_type = + (fmt->audio_fmt.fmt_cfg & MASK(23, 16)) >> 16; + base_cfg->ibs = fmt->buffer_size; + + /* + * FIXME: is this correct? Choose ALSA period size for obs so that the buffer sizes + * will set accodingly. Need to get channel count and format from output format + */ + base_cfg->obs = plug->period_size * 2 * 2; + + return 0; +} + +static int plug_set_up_widget_base_config(snd_sof_plug_t *plug, struct tplg_comp_info *comp_info) +{ + struct plug_cmdline_item *cmd_item = &plug->cmdline[0]; + struct plug_config *config; + bool config_found = false; + int ret, i; + + for (i < 0; i < plug->num_configs; i++) { + config = &plug->config[i]; + + if (!strcmp(config->name, cmd_item->config_name)) { + config_found = true; + break; + } + } + + if (!config_found) { + SNDERR("unsupported config requested %s\n", cmd_item->config_name); + return -ENOTSUP; + } + + /* match audio formats and populate base config */ + ret = plug_match_audio_format(plug, comp_info, config); + if (ret < 0) + return ret; + + /* copy the basecfg into the ipc payload */ + memcpy(comp_info->ipc_payload, &comp_info->basecfg, sizeof(struct ipc4_base_module_cfg)); + + return 0; +} + +/* parse topology file and set up pipeline */ +int plug_parse_topology(snd_sof_plug_t *plug) + +{ + struct tplg_context *ctx = &plug->tplg; + struct snd_soc_tplg_hdr *hdr; + struct list_item *item; + char pipeline_string[256] = {0}; + int i; + int ret = 0; + FILE *file; + size_t size; + + tplg_debug("parsing topology file %s\n", ctx->tplg_file); + + /* TODO: ctl callback */ +// ctx->ctl_arg = sp; +// ctx->ctl_cb = pipe_kcontrol_cb_new; + + /* open topology file */ + file = fopen(ctx->tplg_file, "rb"); + if (!file) { + SNDERR("error: can't open topology %s : %s\n", ctx->tplg_file, strerror(errno)); + return -errno; + } + + /* file size */ + if (fseek(file, 0, SEEK_END)) { + SNDERR("error: can't seek to end of topology: %s\n", strerror(errno)); + fclose(file); + return -errno; + } + ctx->tplg_size = ftell(file); + if (fseek(file, 0, SEEK_SET)) { + SNDERR("error: can't seek to beginning of topology: %s\n", strerror(errno)); + fclose(file); + return -errno; + } + + /* load whole topology into memory */ + ctx->tplg_base = calloc(ctx->tplg_size, 1); + if (!ctx->tplg_base) { + SNDERR("error: can't alloc buffer for topology %zu bytes\n", ctx->tplg_size); + fclose(file); + return -ENOMEM; + } + ret = fread(ctx->tplg_base, ctx->tplg_size, 1, file); + if (ret != 1) { + SNDERR("error: can't read topology: %s\n", + strerror(errno)); + fclose(file); + return -errno; + } + fclose(file); + + /* initialize widget, route, pipeline and pcm lists */ + list_init(&plug->widget_list); + list_init(&plug->route_list); + list_init(&plug->pcm_list); + list_init(&plug->pipeline_list); + + while (ctx->tplg_offset < ctx->tplg_size) { + /* read next topology header */ + hdr = tplg_get_hdr(ctx); + + tplg_debug("type: %x, size: 0x%x count: %d index: %d\n", + hdr->type, hdr->payload_size, hdr->count, hdr->index); + + ctx->hdr = hdr; + + /* parse header and load the next block based on type */ + switch (hdr->type) { + /* load dapm widget */ + case SND_SOC_TPLG_TYPE_DAPM_WIDGET: + tplg_debug("number of DAPM widgets %d\n", hdr->count); + + /* update max pipeline_id */ + ctx->pipeline_id = hdr->index; + + for (i = 0; i < hdr->count; i++) { + ret = plug_load_widget(plug); + if (ret < 0) { + SNDERR("error: loading widget\n"); + return ret; + } + ctx->comp_id++; + } + break; + /* set up component connections from pipeline graph */ + case SND_SOC_TPLG_TYPE_DAPM_GRAPH: + if (plug_register_graph(plug, hdr->count) < 0) { + SNDERR("error: pipeline graph\n"); + return -EINVAL; + } + break; + /* parse PCM info */ + case SND_SOC_TPLG_TYPE_PCM: + ret = plug_parse_pcm(plug, hdr->count); + if (ret < 0) + goto out; + break; + default: + tplg_debug("%s %d\n", __func__, __LINE__); + tplg_skip_hdr_payload(ctx); + break; + } + } + + /* assign pipeline to every widget in the widget list */ + list_for_item(item, &plug->widget_list) { + struct tplg_comp_info *comp_info = container_of(item, struct tplg_comp_info, item); + struct list_item *pipe_item; + + list_for_item(pipe_item, &plug->pipeline_list) { + struct tplg_pipeline_info *pipe_info; + + pipe_info = container_of(pipe_item, struct tplg_pipeline_info, item); + if (pipe_info->id == comp_info->pipeline_id) { + comp_info->pipe_info = pipe_info; + break; + } + } + + if (!comp_info->pipe_info) { + SNDERR("Error assigning pipeline for %s\n", comp_info->name); + return -EINVAL; + } + } +out: + return ret; +} + +static int plug_set_up_widget_ipc(snd_sof_plug_t *plug, struct tplg_comp_info *comp_info) +{ + struct ipc4_module_init_instance *module_init = &comp_info->module_init; + struct ipc4_message_reply reply; + void *msg; + int size, ret; + + module_init->extension.r.param_block_size = comp_info->ipc_size >> 2; + module_init->extension.r.ppl_instance_id = comp_info->pipe_info->instance_id; + + size = sizeof(*module_init) + comp_info->ipc_size; + msg = calloc(size, 1); + if (!msg) + return -ENOMEM; + + memcpy(msg, module_init, sizeof(*module_init)); + memcpy(msg + sizeof(*module_init), comp_info->ipc_payload, comp_info->ipc_size); + + ret = plug_mq_cmd_tx_rx(&plug->ipc_tx, &plug->ipc_rx, + msg, size, &reply, sizeof(reply)); + free(msg); + if (ret < 0) { + SNDERR("error: can't set up widget %s\n", comp_info->name); + return ret; + } + + if (reply.primary.r.status != IPC4_SUCCESS) { + SNDERR("widget %s set up failed with status %d\n", + comp_info->name, reply.primary.r.status); + return -EINVAL; + } + return 0; +} + +static int plug_set_up_pipeline(snd_sof_plug_t *plug, struct tplg_pipeline_info *pipe_info) +{ + struct ipc4_pipeline_create msg; + struct ipc4_message_reply reply; + int ret; + + msg.primary.r.type = SOF_IPC4_GLB_CREATE_PIPELINE; + msg.primary.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG; + msg.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST; + pipe_info->instance_id = plug->instance_ids[SND_SOC_TPLG_DAPM_SCHEDULER]++; + msg.primary.r.instance_id = pipe_info->instance_id; + msg.primary.r.ppl_mem_size = pipe_info->mem_usage; + + ret = plug_mq_cmd_tx_rx(&plug->ipc_tx, &plug->ipc_rx, + &msg, sizeof(msg), &reply, sizeof(reply)); + if (ret < 0) { + SNDERR("error: can't set up pipeline %s\n", pipe_info->name); + return ret; + } + + if (reply.primary.r.status != IPC4_SUCCESS) { + SNDERR("pipeline %s instance ID %d set up failed with status %d\n", + pipe_info->name, pipe_info->instance_id, reply.primary.r.status); + return -EINVAL; + } + + tplg_debug("pipeline %s instance_id %d mem_usage %d set up\n", pipe_info->name, + pipe_info->instance_id, pipe_info->mem_usage); + + return 0; +} + +static int plug_prepare_widget(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_info, + struct tplg_comp_info *comp_info, int dir) +{ + struct tplg_pipeline_list *pipeline_list; + int ret, i; + + if (dir) + pipeline_list = &pcm_info->capture_pipeline_list; + else + pipeline_list = &pcm_info->playback_pipeline_list; + + /* populate base config */ + ret = plug_set_up_widget_base_config(plug, comp_info); + if (ret < 0) + return ret; + + plug_pipeline_update_resource_usage(plug, comp_info); + + /* add pipeline to pcm pipeline_list if needed */ + for (i = 0; i < pipeline_list->count; i++) { + struct tplg_pipeline_info *pipe_info = pipeline_list->pipelines[i]; + + if (pipe_info == comp_info->pipe_info) + break; + } + + if (i == pipeline_list->count) { + pipeline_list->pipelines[pipeline_list->count] = comp_info->pipe_info; + pipeline_list->count++; + } + + tplg_debug("widget %s prepared\n", comp_info->name); + return 0; +} + +static int plug_prepare_widgets(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_info, + struct tplg_comp_info *starting_comp_info, + struct tplg_comp_info *current_comp_info) +{ + struct list_item *item; + int ret; + + /* for playback */ + list_for_item(item, &plug->route_list) { + struct tplg_route_info *route_info = container_of(item, struct tplg_route_info, + item); + + if (route_info->source != current_comp_info) + continue; + + /* set up source widget if it is the starting widget */ + if (starting_comp_info == current_comp_info) { + ret = plug_prepare_widget(plug, pcm_info, current_comp_info, 0); + if (ret < 0) + return ret; + } + + /* set up the sink widget */ + ret = plug_prepare_widget(plug, pcm_info, route_info->sink, 0); + if (ret < 0) + return ret; + + /* and then continue down the path */ + if (route_info->sink->type != SND_SOC_TPLG_DAPM_DAI_IN || + route_info->sink->type != SND_SOC_TPLG_DAPM_DAI_OUT) { + ret = plug_prepare_widgets(plug, pcm_info, starting_comp_info, + route_info->sink); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static int plug_prepare_widgets_capture(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_info, + struct tplg_comp_info *starting_comp_info, + struct tplg_comp_info *current_comp_info) +{ + struct list_item *item; + int ret; + + /* for playback */ + list_for_item(item, &plug->route_list) { + struct tplg_route_info *route_info = container_of(item, struct tplg_route_info, + item); + + if (route_info->sink != current_comp_info) + continue; + + /* set up sink widget if it is the starting widget */ + if (starting_comp_info == current_comp_info) { + ret = plug_prepare_widget(plug, pcm_info, current_comp_info, 1); + if (ret < 0) + return ret; + } + + /* set up the source widget */ + ret = plug_prepare_widget(plug, pcm_info, route_info->source, 1); + if (ret < 0) + return ret; + + /* and then continue up the path */ + if (route_info->source->type != SND_SOC_TPLG_DAPM_DAI_IN && + route_info->source->type != SND_SOC_TPLG_DAPM_DAI_OUT) { + ret = plug_prepare_widgets(plug, pcm_info, starting_comp_info, + route_info->source); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static int plug_set_up_route(snd_sof_plug_t *plug, struct tplg_route_info *route_info) +{ + struct tplg_comp_info *src_comp_info = route_info->source; + struct tplg_comp_info *sink_comp_info = route_info->sink; + struct ipc4_module_bind_unbind bu; + struct ipc4_message_reply reply; + int ret; + + bu.primary.r.module_id = src_comp_info->module_id; + bu.primary.r.instance_id = src_comp_info->instance_id; + bu.primary.r.type = SOF_IPC4_MOD_BIND; + bu.primary.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_MODULE_MSG; + bu.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST; + + bu.extension.r.dst_module_id = sink_comp_info->module_id; + bu.extension.r.dst_instance_id = sink_comp_info->instance_id; + + /* FIXME: assign queue ID for components with multiple inputs/outputs */ + bu.extension.r.dst_queue = 0; + bu.extension.r.src_queue = 0; + + ret = plug_mq_cmd_tx_rx(&plug->ipc_tx, &plug->ipc_rx, + &bu, sizeof(bu), &reply, sizeof(reply)); + if (ret < 0) { + SNDERR("error: can't set up route %s -> %s\n", src_comp_info->name, + sink_comp_info->name); + return ret; + } + + if (reply.primary.r.status != IPC4_SUCCESS) { + SNDERR("route %s -> %s ID set up failed with status %d\n", + src_comp_info->name, sink_comp_info->name, reply.primary.r.status); + return -EINVAL; + } + + tplg_debug("route %s -> %s set up\n", src_comp_info->name, sink_comp_info->name); + + return 0; +} + +static int plug_set_up_widget(snd_sof_plug_t *plug, struct tplg_comp_info *comp_info) +{ + struct tplg_pipeline_info *pipe_info = comp_info->pipe_info; + int ret; + + pipe_info->usage_count++; + + /* first set up pipeline if needed, only done once for the first pipeline widget */ + if (pipe_info->usage_count == 1) { + ret = plug_set_up_pipeline(plug, pipe_info); + if (ret < 0) { + pipe_info->usage_count--; + return ret; + } + } + + /* now set up the widget */ + ret = plug_set_up_widget_ipc(plug, comp_info); + if (ret < 0) + return ret; + + tplg_debug("widget %s set up\n", comp_info->name); + + return 0; +} + +static int plug_set_up_widgets(snd_sof_plug_t *plug, struct tplg_comp_info *starting_comp_info, + struct tplg_comp_info *current_comp_info) +{ + struct list_item *item; + int ret; + + /* for playback */ + list_for_item(item, &plug->route_list) { + struct tplg_route_info *route_info = container_of(item, struct tplg_route_info, + item); + + if (route_info->source != current_comp_info) + continue; + + /* set up source widget if it is the starting widget */ + if (starting_comp_info == current_comp_info) { + ret = plug_set_up_widget(plug, current_comp_info); + if (ret < 0) + return ret; + } + + /* set up the sink widget */ + ret = plug_set_up_widget(plug, route_info->sink); + if (ret < 0) + return ret; + + /* source and sink widgets are up, so set up route now */ + ret = plug_set_up_route(plug, route_info); + if (ret < 0) + return ret; + + /* and then continue down the path */ + if (route_info->sink->type != SND_SOC_TPLG_DAPM_DAI_IN || + route_info->sink->type != SND_SOC_TPLG_DAPM_DAI_OUT) { + ret = plug_set_up_widgets(plug, starting_comp_info, route_info->sink); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static int plug_set_up_widgets_capture(snd_sof_plug_t *plug, + struct tplg_comp_info *starting_comp_info, + struct tplg_comp_info *current_comp_info) +{ + struct list_item *item; + int ret; + + /* for playback */ + list_for_item(item, &plug->route_list) { + struct tplg_route_info *route_info = container_of(item, struct tplg_route_info, + item); + + if (route_info->sink != current_comp_info) + continue; + + /* set up source widget if it is the starting widget */ + if (starting_comp_info == current_comp_info) { + ret = plug_set_up_widget(plug, current_comp_info); + if (ret < 0) + return ret; + } + + /* set up the sink widget */ + ret = plug_set_up_widget(plug, route_info->source); + if (ret < 0) + return ret; + + /* source and sink widgets are up, so set up route now */ + ret = plug_set_up_route(plug, route_info); + if (ret < 0) + return ret; + + /* and then continue down the path */ + if (route_info->source->type != SND_SOC_TPLG_DAPM_DAI_IN && + route_info->source->type != SND_SOC_TPLG_DAPM_DAI_OUT) { + ret = plug_set_up_widgets(plug, starting_comp_info, route_info->source); + if (ret < 0) + return ret; + } + } + + return 0; +} + +int plug_set_up_pipelines(snd_sof_plug_t *plug, int dir) +{ + struct tplg_comp_info *host = NULL; + struct tplg_pcm_info *pcm_info; + struct list_item *item; + int ret; + + list_for_item(item, &plug->pcm_list) { + pcm_info = container_of(item, struct tplg_pcm_info, item); + + if (pcm_info->id == plug->pcm_id) { + if (dir) + host = pcm_info->capture_host; + else + host = pcm_info->playback_host; + break; + } + } + + if (!host) { + SNDERR("No host component found for PCM ID: %d\n", plug->pcm_id); + return -EINVAL; + } + + plug->pcm_info = pcm_info; + + if (dir) { + ret = plug_prepare_widgets_capture(plug, pcm_info, host, host); + if (ret < 0) + return ret; + + ret = plug_set_up_widgets_capture(plug, host, host); + if (ret < 0) + return ret; + + tplg_debug("Setting up capture pipelines complete\n"); + + return 0; + } + + ret = plug_prepare_widgets(plug, pcm_info, host, host); + if (ret < 0) + return ret; + + ret = plug_set_up_widgets(plug, host, host); + if (ret < 0) + return ret; + + tplg_debug("Setting up playback pipelines complete\n"); + + return 0; +} + +static int plug_delete_pipeline(snd_sof_plug_t *plug, struct tplg_pipeline_info *pipe_info) +{ + struct ipc4_pipeline_delete msg; + struct ipc4_message_reply reply; + int ret; + + msg.primary.r.type = SOF_IPC4_GLB_DELETE_PIPELINE; + msg.primary.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG; + msg.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST; + msg.primary.r.instance_id = pipe_info->instance_id; + + ret = plug_mq_cmd_tx_rx(&plug->ipc_tx, &plug->ipc_rx, + &msg, sizeof(msg), &reply, sizeof(reply)); + if (ret < 0) { + SNDERR("error: can't delete pipeline %s\n", pipe_info->name); + return ret; + } + + if (reply.primary.r.status != IPC4_SUCCESS) { + SNDERR("pipeline %s instance ID %d delete failed with status %d\n", + pipe_info->name, pipe_info->instance_id, reply.primary.r.status); + return -EINVAL; + } + + tplg_debug("pipeline %s instance_id %d freed\n", pipe_info->name, + pipe_info->instance_id); + + return 0; +} + +static int plug_free_route(snd_sof_plug_t *plug, struct tplg_route_info *route_info) +{ + struct tplg_comp_info *src_comp_info = route_info->source; + struct tplg_comp_info *sink_comp_info = route_info->sink; + struct ipc4_module_bind_unbind bu; + struct ipc4_message_reply reply; + int ret; + + /* only unbind when widgets belong to separate pipelines */ + if (src_comp_info->pipeline_id == sink_comp_info->pipeline_id) + return 0; + + bu.primary.r.module_id = src_comp_info->module_id; + bu.primary.r.instance_id = src_comp_info->instance_id; + bu.primary.r.type = SOF_IPC4_MOD_UNBIND; + bu.primary.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_MODULE_MSG; + bu.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST; + + bu.extension.r.dst_module_id = sink_comp_info->module_id; + bu.extension.r.dst_instance_id = sink_comp_info->instance_id; + + /* FIXME: assign queue ID for components with multiple inputs/outputs */ + bu.extension.r.dst_queue = 0; + bu.extension.r.src_queue = 0; + + ret = plug_mq_cmd_tx_rx(&plug->ipc_tx, &plug->ipc_rx, + &bu, sizeof(bu), &reply, sizeof(reply)); + if (ret < 0) { + SNDERR("error: can't set up route %s -> %s\n", src_comp_info->name, + sink_comp_info->name); + return ret; + } + + if (reply.primary.r.status != IPC4_SUCCESS) { + SNDERR("route %s -> %s ID set up failed with status %d\n", + src_comp_info->name, sink_comp_info->name, reply.primary.r.status); + return -EINVAL; + } + + tplg_debug("route %s -> %s freed\n", src_comp_info->name, sink_comp_info->name); + + return 0; +} + +static int plug_free_widgets(snd_sof_plug_t *plug, struct tplg_comp_info *starting_comp_info, + struct tplg_comp_info *current_comp_info) +{ + struct list_item *item; + int ret; + + /* for playback */ + list_for_item(item, &plug->route_list) { + struct tplg_route_info *route_info = container_of(item, struct tplg_route_info, + item); + + if (route_info->source != current_comp_info) + continue; + + /* Widgets will be freed when the pipeline is deleted, so just unbind modules */ + ret = plug_free_route(plug, route_info); + if (ret < 0) + return ret; + + /* and then continue down the path */ + if (route_info->sink->type != SND_SOC_TPLG_DAPM_DAI_IN || + route_info->sink->type != SND_SOC_TPLG_DAPM_DAI_OUT) { + ret = plug_free_widgets(plug, starting_comp_info, route_info->sink); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static int plug_free_widgets_capture(snd_sof_plug_t *plug, + struct tplg_comp_info *starting_comp_info, + struct tplg_comp_info *current_comp_info) +{ + struct list_item *item; + int ret; + + /* for playback */ + list_for_item(item, &plug->route_list) { + struct tplg_route_info *route_info = container_of(item, struct tplg_route_info, + item); + + if (route_info->sink != current_comp_info) + continue; + + /* Widgets will be freed when the pipeline is deleted, so just unbind modules */ + ret = plug_free_route(plug, route_info); + if (ret < 0) + return ret; + + /* and then continue down the path */ + if (route_info->sink->type != SND_SOC_TPLG_DAPM_DAI_IN && + route_info->sink->type != SND_SOC_TPLG_DAPM_DAI_OUT) { + ret = plug_free_widgets(plug, starting_comp_info, route_info->source); + if (ret < 0) + return ret; + } + } + + return 0; +} + +int plug_free_pipelines(snd_sof_plug_t *plug, struct tplg_pipeline_list *pipeline_list, int dir) +{ + struct tplg_comp_info *host = NULL; + struct tplg_pcm_info *pcm_info; + struct list_item *item; + int ret, i; + + list_for_item(item, &plug->pcm_list) { + pcm_info = container_of(item, struct tplg_pcm_info, item); + + if (pcm_info->id == plug->pcm_id) { + host = pcm_info->playback_host; /* FIXME */ + break; + } + } + + if (!host) { + SNDERR("No host component found for PCM ID: %d\n", plug->pcm_id); + return -EINVAL; + } + + if (dir) { + } else { + ret = plug_free_widgets(plug, host, host); + if (ret < 0) { + SNDERR("failed to free widgets for PCM %d\n", plug->pcm_id); + return ret; + } + } + + for (i = 0; i < pipeline_list->count; i++) { + struct tplg_pipeline_info *pipe_info = pipeline_list->pipelines[i]; + + ret = plug_delete_pipeline(plug, pipe_info); + if (ret < 0) + return ret; + } + + plug->instance_ids[SND_SOC_TPLG_DAPM_SCHEDULER] = 0; + return 0; +} + +void plug_free_topology(snd_sof_plug_t *plug) +{ + struct list_item *item, *_item; + + list_for_item_safe(item, _item, &plug->pcm_list) { + struct tplg_pcm_info *pcm_info = container_of(item, struct tplg_pcm_info, item); + + free(pcm_info->name); + free(pcm_info); + } + + list_for_item_safe(item, _item, &plug->widget_list) { + struct tplg_comp_info *comp_info = container_of(item, struct tplg_comp_info, item); + + free(comp_info->name); + free(comp_info->stream_name); + free(comp_info->ipc_payload); + free(comp_info); + } + + list_for_item_safe(item, _item, &plug->route_list) { + struct tplg_route_info *route_info = container_of(item, struct tplg_route_info, + item); + + free(route_info); + } + + list_for_item_safe(item, _item, &plug->pipeline_list) { + struct tplg_pipeline_info *pipe_info = container_of(item, struct tplg_pipeline_info, + item); + + free(pipe_info->name); + free(pipe_info); + } + + tplg_debug("freed all pipelines, widgets, routes and pcms\n"); +} diff --git a/tools/plugin/common.c b/tools/plugin/common.c new file mode 100644 index 000000000000..d9bb1c7bb6ba --- /dev/null +++ b/tools/plugin/common.c @@ -0,0 +1,180 @@ +/*-*- linux-c -*-*/ + +/* + * ALSA <-> SOF PCM I/O plugin + * + * Copyright (c) 2022 by Liam Girdwood + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* + * Timing + */ +void plug_timespec_add_ms(struct timespec *ts, unsigned long ms) +{ + long ns; + long secs = ms / 1000; + + /* get ms remainder */ + ms = ms - (secs * 1000); + ns = ms * 1000000; + + ts->tv_nsec += ns; + if (ts->tv_nsec > 1000000000) { + secs++; + ts->tv_nsec -= 1000000000; + } + ts->tv_sec += (secs + DEBUG_TV_SECS); +} + +long plug_timespec_delta_ns(struct timespec *before, struct timespec *after) +{ + long ns; + + ns = (after->tv_sec - before->tv_sec) * 1000000000; + ns += after->tv_nsec - before->tv_nsec; + + return ns; +} + +static const char *suffix_name(const char *longname) +{ + size_t len = strlen(longname); + int i = len; + + /* longname name invalid */ + if (len < 1) { + SNDERR("invalid topology long name\n"); + return NULL; + } + + /* find the last '/' in the longname topology path */ + while (--i >= 0) { + if (longname[i] == '/') { + i += 1; /* skip / */ + return &longname[i]; + } + } + + /* no / in topology path, so use full path */ + return longname; +} + +/* + * IPC + * + * POSIX message queues are used for interprocess IPC messaging. + */ + +/* + * Initialise the IPC object. + */ +int plug_mq_init(struct plug_mq_desc *ipc, const char *tplg, const char *type, int index) +{ + const char *name = suffix_name(tplg); + + if (!name) + return -EINVAL; + + snprintf(ipc->queue_name, NAME_SIZE, "/mq-%s-%s-%d", type, name, index); + return 0; +} + +/* + * Locking + * + * POSIX semaphores are used to block and synchronise audio between + * different threads and processes. + */ + +/* + * Initialise the lock object. + */ +int plug_lock_init(struct plug_sem_desc *lock, const char *tplg, const char *type, int index) +{ + const char *name = suffix_name(tplg); + + if (!name) + return -EINVAL; + + /* semaphores need the leading / */ + snprintf(lock->name, NAME_SIZE, "/lock-%s-%s-%d", name, type, index); + + return 0; +} + +/* + * SHM + * + * Shared memory is used for audio data and audio context sharing between + * threads and processes. + */ + +/* + * Initialise the SHM object. + */ +int plug_shm_init(struct plug_shm_desc *shm, const char *tplg, const char *type, int index) +{ + const char *name = suffix_name(tplg); + + if (!name) + return -EINVAL; + + snprintf(shm->name, NAME_SIZE, "/shm-%s-%s-%d", name, type, index); + shm->size = SHM_SIZE; + + return 0; +} + +/* + * Open an existing shared memory region using the SHM object. + */ +int plug_shm_open(struct plug_shm_desc *shm) +{ + struct stat status; + + /* open SHM to be used for low latency position */ + shm->fd = shm_open(shm->name, O_RDWR, + S_IRWXU | S_IRWXG); + if (shm->fd < 0) { + //SNDERR("failed to open SHM position %s: %s\n", + // shm->name, strerror(errno)); + return -errno; + } + + fstat(shm->fd, &status); + /* map it locally for context readback */ + shm->addr = mmap(NULL, status.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm->fd, 0); + if (!shm->addr) { + SNDERR("failed to mmap SHM position%s: %s\n", shm->name, strerror(errno)); + return -errno; + } + + return 0; +} + diff --git a/tools/plugin/common.h b/tools/plugin/common.h new file mode 100644 index 000000000000..c6e9225567d4 --- /dev/null +++ b/tools/plugin/common.h @@ -0,0 +1,316 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022-2023 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOF_PLUGIN_COMMON_H__ +#define __SOF_PLUGIN_COMMON_H__ + +#include +#include +#include +#include + +/* temporary - current MAXLEN is not define in UAPI header - fix pending */ +#ifndef SNDRV_CTL_ELEM_ID_NAME_MAXLEN +#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN 44 +#endif + +#include + +#define IPC3_MAX_MSG_SIZE 384 +#define NAME_SIZE 256 + +#define MAX_CTLS 256 + +#define MS_TO_US(_msus) (_msus * 1000) +#define MS_TO_NS(_msns) (MS_TO_US(_msns * 1000)) + +#define MS_TO_US(_msus) (_msus * 1000) +#define MS_TO_NS(_msns) (MS_TO_US(_msns * 1000)) + +#define SEM_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) + +#define SHM_SIZE (4096 * 64) /* get from topology - and set for context */ + +#define NUM_EP_CONFIGS 8 + +/* + * Run with valgrind + * valgrind --trace-children=yes aplay -v -Dsof:blah.tplg,1,hw:1,2 -f dat /dev/zero + */ +//#define VALGRIND +#ifdef VALGRIND +#define DEBUG_TV_SECS 10 +#define DEBUG_RETRIES 1000 +#else +#define DEBUG_RETRIES 10 +#define DEBUG_TV_SECS 0 +#endif + +#define SOF_MAGIC "sofpipe" + +enum plugin_state { + SOF_PLUGIN_STATE_INIT = 0, + SOF_PLUGIN_STATE_READY = 1, + SOF_PLUGIN_STATE_DEAD = 2, + SOF_PLUGIN_STATE_STREAM_RUNNING = 3, + SOF_PLUGIN_STATE_STREAM_ERROR = 5, +}; + +struct plug_shm_ctl { + unsigned int comp_id; + unsigned int type; + union { + struct snd_soc_tplg_mixer_control mixer_ctl; + struct snd_soc_tplg_enum_control enum_ctl; + struct snd_soc_tplg_bytes_control bytes_ctl; + }; +}; + +/* + * config.48k2c { + * rate 48000 + * channels 2 + * period_time 0 + * period_frames 6000 + * buffer_time 0 + * buffer_frames 24000 + * } + */ +struct plug_config { + char name[44]; + unsigned long buffer_frames; + unsigned long buffer_time; + unsigned long period_frames; + unsigned long period_time; + int rate; + int channels; + unsigned long format; +}; + +/* + * :[pcm:card:dev:config[pcm:card:dev:config]...] + */ +struct plug_cmdline_item { + int pcm; + char card_name[44]; + char dev_name[44]; + char config_name[44]; +}; + +/* + * Endpoint pipeline configuration + */ +struct endpoint_hw_config { + int pipeline; + char card_name[44]; + char dev_name[44]; + char config_name[44]; + unsigned long buffer_frames; + unsigned long buffer_time; + unsigned long period_frames; + unsigned long period_time; + int rate; + int channels; + unsigned long format; +}; + +struct plug_shm_endpoint { + char magic[8]; /* SOF_MAGIC */ + uint64_t state; + uint32_t pipeline_id; + uint32_t comp_id; + uint32_t idx; + unsigned long rpos; /* current position in ring buffer */ + unsigned long rwrap; + unsigned long wpos; /* current position in ring buffer */ + unsigned long wwrap; + unsigned long buffer_size; /* buffer size */ + unsigned long wtotal; /* total frames copied */ + unsigned long rtotal; /* total frames copied */ + int frame_size; + char data[0]; // TODO: align this on SIMD/cache +}; + +struct plug_shm_glb_state { + char magic[8]; /* SOF_MAGIC */ + uint64_t size; /* size of this structure in bytes */ + uint64_t state; /* enum plugin_state */ + struct endpoint_hw_config ep_config[NUM_EP_CONFIGS]; + int num_ep_configs; + uint64_t num_ctls; /* number of ctls */ + struct plug_shm_ctl ctl[]; +}; + +struct plug_shm_desc { + /* SHM for stream context sync */ + int fd; + int size; + char name[NAME_SIZE]; + void *addr; +}; + +struct plug_mq_desc { + /* IPC message queue */ + mqd_t mq; + struct mq_attr attr; + char queue_name[NAME_SIZE]; +}; + +struct plug_sem_desc { + char name[NAME_SIZE]; + sem_t *sem; +}; + +struct plug_ctl_container { + struct snd_soc_tplg_ctl_hdr *tplg[MAX_CTLS]; + int updated[MAX_CTLS]; + int count; +}; + +static inline void *plug_ep_rptr(struct plug_shm_endpoint *ep) +{ + return ep->data + ep->rpos; +} + +static inline void *plug_ep_wptr(struct plug_shm_endpoint *ep) +{ + return ep->data + ep->wpos; +} + +static inline int plug_ep_wrap_rsize(struct plug_shm_endpoint *ep) +{ + return ep->buffer_size - ep->rpos; +} + +static inline int plug_ep_wrap_wsize(struct plug_shm_endpoint *ep) +{ + return ep->buffer_size - ep->wpos; +} + +static inline int plug_ep_get_free(struct plug_shm_endpoint *ep) +{ + if (ep->rwrap == ep->wwrap) { + /* calculate available bytes */ + if (ep->rpos < ep->wpos) + return ep->buffer_size - (ep->wpos - ep->rpos); + else + return ep->buffer_size; + } else { + return ep->rpos - ep->wpos; + } +} + +static inline int plug_ep_get_avail(struct plug_shm_endpoint *ep) +{ + if (ep->rwrap == ep->wwrap) { + /* calculate available bytes */ + if (ep->rpos < ep->wpos) + return ep->wpos - ep->rpos; + else + return 0; + } else { + return (ep->buffer_size - ep->rpos) + ep->wpos; + } +} + +static inline void *plug_ep_consume(struct plug_shm_endpoint *ep, unsigned int bytes) +{ + ep->rtotal += bytes; + ep->rpos += bytes; + + if (ep->rpos >= ep->buffer_size) { + ep->rpos -= ep->buffer_size; + ep->rwrap++; + } + + return ep->data + ep->rpos; +} + +static inline void *plug_ep_produce(struct plug_shm_endpoint *ep, unsigned int bytes) +{ + ep->wtotal += bytes; + ep->wpos += bytes; + + if (ep->wpos >= ep->buffer_size) { + ep->wpos -= ep->buffer_size; + ep->wwrap++; + } + + return ep->data + ep->wpos; +} + +/* + * SHM + */ +int plug_shm_init(struct plug_shm_desc *shm, const char *tplg, const char *type, int index); + +int plug_shm_create(struct plug_shm_desc *shm); + +int plug_shm_open(struct plug_shm_desc *shm); + +void plug_shm_free(struct plug_shm_desc *shm); + +/* + * IPC + */ +int plug_mq_create(struct plug_mq_desc *ipc); + +int plug_mq_open(struct plug_mq_desc *ipc); + +int plug_mq_init(struct plug_mq_desc *ipc, const char *tplg, const char *type, int index); + +void plug_mq_free(struct plug_mq_desc *ipc); + +int plug_mq_cmd(struct plug_mq_desc *ipc, void *msg, size_t len, void *reply, size_t rlen); + +int plug_mq_cmd_tx_rx(struct plug_mq_desc *ipc_tx, struct plug_mq_desc *ipc_rx, + void *msg, size_t len, void *reply, size_t rlen); + +/* + * Locking + */ +int plug_lock_create(struct plug_sem_desc *lock); + +void plug_lock_free(struct plug_sem_desc *lock); + +int plug_lock_init(struct plug_sem_desc *lock, const char *tplg, const char *type, int index); + +int plug_lock_open(struct plug_sem_desc *lock); + +/* + * Timing. + */ +void plug_timespec_add_ms(struct timespec *ts, unsigned long ms); + +long plug_timespec_delta_ns(struct timespec *before, struct timespec *after); + +/* dump the IPC data - dont print lines of 0s */ +static inline void data_dump(void *vdata, size_t bytes) +{ + uint32_t *data = vdata; + size_t words = bytes >> 2; + int i; + + for (i = 0; i < words; i++) { + /* 4 words per line */ + if (i % 4 == 0) { + /* delete lines with all 0s */ + if (i > 0 && data[i - 3] == 0 && data[i - 2] == 0 && + data[i - 1] == 0 && data[i - 0] == 0) + printf("\r"); + else + printf("\n"); + + printf("0x%4.4x: 0x%8.8x", i, data[i]); + } else { + printf(" 0x%8.8x", data[i]); + } + } + printf("\n"); +} + +#endif diff --git a/tools/plugin/modules/CMakeLists.txt b/tools/plugin/modules/CMakeLists.txt new file mode 100644 index 000000000000..dfd7105c072e --- /dev/null +++ b/tools/plugin/modules/CMakeLists.txt @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: BSD-3-Clause + +# File SHM pipe module +add_library(sof_mod_shm MODULE + shm.c +) +sof_append_relative_path_definitions(sof_mod_shm) +target_include_directories(sof_mod_shm PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/../pipe + ${sof_source_directory}/src/audio) + +target_compile_options(sof_mod_shm PRIVATE -DPIC -g -O3 -Wl,-EL -Wall -Werror -DCONFIG_LIBRARY -imacros${config_h}) + +install(TARGETS sof_mod_shm + DESTINATION /usr/lib/x86_64-linux-gnu/alsa-lib) + +target_link_options(sof_mod_shm PRIVATE -Wl,--export-dynamic) + +target_include_directories(sof_mod_shm PRIVATE ${sof_install_directory}/include) +target_include_directories(sof_mod_shm PRIVATE ${parser_install_dir}/include) + +set_target_properties(sof_mod_shm + PROPERTIES + INSTALL_RPATH "${sof_install_directory}/alsa-lib" + INSTALL_RPATH_USE_LINK_PATH TRUE +) + + +# ALSA SOF pipe module +add_library(sof_mod_alsa MODULE + alsa.c +) +sof_append_relative_path_definitions(sof_mod_alsa) +target_include_directories(sof_mod_alsa PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/../pipe + ${sof_source_directory}/src/audio) + +target_compile_options(sof_mod_alsa PRIVATE -DPIC -g -O3 -Wl,-EL -Wmissing-prototypes + -Wimplicit-fallthrough -Wall -Werror -DCONFIG_LIBRARY -imacros${config_h}) + +install(TARGETS sof_mod_alsa + DESTINATION /usr/lib/x86_64-linux-gnu/alsa-lib) + +target_link_options(sof_mod_alsa PRIVATE -Wl,--export-dynamic) + +target_include_directories(sof_mod_alsa PRIVATE ${sof_install_directory}/include) +target_include_directories(sof_mod_alsa PRIVATE ${parser_install_dir}/include) + +set_target_properties(sof_mod_alsa + PROPERTIES + INSTALL_RPATH "${sof_install_directory}/alsa-lib" + INSTALL_RPATH_USE_LINK_PATH TRUE +) diff --git a/tools/plugin/modules/alsa.c b/tools/plugin/modules/alsa.c new file mode 100644 index 000000000000..a00ca95d759f --- /dev/null +++ b/tools/plugin/modules/alsa.c @@ -0,0 +1,790 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. + +/* file component for reading/writing pcm samples to/from a file */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pipe.h" + +/* 66def9f0-39f2-11ed-89f7-af98a6440cc4 */ +DECLARE_SOF_RT_UUID("arecord", arecord_uuid, 0x66def9f0, 0x39f2, 0x11ed, + 0xf7, 0x89, 0xaf, 0x98, 0xa6, 0x44, 0x0c, 0xc4); +DECLARE_TR_CTX(arecord_tr, SOF_UUID(arecord_uuid), LOG_LEVEL_INFO); + +/* 72cee996-39f2-11ed-a08f-97fcc42eaaeb */ +DECLARE_SOF_RT_UUID("aplay", aplay_uuid, 0x72cee996, 0x39f2, 0x11ed, + 0xa0, 0x8f, 0x97, 0xfc, 0xc4, 0x2e, 0xaa, 0xeb); +DECLARE_TR_CTX(aplay_tr, SOF_UUID(aplay_uuid), LOG_LEVEL_INFO); + +static const struct comp_driver comp_arecord; +static const struct comp_driver comp_aplay; + +/* ALSA comp data */ +struct alsa_comp_data { + snd_pcm_t *handle; + snd_pcm_info_t *info; + snd_pcm_hw_params_t *hw_params; + snd_pcm_sw_params_t *sw_params; + snd_pcm_uframes_t period_frames; + snd_pcm_uframes_t buffer_frames; + char *pcm_name; + struct sof_ipc_stream_params params; + struct plug_shm_desc pcm; + struct plug_shm_endpoint *ctx; + struct plug_shm_desc glb; + struct plug_shm_glb_state *glb_ctx; + struct endpoint_hw_config *ep_hw; +#if CONFIG_IPC_MAJOR_4 + struct ipc4_base_module_cfg base_cfg; +#endif +}; + +static struct endpoint_hw_config *alsa_get_hw_config(struct comp_dev *dev) +{ + struct alsa_comp_data *cd = comp_get_drvdata(dev); + struct plug_shm_glb_state *glb = cd->glb_ctx; + + if (!glb->num_ep_configs) + return NULL; + + return glb->ep_config; +} + +static int alsa_alloc(struct comp_dev *dev) +{ + struct alsa_comp_data *cd = comp_get_drvdata(dev); + int err; + + /* get ALSA ready */ + err = snd_pcm_info_malloc(&cd->info); + if (err < 0) + goto error; + + err = snd_pcm_hw_params_malloc(&cd->hw_params); + if (err < 0) + goto error; + + err = snd_pcm_sw_params_malloc(&cd->sw_params); + if (err < 0) + goto error; + + comp_dbg(dev, "open done"); + return 0; + +error: + return err; +} + +static int alsa_close(struct comp_dev *dev) +{ + struct alsa_comp_data *cd = comp_get_drvdata(dev); + int ret = 0; + + comp_dbg(dev, "close"); + if (cd->handle) { + ret = snd_pcm_hw_free(cd->handle); + if (ret < 0) + comp_err(dev, "error: failed to snd_pcm_hw_free: %s\n", snd_strerror(ret)); + + ret = snd_pcm_close(cd->handle); + if (ret < 0) + comp_err(dev, "error: failed to snd_pcm_close: %s\n", snd_strerror(ret)); + + cd->handle = NULL; + } + + return ret; +} + +static void alsa_free(struct comp_dev *dev) +{ + struct alsa_comp_data *cd = comp_get_drvdata(dev); + + comp_dbg(dev, "alsa_free()"); + + snd_pcm_sw_params_free(cd->sw_params); + snd_pcm_hw_params_free(cd->hw_params); + snd_pcm_info_free(cd->info); + plug_shm_free(&cd->pcm); + free(cd); + free(dev); +} + +static struct comp_dev *alsa_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec) +{ +#if CONFIG_IPC_MAJOR_4 + const struct ipc4_base_module_cfg *base_cfg = (struct ipc4_base_module_cfg *)spec; +#endif + struct comp_dev *dev; + struct alsa_comp_data *cd; + int err; + + dev = comp_alloc(drv, sizeof(*dev)); + if (!dev) + return NULL; + dev->ipc_config = *config; + + /* allocate memory for file comp data */ + cd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + if (!cd) + goto error; + + comp_set_drvdata(dev, cd); + memcpy(&cd->base_cfg, base_cfg, sizeof(struct ipc4_base_module_cfg)); + + /* use PCM ID to create shm */ + err = plug_shm_init(&cd->pcm, _sp->topology_name, "pcm", 1); + if (err < 0) { + comp_err(dev, "Error initializing pcm\n"); + goto error; + } + + // TODO: get the shm size for the buffer using a better method + //cd->pcm.size = 128 * 1024; + + /* mmap the SHM PCM */ + err = plug_shm_open(&cd->pcm); + if (err < 0) { + comp_err(dev, "Error open pcm shm"); + goto error; + } + cd->ctx = cd->pcm.addr; + + err = plug_shm_init(&cd->glb, _sp->topology_name, "ctx", 0); + if (err < 0) { + comp_err(dev, "Error initializing ctx\n"); + goto error; + } + + // TODO: get the shm size for the buffer using a better method + //cd->pcm.size = 128 * 1024; + + /* mmap the GLB ctx */ + err = plug_shm_open(&cd->glb); + if (err < 0) { + comp_err(dev, "Error opening glb ctx\n"); + goto error; + } + cd->glb_ctx = cd->glb.addr; + + /* alloc alsa context */ + err = alsa_alloc(dev); + if (err < 0) { + comp_err(dev, "Error allocating alsa context\n"); + goto error; + } + + return dev; + +error: + free(cd); + free(dev); + return NULL; +} + +static struct comp_dev *arecord_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, const void *spec) +{ + struct comp_dev *dev; + struct alsa_comp_data *cd; + + comp_dbg(dev, "arecord_new()"); + + dev = alsa_new(drv, config, spec); + if (!dev) + return NULL; + + cd = comp_get_drvdata(dev); + cd->params.direction = SND_PCM_STREAM_CAPTURE; + + dev->state = COMP_STATE_READY; + return dev; +} + +static struct comp_dev *aplay_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec) +{ + struct comp_dev *dev; + struct alsa_comp_data *cd; + + comp_dbg(dev, "aplay_new()"); + + dev = alsa_new(drv, config, spec); + if (!dev) + return NULL; + + cd = comp_get_drvdata(dev); + cd->params.direction = SND_PCM_STREAM_PLAYBACK; + + dev->state = COMP_STATE_READY; + return dev; +} + +static int set_params(struct comp_dev *dev) +{ + struct alsa_comp_data *cd = comp_get_drvdata(dev); + struct sof_ipc_stream_params *params = &cd->params; + int frame_fmt; + int err; + + err = snd_pcm_open(&cd->handle, cd->pcm_name, cd->params.direction, 0); + if (err < 0) { + comp_err(dev, "error: cant open PCM %s: %s\n", cd->pcm_name, snd_strerror(err)); + return err; + } + + err = snd_pcm_info(cd->handle, cd->info); + if (err < 0) { + comp_err(dev, "error: cant get PCM info: %s\n", snd_strerror(err)); + return err; + } + + /* is sound card HW configuration valid ? */ + err = snd_pcm_hw_params_any(cd->handle, cd->hw_params); + if (err < 0) { + comp_err(dev, "error: cant get PCM hw_params: %s\n", snd_strerror(err)); + return err; + } + + /* set interleaved buffer format */ + err = snd_pcm_hw_params_set_access(cd->handle, cd->hw_params, + SND_PCM_ACCESS_RW_INTERLEAVED); + if (err < 0) { + comp_err(dev, "error: PCM can't set interleaved: %s\n", snd_strerror(err)); + return err; + } + + /* set sample format */ + /* set all topology configuration */ + switch (params->frame_fmt) { + case SOF_IPC_FRAME_S16_LE: + frame_fmt = SND_PCM_FORMAT_S16_LE; + break; + case SOF_IPC_FRAME_S24_4LE: + frame_fmt = SND_PCM_FORMAT_S24_LE; + break; + case SOF_IPC_FRAME_S32_LE: + frame_fmt = SND_PCM_FORMAT_S32_LE; + break; + case SOF_IPC_FRAME_FLOAT: + frame_fmt = SND_PCM_FORMAT_FLOAT_LE; + break; + case SOF_IPC_FRAME_S24_3LE: + frame_fmt = SND_PCM_FORMAT_S24_3LE; + break; + default: + comp_err(dev, "error: invalid frame format %d for ALSA PCM\n", params->frame_fmt); + return -EINVAL; + } + err = snd_pcm_hw_params_set_format(cd->handle, cd->hw_params, frame_fmt); + if (err < 0) { + comp_err(dev, "error: PCM can't set format %d: %s\n", + frame_fmt, snd_strerror(err)); + return err; + } + + /* set number of channels */ + err = snd_pcm_hw_params_set_channels(cd->handle, cd->hw_params, params->channels); + if (err < 0) { + comp_err(dev, "error: PCM can't set channels %d: %s\n", + params->channels, snd_strerror(err)); + return err; + } + + /* set sample rate */ + err = snd_pcm_hw_params_set_rate(cd->handle, cd->hw_params, params->rate, 0); + if (err < 0) { + comp_err(dev, "error: PCM can't set rate %d: %s\n", + params->rate, snd_strerror(err)); + return err; + } + + /* set period size TODO: get from topology */ + err = snd_pcm_hw_params_set_period_size(cd->handle, cd->hw_params, + cd->period_frames, 0); + if (err < 0) { + comp_err(dev, "error: PCM can't set period size %ld frames: %s\n", + cd->period_frames, snd_strerror(err)); + return err; + } + + /* set buffer size: TODO: get from topology */ + err = snd_pcm_hw_params_set_buffer_size_near(cd->handle, cd->hw_params, + &cd->buffer_frames); + if (err < 0) { + comp_err(dev, "error: PCM can't set buffer size %ld frames: %s\n", + cd->buffer_frames, snd_strerror(err)); + return err; + } + + /* commit the hw params */ + err = snd_pcm_hw_params(cd->handle, cd->hw_params); + if (err < 0) { + comp_err(dev, "error: PCM can't commit hw_params: %s\n", snd_strerror(err)); + snd_pcm_hw_params_dump(cd->hw_params, SND_OUTPUT_STDIO); + return err; + } + + /* get the initial SW params */ + err = snd_pcm_sw_params_current(cd->handle, cd->sw_params); + if (err < 0) { + comp_err(dev, "error: PCM can't get sw params: %s\n", snd_strerror(err)); + return err; + } + + /* set the avail min to the period size */ + err = snd_pcm_sw_params_set_avail_min(cd->handle, cd->sw_params, cd->period_frames); + if (err < 0) { + comp_err(dev, "error: PCM can't set avail min: %s\n", snd_strerror(err)); + return err; + } + + /* PCM should start after receiving first periods worth of data */ + err = snd_pcm_sw_params_set_start_threshold(cd->handle, cd->sw_params, cd->period_frames); + if (err < 0) { + comp_err(dev, "error: PCM can't set start threshold: %s\n", snd_strerror(err)); + return err; + } + + /* PCM should stop if only 1/4 period worth of data is available */ + err = snd_pcm_sw_params_set_stop_threshold(cd->handle, cd->sw_params, + cd->period_frames / 4); + if (err < 0) { + comp_err(dev, "error: PCM can't set stop threshold: %s\n", snd_strerror(err)); + return err; + } + + /* commit the sw params */ + if (snd_pcm_sw_params(cd->handle, cd->sw_params) < 0) { + comp_err(dev, "error: PCM can't commit sw_params: %s\n", snd_strerror(err)); + snd_pcm_sw_params_dump(cd->sw_params, SND_OUTPUT_STDIO); + return err; + } + + comp_dbg(dev, "params set"); + return 0; +} + +static int alsa_dai_get_hw_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params, int dir); + +/** + * \brief Sets file component audio stream parameters. + * \param[in,out] dev Volume base component device. + * \param[in] params Audio (PCM) stream parameters (ignored for this component) + * \return Error code. + * + * All done in prepare() since we need to know source and sink component params. + */ +static int arecord_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) +{ + struct comp_buffer *buffer; + struct alsa_comp_data *cd = comp_get_drvdata(dev); + struct comp_buffer __sparse_cache *buf_c; + int ret; + + comp_dbg(dev, "arecord params"); + + ret = alsa_dai_get_hw_params(dev, params, cd->params.direction); + + if (params->direction != SND_PCM_STREAM_CAPTURE) { + comp_err(dev, "alsa_params(): pcm params invalid direction."); + return -EINVAL; + } + + /* params can be aligned to match pipeline here */ + ret = comp_verify_params(dev, 0, params); + if (ret < 0) { + comp_err(dev, "alsa_params(): pcm params verification failed."); + return ret; + } + memcpy(&cd->params, params, sizeof(*params)); + + /* file component sink/source buffer period count */ + buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); + buf_c = buffer_acquire(buffer); + buffer_reset_pos(buf_c, NULL); + buffer_release(buf_c); + + comp_dbg(dev, "prepare done ret = %d", ret); + + return 0; +} + +static int aplay_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) +{ + struct comp_buffer *buffer; + struct alsa_comp_data *cd = comp_get_drvdata(dev); + int ret; + + comp_dbg(dev, "aplay params"); + + ret = alsa_dai_get_hw_params(dev, params, cd->params.direction); + + if (params->direction != SND_PCM_STREAM_PLAYBACK) { + comp_err(dev, "alsa_params(): pcm params invalid direction."); + return -EINVAL; + } + + /* params can be aligned to match pipeline here */ + ret = comp_verify_params(dev, 0, params); + if (ret < 0) { + comp_err(dev, "alsa_params(): pcm params verification failed."); + return ret; + } + memcpy(&cd->params, params, sizeof(*params)); + + /* file component sink/source buffer period count */ + buffer = list_first_item(&dev->bsource_list, struct comp_buffer, + sink_list); + buffer_reset_pos(buffer, NULL); + + comp_dbg(dev, "prepare done ret = %d", ret); + return 0; +} + +static int alsa_trigger(struct comp_dev *dev, int cmd) +{ + int err; + + /* trigger is handled automatically by ALSA start threshold */ + comp_dbg(dev, "trigger cmd %d", cmd); + + switch (cmd) { + case COMP_TRIGGER_PAUSE: + case COMP_TRIGGER_STOP: + err = alsa_close(dev); + if (err < 0) { + comp_err(dev, "error: cant stop pipeline"); + return err; + } + break; + case COMP_TRIGGER_RELEASE: + case COMP_TRIGGER_START: + err = set_params(dev); + if (err < 0) { + comp_err(dev, "error: cant stop pipeline"); + return err; + } + break; + default: + break; + } + + return comp_set_state(dev, cmd); +} + +/* used to pass standard and bespoke commands (with data) to component */ +static int alsa_cmd(struct comp_dev *dev, int cmd, void *data, + int max_data_size) +{ + return 0; +} + +/* + * copy and process stream samples + * returns the number of bytes copied + */ +static int arecord_copy(struct comp_dev *dev) +{ + struct alsa_comp_data *cd = comp_get_drvdata(dev); + struct comp_buffer __sparse_cache *buf_c; + struct comp_buffer *buffer; + struct audio_stream *sink; + snd_pcm_sframes_t frames; + snd_pcm_uframes_t free; + snd_pcm_uframes_t total = 0; + unsigned int frame_bytes; + void *pos; + + switch (dev->state) { + case COMP_STATE_ACTIVE: + break; + default: + return -EINVAL; + } + + /* file component sink buffer */ + buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); + buf_c = buffer_acquire(buffer); + sink = &buf_c->stream; + pos = sink->w_ptr; + + //FIX: this will fill buffer and higher latency, use period size + free = MIN(audio_stream_get_free_frames(sink), cd->period_frames); + frame_bytes = audio_stream_frame_bytes(sink); + + while (free) { + frames = MIN(free, audio_stream_frames_without_wrap(sink, pos)); + + /* read PCM samples from file */ + frames = snd_pcm_readi(cd->handle, pos, frames); + if (frames < 0) { + comp_err(dev, "failed to read: %s: %s\n", + cd->pcm_name, snd_strerror(frames)); + buffer_release(buf_c); + return frames; + } + + free -= frames; + pos = audio_stream_wrap(sink, pos + frames * frame_bytes); + total += frames; + } + + /* update sink buffer pointers */ + comp_update_buffer_produce(buffer, total * frame_bytes); + comp_dbg(dev, "read %d frames", total); + buffer_release(buf_c); + + return 0; +} + +/* + * copy and process stream samples + * returns the number of bytes copied + */ +static int aplay_copy(struct comp_dev *dev) +{ + struct alsa_comp_data *cd = comp_get_drvdata(dev); + struct comp_buffer *buffer; + struct audio_stream *source; + snd_pcm_sframes_t frames; + snd_pcm_sframes_t avail; + snd_pcm_uframes_t total = 0; + unsigned int frame_bytes; + void *pos; + + switch (dev->state) { + case COMP_STATE_ACTIVE: + break; + default: + return -EINVAL; + } + + /* file component source buffer */ + buffer = list_first_item(&dev->bsource_list, struct comp_buffer, + sink_list); + source = &buffer->stream; + pos = source->r_ptr; + avail = MIN(audio_stream_get_avail_frames(source), cd->period_frames); + avail = audio_stream_get_avail_frames(source); + frame_bytes = audio_stream_frame_bytes(source); + + while (avail > 0) { + frames = MIN(avail, audio_stream_frames_without_wrap(source, pos)); + + /* write PCM samples to PCM */ + frames = snd_pcm_writei(cd->handle, pos, frames); + if (frames < 0) { + comp_err(dev, "failed to write: %s: %s\n", + cd->pcm_name, snd_strerror(frames)); + return frames; + } + + avail -= frames; + pos = audio_stream_wrap(source, pos + frames * frame_bytes); + total += frames; + } + + /* update sink buffer pointers */ + comp_update_buffer_consume(buffer, total * frame_bytes); + comp_dbg(dev, "wrote %d bytes", total * frame_bytes); + + return 0; +} + +static int alsa_prepare(struct comp_dev *dev) +{ + int ret = 0; + + comp_dbg(dev, "prepare"); + ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); + if (ret < 0) + return ret; + + if (ret == COMP_STATUS_STATE_ALREADY_SET) + return PPL_STATUS_PATH_STOP; + + return ret; +} + +static int alsa_reset(struct comp_dev *dev) +{ + comp_dbg(dev, "reset"); + + comp_set_state(dev, COMP_TRIGGER_RESET); + + return 0; +} + +/* + * TODO: we pass the DAI topology config back up the pipeline so + * that upstream/downstream can be configured. Needs to be configured + * at stream runtime instead of at topology load time. + */ +static int alsa_dai_get_hw_params(struct comp_dev *dev, struct sof_ipc_stream_params *params, + int dir) +{ + struct alsa_comp_data *cd = comp_get_drvdata(dev); + struct endpoint_hw_config *ep_hw; + char pcm_name[128]; + + comp_dbg(dev, "get_hw_params"); + + /* get our hw config from cmdline and conf file */ + ep_hw = alsa_get_hw_config(dev); + if (!ep_hw) { + comp_err(dev, "error: failed to get hw config %d\n"); + return -EINVAL; + } + cd->ep_hw = ep_hw; + + /* PCM name comes from cmd line - "default" dev means dont use dev */ + if (!strncmp(cd->ep_hw->dev_name, "default", sizeof(cd->ep_hw->dev_name))) { + snprintf(pcm_name, sizeof(pcm_name), "%s", cd->ep_hw->card_name); + } else { + snprintf(pcm_name, sizeof(pcm_name), "%s:%s", + cd->ep_hw->card_name, cd->ep_hw->dev_name); + } + cd->pcm_name = strdup(pcm_name); + comp_dbg(dev, "using ALSA card %s", cd->pcm_name); + + /* set default config - get from cmdline and plugin config */ + cd->params.rate = cd->ep_hw->rate; + cd->params.channels = cd->ep_hw->channels; + cd->buffer_frames = cd->ep_hw->buffer_frames; + cd->period_frames = cd->ep_hw->period_frames; + + /* ALSA API uses frames, SOF buffer uses bytes */ + switch (cd->ep_hw->format) { + case SND_PCM_FORMAT_S16_LE: + cd->params.frame_fmt = SOF_IPC_FRAME_S16_LE; + cd->params.buffer.size = cd->ep_hw->buffer_frames * 2; + break; + case SND_PCM_FORMAT_S24_LE: + cd->params.frame_fmt = SOF_IPC_FRAME_S24_4LE; + cd->params.buffer.size = cd->ep_hw->buffer_frames * 4; + break; + case SND_PCM_FORMAT_S32_LE: + cd->params.frame_fmt = SOF_IPC_FRAME_S32_LE; + cd->params.buffer.size = cd->ep_hw->buffer_frames * 4; + break; + case SND_PCM_FORMAT_FLOAT: + cd->params.frame_fmt = SOF_IPC_FRAME_FLOAT; + cd->params.buffer.size = cd->ep_hw->buffer_frames * 4; + break; + case SND_PCM_FORMAT_S24_3LE: + cd->params.frame_fmt = SOF_IPC_FRAME_S24_3LE; + cd->params.buffer.size = cd->ep_hw->buffer_frames * 3; + break; + default: + comp_err(dev, "error: invalid frame format %d for ALSA PCM\n", params->frame_fmt); + return -EINVAL; + } + + memcpy(params, &cd->params, sizeof(*params)); + + comp_dbg(dev, "rate %d", params->rate); + comp_dbg(dev, "frame format %d", params->frame_fmt); + comp_dbg(dev, "channels %d", params->channels); + comp_dbg(dev, "buffer frames %d", cd->buffer_frames); + comp_dbg(dev, "period frames %d", cd->period_frames); + comp_dbg(dev, "direction %d", params->direction); + + return 0; +} + +static int alsa_get_attribute(struct comp_dev *dev, uint32_t type, void *value) +{ + struct alsa_comp_data *cd = comp_get_drvdata(dev); + + switch (type) { + case COMP_ATTR_BASE_CONFIG: + memcpy_s(value, sizeof(struct ipc4_base_module_cfg), + &cd->base_cfg, sizeof(struct ipc4_base_module_cfg)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct comp_driver comp_arecord = { + .type = SOF_COMP_FILEREAD, + .uid = SOF_RT_UUID(arecord_uuid), + .tctx = &arecord_tr, + .ops = { + .create = arecord_new, + .free = alsa_free, + .params = arecord_params, + .cmd = alsa_cmd, + .trigger = alsa_trigger, + .copy = arecord_copy, + .prepare = alsa_prepare, + .reset = alsa_reset, + .dai_get_hw_params = alsa_dai_get_hw_params, + .get_attribute = alsa_get_attribute, + }, +}; + +static const struct comp_driver comp_aplay = { + .type = SOF_COMP_FILEWRITE, + .uid = SOF_RT_UUID(aplay_uuid), + .tctx = &aplay_tr, + .ops = { + .create = aplay_new, + .free = alsa_free, + .params = aplay_params, + .cmd = alsa_cmd, + .trigger = alsa_trigger, + .copy = aplay_copy, + .prepare = alsa_prepare, + .reset = alsa_reset, + .dai_get_hw_params = alsa_dai_get_hw_params, + .get_attribute = alsa_get_attribute, + }, +}; + +static struct comp_driver_info comp_arecord_info = { + .drv = &comp_arecord, +}; + +static struct comp_driver_info comp_aplay_info = { + .drv = &comp_aplay, +}; + +static void sys_comp_alsa_init(void) +{ + comp_register(&comp_arecord_info); + comp_register(&comp_aplay_info); +} + +DECLARE_MODULE(sys_comp_alsa_init); diff --git a/tools/plugin/modules/shm.c b/tools/plugin/modules/shm.c new file mode 100644 index 000000000000..d59db6694902 --- /dev/null +++ b/tools/plugin/modules/shm.c @@ -0,0 +1,451 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. + +/* shm component for reading/writing pcm samples to/from a shm */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pipe.h" + +/* 1488beda-e847-ed11-b309-a58b974fecce */ +DECLARE_SOF_RT_UUID("shmread", shmread_uuid, 0xdabe8814, 0x47e8, 0x11ed, + 0xa5, 0x8b, 0xb3, 0x09, 0x97, 0x4f, 0xec, 0xce); +DECLARE_TR_CTX(shmread_tr, SOF_UUID(shmread_uuid), LOG_LEVEL_INFO); + +/* 1c03b6e2-e847-ed11-7f80-07a91b6efa6c */ +DECLARE_SOF_RT_UUID("shmwrite", shmwrite_uuid, 0xe2b6031c, 0x47e8, 0x11ed, + 0x07, 0xa9, 0x7f, 0x80, 0x1b, 0x6e, 0xfa, 0x6c); +DECLARE_TR_CTX(shmwrite_tr, SOF_UUID(shmwrite_uuid), LOG_LEVEL_INFO); + +static const struct comp_driver comp_shmread; +static const struct comp_driver comp_shmwrite; + +/* shm comp data */ +struct shm_comp_data { + /* PCM data */ + struct plug_shm_desc pcm; + struct plug_shm_endpoint *ctx; +#if CONFIG_IPC_MAJOR_4 + struct ipc4_base_module_cfg base_cfg; +#endif +}; + +static int shm_process_new(struct comp_dev *dev, + const struct comp_ipc_config *config, + const void *spec) +{ + struct shm_comp_data *cd = comp_get_drvdata(dev); + struct plug_shm_endpoint *ctx; + int ret; + + comp_dbg(dev, "shm new()"); + + /* FIXME: use PCM ID to create shm */ + ret = plug_shm_init(&cd->pcm, _sp->topology_name, "pcm", 1); + if (ret < 0) + return ret; + + // TODO: get the shm size for the buffer using a better method + cd->pcm.size = 128 * 1024; + + /* mmap the SHM PCM */ + ret = plug_shm_create(&cd->pcm); + if (ret < 0) + return ret; + + cd->ctx = cd->pcm.addr; + ctx = cd->ctx; + ctx->buffer_size = cd->pcm.size; + memset(ctx, 0, sizeof(*ctx)); + ctx->comp_id = config->id; + ctx->pipeline_id = config->pipeline_id; + ctx->state = SOF_PLUGIN_STATE_INIT; + dev->state = COMP_STATE_READY; + + return 0; +} + +static void shm_free(struct comp_dev *dev) +{ + struct shm_comp_data *cd = comp_get_drvdata(dev); + + cd->ctx = NULL; + + plug_shm_free(&cd->pcm); + shm_unlink(cd->pcm.name); + + free(cd); + free(dev); +} + +static struct comp_dev *shm_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec, int direction) +{ + struct comp_dev *dev; +#if CONFIG_IPC_MAJOR_4 + const struct ipc4_base_module_cfg *base_cfg = (struct ipc4_base_module_cfg *)spec; +#endif + struct shm_comp_data *cd; + int err; + + dev = comp_alloc(drv, sizeof(*dev)); + if (!dev) + return NULL; + dev->ipc_config = *config; + + /* allocate memory for shm comp data */ + cd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + if (!cd) + goto error; + + comp_set_drvdata(dev, cd); + memcpy(&cd->base_cfg, base_cfg, sizeof(struct ipc4_base_module_cfg)); + + dev->direction = direction; + err = shm_process_new(dev, config, spec); + if (err < 0) { + free(cd); + free(dev); + return NULL; + } + dev->direction_set = true; + + dev->state = COMP_STATE_READY; + return dev; + +error: + free(dev); + return NULL; +} + +static struct comp_dev *shmwrite_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec) +{ + return shm_new(drv, config, spec, SOF_IPC_STREAM_PLAYBACK); +} + +static struct comp_dev *shmread_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec) +{ + return shm_new(drv, config, spec, SOF_IPC_STREAM_CAPTURE); +} + +/** + * \brief Sets shm component audio stream parameters. + * \param[in,out] dev Volume base component device. + * \param[in] params Audio (PCM) stream parameters (ignored for this component) + * \return Error code. + * + * All done in prepare() since we need to know source and sink component params. + */ +static int shmread_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) +{ + struct shm_comp_data *cd = comp_get_drvdata(dev); + struct plug_shm_endpoint *ctx = cd->ctx; + int ret; + +#if CONFIG_IPC_MAJOR_4 + ipc4_base_module_cfg_to_stream_params(&cd->base_cfg, params); +#endif + + comp_err(dev, "forme_fmt %d channels %d", params->frame_fmt, params->channels); + + ret = comp_verify_params(dev, 0, params); + if (ret < 0) { + comp_err(dev, "shm_params(): pcm params verification failed."); + return ret; + } + ctx->state = SOF_PLUGIN_STATE_READY; + + return 0; +} + +static int shmwrite_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) +{ + struct shm_comp_data *cd = comp_get_drvdata(dev); + struct plug_shm_endpoint *ctx = cd->ctx; + int ret; + + ret = comp_verify_params(dev, 0, params); + if (ret < 0) { + comp_err(dev, "shm_params(): pcm params verification failed."); + return ret; + } + ctx->state = SOF_PLUGIN_STATE_READY; + + return 0; +} + +static int shm_trigger(struct comp_dev *dev, int cmd) +{ + struct shm_comp_data *cd = comp_get_drvdata(dev); + struct plug_shm_endpoint *ctx = cd->ctx; + + comp_dbg(dev, "shm_trigger(%d)", cmd); + + switch (cmd) { + case COMP_TRIGGER_START: + case COMP_TRIGGER_RELEASE: + ctx->state = SOF_PLUGIN_STATE_STREAM_RUNNING; + break; + case COMP_TRIGGER_STOP: + case COMP_TRIGGER_PAUSE: + ctx->state = SOF_PLUGIN_STATE_READY; + break; + case COMP_TRIGGER_RESET: + ctx->state = SOF_PLUGIN_STATE_INIT; + break; + case COMP_TRIGGER_XRUN: + ctx->state = SOF_PLUGIN_STATE_STREAM_ERROR; + break; + default: + break; + } + + return comp_set_state(dev, cmd); +} + +static int shm_cmd(struct comp_dev *dev, int cmd, void *data, int max_data_size) +{ + return 0; +} + +/* + * copy from local SOF buffer to remote SHM buffer + */ +static int shmread_copy(struct comp_dev *dev) +{ + struct shm_comp_data *cd = comp_get_drvdata(dev); + struct plug_shm_endpoint *ctx = cd->ctx; + struct comp_buffer *buffer; + struct audio_stream *source; + unsigned int copy_bytes; + unsigned int remaining; + unsigned int total = 0; + void *rptr; + void *dest; + + /* local SOF source buffer */ + buffer = list_first_item(&dev->bsource_list, struct comp_buffer, + sink_list); + source = &buffer->stream; + rptr = source->r_ptr; + + /* remote SHM sink buffer */ + dest = plug_ep_wptr(ctx); + + /* maximum byte count that can be copied this iteration */ + remaining = MIN(audio_stream_get_avail_bytes(source), plug_ep_get_free(ctx)); + + while (remaining) { + /* min bytes from source pipe */ + copy_bytes = MIN(remaining, plug_ep_wrap_wsize(ctx)); + + /* min bytes from source and sink */ + copy_bytes = MIN(copy_bytes, audio_stream_bytes_without_wrap(source, rptr)); + + /* anything to copy ? */ + if (copy_bytes == 0) + break; + + /* copy to local buffer from SHM buffer */ + memcpy(dest, rptr, copy_bytes); + + /* update SHM pointer with wrap */ + dest = plug_ep_produce(ctx, copy_bytes); + + /* update local pointers */ + rptr = audio_stream_wrap(source, rptr + copy_bytes); + + /* update avail and totals */ + remaining -= copy_bytes; + total += copy_bytes; + } + + /* update sink buffer pointers */ + comp_update_buffer_consume(buffer, total); + comp_dbg(dev, "wrote %d bytes", total); + + return 0; +} + +/* + * copy to local SOF buffer from remote SHM buffer + */ +static int shmwrite_copy(struct comp_dev *dev) +{ + struct shm_comp_data *cd = comp_get_drvdata(dev); + struct plug_shm_endpoint *ctx = cd->ctx; + struct comp_buffer *buffer; + struct audio_stream *sink; + unsigned int copy_bytes; + unsigned int remaining; + unsigned int total = 0; + void *wptr; + void *src; + + /* local SOF sink buffer */ + buffer = list_first_item(&dev->bsink_list, struct comp_buffer, + source_list); + sink = &buffer->stream; + wptr = sink->w_ptr; + + /* remote SHM source buffer */ + src = plug_ep_rptr(ctx); + + /* maximum byte count that can be copied this iteration */ + remaining = MIN(audio_stream_get_free_bytes(sink), plug_ep_get_avail(ctx)); + + while (remaining > 0) { + /* min bytes free bytes in local sink */ + copy_bytes = MIN(remaining, plug_ep_wrap_rsize(ctx)); + + /* min bytes to wrap */ + copy_bytes = MIN(copy_bytes, audio_stream_bytes_without_wrap(sink, wptr)); + + /* nothing to copy ? */ + if (copy_bytes == 0) + break; + + /* copy to SHM from local buffer */ + memcpy(wptr, src, copy_bytes); + + /* update local pointers */ + wptr = audio_stream_wrap(sink, wptr + copy_bytes); + + /* update SHM pointer with wrap */ + src = plug_ep_consume(ctx, copy_bytes); + + /* update avail and totals */ + remaining -= copy_bytes; + total += copy_bytes; + } + + /* update sink buffer pointers */ + comp_update_buffer_produce(buffer, total); + comp_dbg(dev, "read %d bytes", total); + + return 0; +} + +static int shm_prepare(struct comp_dev *dev) +{ + struct shm_comp_data *cd = comp_get_drvdata(dev); + struct plug_shm_endpoint *ctx = cd->ctx; + int ret = 0; + + comp_dbg(dev, "shm prepare_copy()"); + + ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); + if (ret < 0) + return ret; + + ctx->state = SOF_PLUGIN_STATE_READY; + + if (ret == COMP_STATUS_STATE_ALREADY_SET) + return PPL_STATUS_PATH_STOP; + + return ret; +} + +static int shm_reset(struct comp_dev *dev) +{ + struct shm_comp_data *cd = comp_get_drvdata(dev); + struct plug_shm_endpoint *ctx = cd->ctx; + + comp_set_state(dev, COMP_TRIGGER_RESET); + ctx->state = SOF_PLUGIN_STATE_INIT; + + return 0; +} + +int shm_get_attribute(struct comp_dev *dev, uint32_t type, void *value) +{ + struct shm_comp_data *cd = comp_get_drvdata(dev); + + switch (type) { + case COMP_ATTR_BASE_CONFIG: + memcpy_s(value, sizeof(struct ipc4_base_module_cfg), + &cd->base_cfg, sizeof(struct ipc4_base_module_cfg)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct comp_driver comp_shmread = { + .type = SOF_COMP_HOST, + .uid = SOF_RT_UUID(shmread_uuid), + .tctx = &shmread_tr, + .ops = { + .create = shmread_new, + .free = shm_free, + .params = shmread_params, + .cmd = shm_cmd, + .trigger = shm_trigger, + .copy = shmread_copy, + .prepare = shm_prepare, + .reset = shm_reset, + .get_attribute = shm_get_attribute, + }, +}; + +static const struct comp_driver comp_shmwrite = { + .type = SOF_COMP_HOST, + .uid = SOF_RT_UUID(shmwrite_uuid), + .tctx = &shmwrite_tr, + .ops = { + .create = shmwrite_new, + .free = shm_free, + .params = shmwrite_params, + .cmd = shm_cmd, + .trigger = shm_trigger, + .copy = shmwrite_copy, + .prepare = shm_prepare, + .reset = shm_reset, + .get_attribute = shm_get_attribute, + }, +}; + +static struct comp_driver_info comp_shmread_info = { + .drv = &comp_shmread, +}; + +static struct comp_driver_info comp_shmwrite_info = { + .drv = &comp_shmwrite, +}; + +static void sys_comp_shm_init(void) +{ + comp_register(&comp_shmread_info); + comp_register(&comp_shmwrite_info); +} + +DECLARE_MODULE(sys_comp_shm_init); diff --git a/tools/plugin/pipe/CMakeLists.txt b/tools/plugin/pipe/CMakeLists.txt new file mode 100644 index 000000000000..69f6245cfab2 --- /dev/null +++ b/tools/plugin/pipe/CMakeLists.txt @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_executable(sof-pipe + main.c + cpu.c + pipeline.c + ctl.c + ipc4.c + ../common.c +) + +sof_append_relative_path_definitions(sof-pipe) + +target_include_directories(sof-pipe PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${sof_source_directory}/src/audio) + +target_compile_options(sof-pipe PRIVATE -DPIC -g -O3 -Wl,-EL -Wall -Werror -DCONFIG_LIBRARY -imacros${config_h}) + +target_include_directories(sof-pipe PRIVATE ${sof_install_directory}/include) +target_include_directories(sof-pipe PRIVATE ${parser_install_dir}/include) + +target_link_libraries(sof-pipe PRIVATE -Wl,-whole-archive sof_library -Wl,-no-whole-archive) +target_link_libraries(sof-pipe PRIVATE sof_parser_lib) +target_link_libraries(sof-pipe PRIVATE pthread) +target_link_libraries(sof-pipe PRIVATE -rdynamic -lasound -ldl -lm -lasound -lrt) diff --git a/tools/plugin/pipe/cpu.c b/tools/plugin/pipe/cpu.c new file mode 100644 index 000000000000..ea7e5d0645e2 --- /dev/null +++ b/tools/plugin/pipe/cpu.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood + +/* + * SOF pipeline in userspace. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "pipe.h" + +/* read the CPU ID register data on x86 */ +static inline void x86_cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + /* data type is passed in on eax (and sometimes ecx) */ + asm volatile("cpuid" + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) + : "0" (*eax), "2" (*ecx)); +} + +/* + * Check core type for E cores. If non hybrid then it does not matter. + */ +static inline int use_this_core(struct sof_pipe *sp) +{ + /* CPUID - set eax to 0x1a for hybrid core types */ + unsigned int eax = 0x1a, ebx = 0, ecx = 0, edx = 0; + char core_mask; + + /* get the processor core type we are running on now */ + x86_cpuid(&eax, &ebx, &ecx, &edx); + + /* core type 0x20 is atom, 0x40 is core */ + core_mask = (eax >> 24) & 0xFF; + switch (core_mask) { + case 0x20: + fprintf(sp->log, "found E core\n"); + if (sp->use_E_core) + return 1; + return 0; + case 0x40: + fprintf(sp->log, "found P core\n"); + if (sp->use_P_core) + return 1; + return 0; + default: + /* non hybrid arch, just use first core */ + fprintf(sp->log, "found non hybrid core topology\n"); + return 1; + } +} + +/* sof-pipe needs to be sticky to the current core for low latency */ +int pipe_set_affinity(struct sof_pipe *sp) +{ + cpu_set_t cpuset; + pthread_t thread; + long core_count = sysconf(_SC_NPROCESSORS_ONLN); + int i; + int err; + + /* Set affinity mask to core */ + thread = pthread_self(); + CPU_ZERO(&cpuset); + + /* find the first E core (usually come after the P cores ?) */ + for (i = core_count - 1; i >= 0; i--) { + CPU_ZERO(&cpuset); + CPU_SET(i, &cpuset); + + /* change our core to i */ + err = pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset); + if (err != 0) { + fprintf(sp->log, "error: failed to set CPU affinity to core %d: %s\n", + i, strerror(err)); + return err; + } + + /* should we use this core ? */ + if (use_this_core(sp)) + break; + } + + return 0; +} + +/* set ipc thread to low priority */ +int pipe_set_ipc_lowpri(struct sof_pipe *sp) +{ + pthread_attr_t attr; + struct sched_param param; + int err; + + /* attempt to set thread priority - needs suid */ + fprintf(sp->log, "pipe: set IPC low priority\n"); + + err = pthread_attr_init(&attr); + if (err < 0) { + fprintf(sp->log, "error: can't create thread attr %d %s\n", err, strerror(errno)); + return err; + } + + err = pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + if (err < 0) { + fprintf(sp->log, "error: can't set thread policy %d %s\n", err, strerror(errno)); + return err; + } + param.sched_priority = 0; + err = pthread_attr_setschedparam(&attr, ¶m); + if (err < 0) { + fprintf(sp->log, "error: can't set thread sched param %d %s\n", + err, strerror(errno)); + return err; + } + + return 0; +} + +/* set pipeline to realtime priority */ +int pipe_set_rt(struct sof_pipe *sp) +{ + pthread_attr_t attr; + struct sched_param param; + int err; + uid_t uid = getuid(); + uid_t euid = geteuid(); + + /* do we have elevated privileges to attempt RT priority */ + if (uid < 0 || uid != euid) { + /* attempt to set thread priority - needs suid */ + fprintf(sp->log, "pipe: set RT priority\n"); + + err = pthread_attr_init(&attr); + if (err < 0) { + fprintf(sp->log, "error: can't create thread attr %d %s\n", + err, strerror(errno)); + return err; + } + + err = pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + if (err < 0) { + fprintf(sp->log, "error: can't set thread policy %d %s\n", + err, strerror(errno)); + return err; + } + param.sched_priority = 80; + err = pthread_attr_setschedparam(&attr, ¶m); + if (err < 0) { + fprintf(sp->log, "error: can't set thread sched param %d %s\n", + err, strerror(errno)); + return err; + } + err = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + if (err < 0) { + fprintf(sp->log, "error: can't set thread inherit %d %s\n", + err, strerror(errno)); + return err; + } + } else { + fprintf(sp->log, "error: no elevated privileges for RT. uid %d euid %d\n", + uid, euid); + } + + return 0; +} diff --git a/tools/plugin/pipe/ctl.c b/tools/plugin/pipe/ctl.c new file mode 100644 index 000000000000..c2c806621927 --- /dev/null +++ b/tools/plugin/pipe/ctl.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood + +/* + * SOF pipeline in userspace. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "pipe.h" + +int pipe_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, + void *_comp, void *arg) +{ + struct sof_pipe *sp = arg; + struct sof_ipc_comp *comp = _comp; + struct plug_shm_glb_state *glb = sp->glb; + struct plug_shm_ctl *ctl; + + if (glb->num_ctls >= MAX_CTLS) { + fprintf(sp->log, "error: too many ctls\n"); + return -EINVAL; + } + + switch (tplg_ctl->type) { + case SND_SOC_TPLG_CTL_VOLSW: + case SND_SOC_TPLG_CTL_VOLSW_SX: + case SND_SOC_TPLG_CTL_VOLSW_XR_SX: + { + struct snd_soc_tplg_mixer_control *tplg_mixer = + (struct snd_soc_tplg_mixer_control *)tplg_ctl; + + glb->size += sizeof(struct plug_shm_ctl); + ctl = &glb->ctl[glb->num_ctls++]; + ctl->comp_id = comp->id; + ctl->mixer_ctl = *tplg_mixer; + break; + } + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_CTL_ENUM_VALUE: + { + struct snd_soc_tplg_enum_control *tplg_enum = + (struct snd_soc_tplg_enum_control *)tplg_ctl; + + glb->size += sizeof(struct plug_shm_ctl); + ctl = &glb->ctl[glb->num_ctls++]; + ctl->comp_id = comp->id; + ctl->enum_ctl = *tplg_enum; + break; + } + case SND_SOC_TPLG_CTL_BYTES: + { + struct snd_soc_tplg_bytes_control *tplg_bytes = + (struct snd_soc_tplg_bytes_control *)tplg_ctl; + + glb->size += sizeof(struct plug_shm_ctl); + ctl = &glb->ctl[glb->num_ctls++]; + ctl->comp_id = comp->id; + ctl->bytes_ctl = *tplg_bytes; + break; + } + case SND_SOC_TPLG_CTL_RANGE: + case SND_SOC_TPLG_CTL_STROBE: + default: + fprintf(sp->log, "error: invalid ctl type %d\n", + tplg_ctl->type); + return -EINVAL; + } + + return 0; +} diff --git a/tools/plugin/pipe/ipc4.c b/tools/plugin/pipe/ipc4.c new file mode 100644 index 000000000000..9320eeef1999 --- /dev/null +++ b/tools/plugin/pipe/ipc4.c @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood + +/* + * SOF pipeline in userspace. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "pipe.h" + +// TODO: take prefix from ALSA prefix +#define COMP_PREFIX "./sof_ep/install/lib/libsof_" +#define COMP_SUFFIX ".so" +#define UUID_STR_SIZE 32 + +struct sof_pipe_module_library_map { + int module_id; + const char *name; +}; + +static const struct sof_pipe_module_library_map library_map[] = { + {0x6, "libsof_volume.so"}, + {0x2, "libsof_mixer.so"}, + {0x3, "libsof_mixer.so"}, + /*FIXME: hack for now to set up ALSA and SHM components */ + {0x96, "libsof_mod_shm.so"}, /* host playback */ + {0x97, "libsof_mod_alsa.so"}, /* dai playback */ + {0x98, "libsof_mod_shm.so"}, /* host capture */ + {0x99, "libsof_mod_alsa.so"}, /* dai capture */ +}; + +static int pipe_register_comp(struct sof_pipe *sp, uint16_t module_id) +{ + const struct sof_pipe_module_library_map *lib; + int i; + + /* check if module already loaded */ + for (i = 0; i < sp->mod_idx; i++) { + if (sp->module[i].module_id == module_id) + return 0; /* module found and already loaded */ + } + + for (i = 0; i < ARRAY_SIZE(library_map); i++) { + lib = &library_map[i]; + + if (module_id == lib->module_id) + break; + } + + if (i == ARRAY_SIZE(library_map)) { + fprintf(stderr, "module ID: %d not supported\n", module_id); + return -ENOTSUP; + } + + /* not loaded, so load module */ + sp->module[sp->mod_idx].handle = dlopen(lib->name, RTLD_NOW); + if (!sp->module[sp->mod_idx].handle) { + fprintf(stderr, "error: cant load module %s: %s\n", + lib->name, dlerror()); + return -errno; + } + + sp->mod_idx++; + + return 0; +} + +#define iCS(x) ((x) & SOF_CMD_TYPE_MASK) +#define iGS(x) ((x) & SOF_GLB_TYPE_MASK) + +static int pipe_sof_ipc_cmd_before(struct sof_pipe *sp, void *mailbox, size_t bytes) +{ + struct ipc4_message_request *in = mailbox; + enum ipc4_message_target target = in->primary.r.msg_tgt; + int ret = 0; + + switch (target) { + case SOF_IPC4_MESSAGE_TARGET_MODULE_MSG: + { + uint32_t type = in->primary.r.type; + + switch (type) { + case SOF_IPC4_MOD_INIT_INSTANCE: + struct ipc4_module_init_instance *module_init = + (struct ipc4_module_init_instance *)in; + + ret = pipe_register_comp(sp, module_init->primary.r.module_id); + break; + default: + break; + } + break; + } + case SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG: + { + uint32_t type = in->primary.r.type; + + switch (type) { + case SOF_IPC4_GLB_SET_PIPELINE_STATE: + { + struct ipc4_pipeline_set_state *state; + struct ipc_comp_dev *ipc_pipe; + struct ipc *ipc = ipc_get(); + unsigned int pipeline_id; + + state = (struct ipc4_pipeline_set_state *)in; + pipeline_id = (unsigned int)state->primary.r.ppl_id; + + if (state->primary.r.ppl_state == SOF_IPC4_PIPELINE_STATE_PAUSED) { + ipc_pipe = ipc_get_pipeline_by_id(ipc, pipeline_id); + if (!ipc_pipe) { + fprintf(stderr, "No pipeline with instance_id = %u", + pipeline_id); + return -EINVAL; + } + + /* stop the pipeline thread */ + ret = pipe_thread_stop(sp, ipc_pipe->pipeline); + if (ret < 0) { + printf("error: can't start pipeline %d thread\n", + ipc_pipe->pipeline->comp_id); + return ret; + } + } + break; + } + default: + break; + } + break; + } + default: + fprintf(sp->log, "ipc: unknown command target %u size %ld", + target, bytes); + ret = -EINVAL; + break; + } + + return ret; +} + +static int pipe_sof_ipc_cmd_after(struct sof_pipe *sp, void *mailbox, size_t bytes) +{ + struct ipc4_message_request *in = mailbox; + enum ipc4_message_target target = in->primary.r.msg_tgt; + int ret = 0; + + switch (target) { + case SOF_IPC4_MESSAGE_TARGET_MODULE_MSG: + break; + case SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG: + { + uint32_t type = in->primary.r.type; + + switch (type) { + case SOF_IPC4_GLB_CREATE_PIPELINE: + { + struct ipc4_pipeline_create *pipe_desc = (struct ipc4_pipeline_create *)in; + struct ipc_comp_dev *ipc_pipe; + struct ipc *ipc = ipc_get(); + unsigned int pipeline_id = (unsigned int)pipe_desc->primary.r.instance_id; + + ipc_pipe = ipc_get_pipeline_by_id(ipc, pipeline_id); + if (!ipc_pipe) { + fprintf(stderr, "No pipeline with instance_id = %u\n", + pipeline_id); + return -EINVAL; + } + + /* create new pipeline thread */ + ret = pipe_thread_new(sp, ipc_pipe->pipeline); + if (ret < 0) { + printf("error: can't create pipeline %d thread\n", + ipc_pipe->pipeline->pipeline_id); + return ret; + } + break; + } + case SOF_IPC4_GLB_SET_PIPELINE_STATE: + { + struct ipc4_pipeline_set_state *state; + struct ipc_comp_dev *ipc_pipe; + struct ipc *ipc = ipc_get(); + unsigned int pipeline_id; + + state = (struct ipc4_pipeline_set_state *)in; + pipeline_id = (unsigned int)state->primary.r.ppl_id; + + if (state->primary.r.ppl_state == SOF_IPC4_PIPELINE_STATE_RUNNING) { + ipc_pipe = ipc_get_pipeline_by_id(ipc, pipeline_id); + if (!ipc_pipe) { + fprintf(stderr, "No pipeline with instance_id = %u\n", + pipeline_id); + return -EINVAL; + } + + /* start the pipeline thread */ + ret = pipe_thread_start(sp, ipc_pipe->pipeline); + if (ret < 0) { + printf("error: can't start pipeline %d thread\n", + ipc_pipe->pipeline->comp_id); + return ret; + } + } + break; + } + case SOF_IPC4_GLB_DELETE_PIPELINE: + { + struct ipc4_pipeline_create *pipe_desc = (struct ipc4_pipeline_create *)in; + unsigned int pipeline_id = (unsigned int)pipe_desc->primary.r.instance_id; + + /* free pipeline thread */ + ret = pipe_thread_free(sp, pipeline_id); + if (ret < 0) { + printf("error: can't free pipeline %d thread\n", + pipeline_id); + return ret; + } + + break; + } + default: + break; + } + break; + } + default: + fprintf(sp->log, "ipc: unknown command target %u size %ld", + target, bytes); + ret = -EINVAL; + break; + } + + return ret; +} + +int pipe_ipc_do(struct sof_pipe *sp, void *mailbox, size_t bytes) +{ + char mailbox_copy[IPC3_MAX_MSG_SIZE] = {0}; + int err = 0; + + /* preserve mailbox contents for local "after" config */ + memcpy(mailbox_copy, mailbox, bytes); + + /* some IPCs require pipe to perform actions before core */ + /* mailbox can be re-written here by local pipe if needed */ + err = pipe_sof_ipc_cmd_before(sp, mailbox, bytes); + if (err < 0) { + fprintf(sp->log, "error: local IPC processing failed\n"); + return err; + } + + /* is the IPC local only or do we need send to infra ? */ + err = pipe_ipc_message(sp, mailbox, bytes); + if (err < 0) { + fprintf(sp->log, "error: infra IPC processing failed\n"); + return err; + } + + /* some IPCs require pipe to perform actions before core */ + err = pipe_sof_ipc_cmd_after(sp, mailbox_copy, bytes); + if (err < 0) { + fprintf(sp->log, "error: local IPC processing failed\n"); + return err; + } + + return err; +} + +int pipe_ipc_process(struct sof_pipe *sp, struct plug_mq_desc *tx_mq, struct plug_mq_desc *rx_mq) +{ + ssize_t ipc_size; + char mailbox[IPC3_MAX_MSG_SIZE] = {0}; + int err; + struct timespec ts; + + /* IPC thread should not preempt processing thread */ + err = pipe_set_ipc_lowpri(sp); + if (err < 0) + fprintf(sp->log, "error: cant set PCM IPC thread to low priority"); + + /* create the IPC message queue */ + err = plug_mq_create(tx_mq); + if (err < 0) { + fprintf(sp->log, "error: can't create TX IPC message queue : %s\n", + strerror(errno)); + return -errno; + } + + /* create the IPC message queue */ + err = plug_mq_create(rx_mq); + if (err < 0) { + fprintf(sp->log, "error: can't create PCM IPC message queue : %s\n", + strerror(errno)); + return -errno; + } + + /* let main() know we are ready */ + fprintf(sp->log, "sof-pipe: IPC TX %s thread ready\n", tx_mq->queue_name); + fprintf(sp->log, "sof-pipe: IPC RX %s thread ready\n", rx_mq->queue_name); + + /* main PCM IPC handling loop */ + while (1) { + memset(mailbox, 0, IPC3_MAX_MSG_SIZE); + + /* is client dead ? */ + if (sp->glb->state == SOF_PLUGIN_STATE_DEAD) { + fprintf(sp->log, "sof-pipe: IPC %s client complete\n", tx_mq->queue_name); + break; + } + + ipc_size = mq_receive(tx_mq->mq, mailbox, IPC3_MAX_MSG_SIZE, NULL); + if (ipc_size < 0) { + fprintf(sp->log, "error: can't read PCM IPC message queue %s : %s\n", + tx_mq->queue_name, strerror(errno)); + break; + } + + /* TODO: properly validate message and continue if garbage */ + if (*((uint32_t *)mailbox) == 0) { + fprintf(sp->log, "sof-pipe: IPC %s garbage read\n", tx_mq->queue_name); + ts.tv_sec = 0; + ts.tv_nsec = 20 * 1000 * 1000; /* 20 ms */ + nanosleep(&ts, NULL); + continue; + } + + /* do the message work */ + //data_dump(mailbox, IPC3_MAX_MSG_SIZE); + + err = pipe_ipc_do(sp, mailbox, ipc_size); + if (err < 0) + fprintf(sp->log, "error: local IPC processing failed\n"); + + /* now return message completion status found in mailbox */ + err = mq_send(rx_mq->mq, mailbox, IPC3_MAX_MSG_SIZE, 0); + if (err < 0) { + fprintf(sp->log, "error: can't send PCM IPC message queue %s : %s\n", + rx_mq->queue_name, strerror(errno)); + break; + } + } + + fprintf(sp->log, "***sof-pipe: IPC %s thread finished !!\n", tx_mq->queue_name); + return 0; +} + +int plug_mq_cmd(struct plug_mq_desc *ipc, void *msg, size_t len, void *reply, size_t rlen) +{ + struct timespec ts; + ssize_t ipc_size; + char mailbox[IPC3_MAX_MSG_SIZE]; + int err; + + if (len > IPC3_MAX_MSG_SIZE) { + SNDERR("ipc: message too big %d\n", len); + return -EINVAL; + } + memset(mailbox, 0, IPC3_MAX_MSG_SIZE); + memcpy(mailbox, msg, len); + + /* wait for sof-pipe reader to consume data or timeout */ + err = clock_gettime(CLOCK_REALTIME, &ts); + if (err == -1) { + SNDERR("ipc: cant get time: %s", strerror(errno)); + return -errno; + } + + /* IPCs should be read under 10ms */ + plug_timespec_add_ms(&ts, 10); + + /* now return message completion status */ + err = mq_timedsend(ipc->mq, mailbox, IPC3_MAX_MSG_SIZE, 0, &ts); + if (err < 0) { + SNDERR("error: can't send IPC message queue %s : %s\n", + ipc->queue_name, strerror(errno)); + return -errno; + } + + /* wait for sof-pipe reader to consume data or timeout */ + err = clock_gettime(CLOCK_REALTIME, &ts); + if (err == -1) { + SNDERR("ipc: cant get time: %s", strerror(errno)); + return -errno; + } + + /* IPCs should be processed under 20ms */ + plug_timespec_add_ms(&ts, 20); + + ipc_size = mq_timedreceive(ipc->mq, mailbox, IPC3_MAX_MSG_SIZE, NULL, &ts); + if (ipc_size < 0) { + SNDERR("error: can't read IPC message queue %s : %s\n", + ipc->queue_name, strerror(errno)); + return -errno; + } + + /* do the message work */ + //printf("cmd got IPC %ld reply bytes\n", ipc_size); + if (rlen && reply) + memcpy(reply, mailbox, rlen); + + return 0; +} diff --git a/tools/plugin/pipe/main.c b/tools/plugin/pipe/main.c new file mode 100644 index 000000000000..3d9c831dba0b --- /dev/null +++ b/tools/plugin/pipe/main.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood + +/* + * SOF pipeline in userspace. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "pipe.h" + +#define VERSION "v0.1" + +/* global needed for signal handler */ +struct sof_pipe *_sp; + +static void shutdown(struct sof_pipe *sp) +{ + struct pipethread_data *pipeline_ctx = sp->pipeline_ctx; + int i; + + /* free everything */ + munmap(sp->shm_context.addr, sp->shm_context.size); + shm_unlink(sp->shm_context.name); + + /* cancel all threads, free locks and message queues */ + for (i = 0; i < sp->pipe_thread_count; i++) { + struct pipethread_data *pd = &pipeline_ctx[i]; + + pthread_cancel(pd->ipc_thread); + pthread_cancel(pd->pcm_thread); + plug_mq_free(&pd->ipc_tx_mq); + plug_mq_free(&pd->ipc_rx_mq); + plug_lock_free(&pd->ready); + plug_lock_free(&pd->done); + } + + /* free the sof-pipe IPC tx/rx message queues */ + plug_mq_free(&sp->ipc_tx_mq); + plug_mq_free(&sp->ipc_rx_mq); + + pthread_mutex_destroy(&sp->ipc_lock); + + fflush(sp->log); + fflush(stdout); + fflush(stderr); +} + +/* signals from the ALSA PCM plugin or something has gone wrong */ +static void signal_handler(int sig) +{ + switch (sig) { + case SIGTERM: + fprintf(_sp->log, "Pipe caught SIGTERM - shutdown\n"); + break; + case SIGINT: + fprintf(_sp->log, "Pipe caught SIGINT - shutdown\n"); + break; + default: + fprintf(_sp->log, "Pipe caught signal %d, something went wrong\n", sig); + break; + } + fprintf(_sp->log, "Pipe shutdown signal\n"); + + /* try and clean up if we can */ + shutdown(_sp); + exit(EXIT_FAILURE); +} + +static int pipe_init_signals(struct sof_pipe *sp) +{ + struct sigaction *action = &sp->action; + int err; + + /* + * signals - currently only check for SIGCHLD. TODO: handle more + */ + sigemptyset(&action->sa_mask); + action->sa_handler = signal_handler; + err = sigaction(SIGTERM, action, NULL); + if (err < 0) { + fprintf(sp->log, "failed to register signal action: %s", + strerror(errno)); + return err; + } + + err = sigaction(SIGSEGV, action, NULL); + if (err < 0) { + fprintf(sp->log, "failed to register signal action: %s", + strerror(errno)); + return err; + } + + err = sigaction(SIGINT, action, NULL); + if (err < 0) { + fprintf(sp->log, "failed to register signal action: %s", + strerror(errno)); + return err; + } + + return 0; +} + +int pipe_ipc_message(struct sof_pipe *sp, void *mailbox, size_t bytes) +{ + struct ipc *ipc = ipc_get(); + + /* reply is copied back to mailbox */ + pthread_mutex_lock(&sp->ipc_lock); + memcpy(ipc->comp_data, mailbox, bytes); + ipc_cmd(mailbox); + memcpy(mailbox, ipc->comp_data, bytes); + pthread_mutex_unlock(&sp->ipc_lock); + + return 0; +} + +/* + * Create and open a new semaphore using the lock object. + */ +int plug_lock_create(struct plug_sem_desc *lock) +{ + /* delete any old stale resources that use our resource name */ + sem_unlink(lock->name); + + /* RW blocking lock */ + lock->sem = sem_open(lock->name, O_CREAT | O_RDWR | O_EXCL, SEM_PERMS, 0); + if (lock->sem == SEM_FAILED) { + SNDERR("failed to create semaphore %s: %s", lock->name, strerror(errno)); + return -errno; + } + + return 0; +} + +/* + * Free and delete semaphore resourses in lock object. + */ +void plug_lock_free(struct plug_sem_desc *lock) +{ + sem_close(lock->sem); + sem_unlink(lock->name); +} + +/* + * Create and open a new shared memory region using the SHM object. + */ +int plug_shm_create(struct plug_shm_desc *shm) +{ + int err; + + /* delete any old stale resources that use our resource name */ + shm_unlink(shm->name); + + /* open SHM to be used for low latency position */ + shm->fd = shm_open(shm->name, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG); + if (shm->fd < 0) { + SNDERR("failed to create SHM position %s: %s", shm->name, strerror(errno)); + return -errno; + } + + /* set SHM size */ + err = ftruncate(shm->fd, shm->size); + if (err < 0) { + SNDERR("failed to truncate SHM position %s: %s", shm->name, strerror(errno)); + shm_unlink(shm->name); + return -errno; + } + + /* map it locally for context readback */ + shm->addr = mmap(NULL, shm->size, PROT_READ | PROT_WRITE, MAP_SHARED, shm->fd, 0); + if (!shm->addr) { + SNDERR("failed to mmap SHM position%s: %s", shm->name, strerror(errno)); + shm_unlink(shm->name); + return -errno; + } + + return 0; +} + +/* + * Free and delete shared memory region resourses in SHM object. + */ +void plug_shm_free(struct plug_shm_desc *shm) +{ + close(shm->fd); + shm_unlink(shm->name); +} + +/* + * Create and open a new message queue using the IPC object. + */ +int plug_mq_create(struct plug_mq_desc *ipc) +{ + /* delete any old stale resources that use our resource name */ + mq_unlink(ipc->queue_name); + + memset(&ipc->attr, 0, sizeof(ipc->attr)); + ipc->attr.mq_msgsize = IPC3_MAX_MSG_SIZE; + ipc->attr.mq_maxmsg = 1; + + /* now open new queue for Tx/Rx */ + ipc->mq = mq_open(ipc->queue_name, O_CREAT | O_RDWR | O_EXCL, + S_IRWXU | S_IRWXG, &ipc->attr); + if (ipc->mq < 0) { + fprintf(stderr, "failed to create IPC queue %s: %s\n", + ipc->queue_name, strerror(errno)); + return -errno; + } + + return 0; +} + +/* + * Free and delete message queue resources in IPC object. + */ +void plug_mq_free(struct plug_mq_desc *ipc) +{ + mq_close(ipc->mq); + mq_unlink(ipc->queue_name); +} + +/* + * -D ALSA device. e.g. + * -R realtime (needs parent to set uid) + * -p Force run on P core + * -e Force run on E core + * -t topology name. + * -L log file (otherwise stdout) + * -h help + */ +static void usage(char *name) +{ + fprintf(stdout, "Usage: %s -D ALSA device -T topology\n", name); +} + +int main(int argc, char *argv[], char *env[]) +{ + struct sof_pipe sp = {0}; + int option = 0; + int ret = 0; + + /* default config */ + sp.log = stdout; + sp.alsa_name = "default"; /* default sound device */ + _sp = &sp; + + /* parse all args */ + while ((option = getopt(argc, argv, "hD:RpeT:")) != -1) { + switch (option) { + /* Alsa device */ + case 'D': + sp.alsa_name = strdup(optarg); + break; + case 'R': + sp.realtime = 1; + break; + case 'p': + sp.use_P_core = 1; + sp.use_E_core = 0; + break; + case 'e': + sp.use_E_core = 1; + sp.use_P_core = 0; + break; + case 'T': + snprintf(sp.topology_name, NAME_SIZE, "%s", optarg); + break; + + /* print usage */ + default: + fprintf(sp.log, "unknown option %c\n", option); + __attribute__ ((fallthrough)); + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + } + } + + /* validate cmd line params */ + if (strlen(sp.topology_name) == 0) { + fprintf(sp.log, "error: no IPC topology name specified\n"); + exit(EXIT_FAILURE); + } + + /* global IPC access serialisation mutex */ + ret = pthread_mutex_init(&sp.ipc_lock, NULL); + if (ret < 0) { + fprintf(sp.log, "error: cant create mutex %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + fprintf(sp.log, "sof-pipe-%s: using topology %s\n", VERSION, sp.topology_name); + + /* set CPU affinity */ + if (sp.use_E_core || sp.use_P_core) { + ret = pipe_set_affinity(&sp); + if (ret < 0) + goto out; + } + + /* initialize ipc and scheduler */ + if (pipe_sof_setup(sof_get()) < 0) { + fprintf(stderr, "error: pipeline init\n"); + exit(EXIT_FAILURE); + } + + /* global context - plugin clients open this first */ + ret = plug_shm_init(&sp.shm_context, sp.topology_name, "ctx", 0); + if (ret < 0) + goto out; + + /* cleanup any lingering global IPC files */ + shm_unlink(sp.shm_context.name); + + /* make sure we can cleanly shutdown */ + ret = pipe_init_signals(&sp); + if (ret < 0) + goto out; + + /* mmap context on successful topology load */ + ret = plug_shm_create(&sp.shm_context); + if (ret < 0) + goto out; + + /* now prep the global context for client plugin access */ + sp.glb = sp.shm_context.addr; + memset(sp.glb, 0, sizeof(*sp.glb)); + sprintf(sp.glb->magic, "%s", SOF_MAGIC); + sp.glb->size = sizeof(*sp.glb); + sp.glb->state = SOF_PLUGIN_STATE_INIT; + sp.tplg.tplg_file = sp.topology_name; + sp.tplg.ipc_major = 4; //HACK hard code to v4 + + /* sofpipe is now ready */ + sp.glb->state = SOF_PLUGIN_STATE_INIT; + + ret = plug_mq_init(&sp.ipc_tx_mq, "sof", "ipc-tx", 0); + if (ret < 0) + goto out; + + ret = plug_mq_init(&sp.ipc_rx_mq, "sof", "ipc-rx", 0); + if (ret < 0) + goto out; + + /* now process IPCs as they arrive from plugins */ + ret = pipe_ipc_process(&sp, &sp.ipc_tx_mq, &sp.ipc_rx_mq); + +out: + fprintf(sp.log, "shutdown main\n"); + shutdown(&sp); + return ret; +} diff --git a/tools/plugin/pipe/pipe.h b/tools/plugin/pipe/pipe.h new file mode 100644 index 000000000000..3cc95bf8401e --- /dev/null +++ b/tools/plugin/pipe/pipe.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022-2023 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOF_PLUGIN_PIPE_H__ +#define __SOF_PLUGIN_PIPE_H__ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "common.h" + +struct sof_pipe; + +#define MAX_MODULE_ID 256 +#define MAX_PIPE_THREADS 128 +#define MAX_PIPELINES 32 + +struct pipethread_data { + pthread_t pcm_thread; + pthread_t ipc_thread; + struct sof_pipe *sp; + struct plug_mq_desc ipc_tx_mq; + struct plug_mq_desc ipc_rx_mq; + struct pipeline *pcm_pipeline; + /* PCM flow control */ + struct plug_sem_desc ready; + struct plug_sem_desc done; + atomic_int pipe_users; +}; + +struct sof_pipe_module { + void *handle; + char uuid[SOF_UUID_SIZE]; + int module_id; +}; + +struct sof_pipe { + const char *alsa_name; + char topology_name[NAME_SIZE]; + int realtime; + int use_P_core; + int use_E_core; + int capture; + int file_mode; + int pipe_thread_count; + + struct sigaction action; + + /* SHM for stream context sync */ + struct plug_shm_desc shm_context; + struct plug_shm_glb_state *glb; + + FILE *log; + pthread_mutex_t ipc_lock; + struct tplg_context tplg; + struct tplg_comp_info *comp_list; + struct list_item widget_list; /* list of widgets */ + struct list_item route_list; /* list of widget connections */ + struct list_item pcm_list; /* list of PCMs */ + int info_elems; + int info_index; + + /* IPC */ + pthread_t ipc_pcm_thread; + struct plug_mq_desc ipc_tx_mq; /* queue used by plugin to send IPCs */ + struct plug_mq_desc ipc_rx_mq; /* queue used by plugin to receive the IPC response */ + + /* module SO handles */ + struct sof_pipe_module module[MAX_MODULE_ID]; + int mod_idx; + + /* pipeline context */ + struct pipethread_data pipeline_ctx[MAX_PIPELINES]; +}; + +/* global needed for signal handler */ +extern struct sof_pipe *_sp; + +int pipe_thread_new(struct sof_pipe *sp, struct pipeline *p); +int pipe_thread_free(struct sof_pipe *sp, int pipeline_id); +int pipe_thread_start(struct sof_pipe *sp, struct pipeline *p); +int pipe_thread_stop(struct sof_pipe *sp, struct pipeline *p); +int pipe_sof_setup(struct sof *sof); +int pipe_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, + void *comp, void *arg); + +/* set pipeline to realtime priority */ +int pipe_set_rt(struct sof_pipe *sp); + +/* set ipc thread to low priority */ +int pipe_set_ipc_lowpri(struct sof_pipe *sp); + +int pipe_ipc_process(struct sof_pipe *sp, struct plug_mq_desc *tx_mq, struct plug_mq_desc *rx_mq); + +int pipe_ipc_new(struct sof_pipe *sp, int pri, int core); +void pipe_ipc_free(struct sof_pipe *sp); + +int pipe_set_affinity(struct sof_pipe *sp); + +int pipe_ipc_message(struct sof_pipe *sp, void *mailbox, size_t bytes); + +int pipe_ipc_do(struct sof_pipe *sp, void *mailbox, size_t bytes); + +/* + * Topology + */ +int plug_parse_topology(struct sof_pipe *sp, struct tplg_context *ctx); + +int plug_load_widget(struct sof_pipe *sp, struct tplg_context *ctx); + +int plug_register_graph(struct sof_pipe *sp, struct tplg_context *ctx, + struct tplg_comp_info *temp_comp_list, + char *pipeline_string, + int count, int num_comps, int pipeline_id); + +#endif diff --git a/tools/plugin/pipe/pipeline.c b/tools/plugin/pipe/pipeline.c new file mode 100644 index 000000000000..831b60a3b6a9 --- /dev/null +++ b/tools/plugin/pipe/pipeline.c @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood + +/* + * SOF pipeline in userspace. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "pipe.h" + +#define MAX_PIPE_USERS 8 + +static struct ll_schedule_domain domain = {0}; + +// TODO: all these steps are probably not needed - i.e we only need IPC and pipeline. +int pipe_sof_setup(struct sof *sof) +{ + /* register modules */ + + domain.next_tick = 0; + + /* init components */ + sys_comp_init(sof); + + /* other necessary initializations, todo: follow better SOF init */ + pipeline_posn_init(sof); + init_system_notify(sof); + + /* init IPC */ + if (ipc_init(sof) < 0) { + fprintf(stderr, "error: IPC init\n"); + return -EINVAL; + } + + /* init LL scheduler */ + if (scheduler_init_ll(&domain) < 0) { + fprintf(stderr, "error: edf scheduler init\n"); + return -EINVAL; + } + + /* init EDF scheduler */ + if (scheduler_init_edf() < 0) { + fprintf(stderr, "error: edf scheduler init\n"); + return -EINVAL; + } + + return 0; +} + +static inline int pipe_copy_ready(struct pipethread_data *pd) +{ + struct timespec delay; + int err; + + /* get the current time for source delay */ + err = clock_gettime(CLOCK_REALTIME, &delay); + if (err == -1) { + fprintf(_sp->log, "shm: cant get time: %s", strerror(errno)); + return -errno; + } + + // TODO get from rate + plug_timespec_add_ms(&delay, 2000); + + /* wait for data from source */ + err = sem_timedwait(pd->ready.sem, &delay); + if (err == -1) { + fprintf(_sp->log, "%s %d: fatal timeout: %s on %s\n", __FILE__, __LINE__, + strerror(errno), pd->ready.name); + return -errno; + } + + return 0; +} + +static inline void pipe_copy_done(struct pipethread_data *pd) +{ + /* tell peer we are done */ + sem_post(pd->done.sem); +} + +static void *pipe_process_thread(void *arg) +{ + struct pipethread_data *pd = arg; + int err; + + fprintf(_sp->log, "pipe thread started for pipeline %d\n", + pd->pcm_pipeline->pipeline_id); + + do { + if (pd->pcm_pipeline->status != COMP_STATE_ACTIVE) { + fprintf(_sp->log, "pipe state non active %d\n", + pd->pcm_pipeline->status); + break; + } + + if (pd->pipe_users <= 0) { + fprintf(_sp->log, "pipe no users.\n"); + break; + } + + /* wait for pipe to be ready */ + err = pipe_copy_ready(pd); + if (err < 0) { + fprintf(_sp->log, "pipe ready timeout on pipeline %d state %d users %d\n", + pd->pcm_pipeline->pipeline_id, pd->pcm_pipeline->status, + pd->pipe_users); + break; + } + + /* sink has read data so now generate more it */ + err = pipeline_copy(pd->pcm_pipeline); + + pipe_copy_done(pd); + + if (err < 0) { + fprintf(_sp->log, "pipe thread error %d\n", err); + break; + } else if (err > 0) { + fprintf(_sp->log, "pipe thread complete %d\n", err); + break; + } + + } while (1); + + fprintf(_sp->log, "pipe complete for pipeline %d\n", + pd->pcm_pipeline->pipeline_id); + return 0; +} + +static void *pipe_ipc_process_thread(void *arg) +{ + struct pipethread_data *pd = arg; + int err; + + /* initialise semaphores to default starting value */ + err = sem_init(pd->done.sem, 1, 0); + if (err < 0) { + fprintf(_sp->log, "failed to reset DONE: %s\n", + strerror(errno)); + return NULL; + } + err = sem_init(pd->ready.sem, 1, 0); + if (err < 0) { + fprintf(_sp->log, "failed to reset READY: %s\n", + strerror(errno)); + return NULL; + } + + err = pipe_ipc_process(pd->sp, &pd->ipc_tx_mq, &pd->ipc_rx_mq); + if (err < 0) { + fprintf(_sp->log, "pipe IPC thread error for pipeline %d\n", + pd->pcm_pipeline->pipeline_id); + } + + return NULL; +} + +int pipe_thread_start(struct sof_pipe *sp, struct pipeline *p) +{ + struct pipethread_data *pipeline_ctx = sp->pipeline_ctx; + struct pipethread_data *pd; + int pipeline_id; + int ret, pipe_users; + + pipeline_id = p->pipeline_id; + + if (pipeline_id >= MAX_PIPELINES) { + fprintf(_sp->log, "error: pipeline ID %d out of range\n", pipeline_id); + return -EINVAL; + } + + if (!pipeline_ctx[pipeline_id].sp) { + fprintf(_sp->log, "error: pipeline ID %d not in use\n", pipeline_id); + return -EINVAL; + } + pd = &pipeline_ctx[pipeline_id]; + + /* only create thread if not active */ + pipe_users = atomic_fetch_add(&pd->pipe_users, 1); + if (pipe_users > 0) { + fprintf(_sp->log, "pipeline ID %d thread already running %d users\n", + pipeline_id, pipe_users); + return 0; + } + + fprintf(_sp->log, "pipeline ID %d thread not running so starting...\n", pipeline_id); + + /* first user so start the PCM pipeline thread */ + ret = pthread_create(&pd->pcm_thread, NULL, pipe_process_thread, pd); + if (ret < 0) { + fprintf(_sp->log, "failed to create PCM thread: %s\n", strerror(errno)); + return -errno; + } + + return ret; +} + +int pipe_thread_stop(struct sof_pipe *sp, struct pipeline *p) +{ + struct pipethread_data *pipeline_ctx = sp->pipeline_ctx; + struct pipethread_data *pd; + int pipeline_id; + int ret, pipe_users; + + pipeline_id = p->pipeline_id; + + /* this is called when the pipeline is PAUSED for the first time before RUNNING */ + if (p->status == COMP_STATE_INIT) + return 0; + + if (pipeline_id >= MAX_PIPELINES) { + fprintf(_sp->log, "error: pipeline ID %d out of range\n", pipeline_id); + return -EINVAL; + } + + if (!pipeline_ctx[pipeline_id].sp) { + fprintf(_sp->log, "error: pipeline ID %d not in use\n", pipeline_id); + return -EINVAL; + } + pd = &pipeline_ctx[pipeline_id]; + + /* only join thread if not active */ + pipe_users = atomic_fetch_sub(&pd->pipe_users, 1); + if (pipe_users != 1) { + fprintf(_sp->log, "pipeline ID %d thread has multiple %d users\n", + pipeline_id, pipe_users); + return 0; + } + + fprintf(_sp->log, "pipeline ID %d thread can be stopped...\n", pipeline_id); + + ret = pthread_cancel(pd->pcm_thread); + if (ret < 0) { + fprintf(_sp->log, "failed to cancel PCM thread: %s\n", strerror(errno)); + return -errno; + } + + return ret; +} + +int pipe_thread_new(struct sof_pipe *sp, struct pipeline *p) +{ + struct pipethread_data *pipeline_ctx = sp->pipeline_ctx; + struct pipethread_data *pd; + int ret; + + if (!p) { + fprintf(_sp->log, "error: invalid pipeline\n"); + return -EINVAL; + } + + if (p->pipeline_id >= MAX_PIPELINES) { + fprintf(_sp->log, "error: pipeline ID %d out of range\n", p->pipeline_id); + return -EINVAL; + } + + if (pipeline_ctx[p->pipeline_id].sp) { + fprintf(_sp->log, "error: pipeline ID %d in use\n", p->pipeline_id); + return -EINVAL; + } + pd = &pipeline_ctx[p->pipeline_id]; + pd->sp = _sp; + pd->pcm_pipeline = p; + + /* initialise global IPC data */ + /* TODO: change the PCM name to tplg or make it per PID*/ + ret = plug_mq_init(&pd->ipc_tx_mq, pd->sp->topology_name, "pcm-tx", p->pipeline_id); + if (ret < 0) + return -EINVAL; + mq_unlink(pd->ipc_tx_mq.queue_name); + + ret = plug_mq_init(&pd->ipc_rx_mq, pd->sp->topology_name, "pcm-rx", p->pipeline_id); + if (ret < 0) + return -EINVAL; + mq_unlink(pd->ipc_rx_mq.queue_name); + + /* init names of shared resources */ + ret = plug_lock_init(&pd->ready, _sp->topology_name, "ready", p->pipeline_id); + if (ret < 0) + return ret; + + ret = plug_lock_init(&pd->done, _sp->topology_name, "done", p->pipeline_id); + if (ret) + return ret; + + /* open semaphores */ + ret = plug_lock_create(&pd->ready); + if (ret < 0) + return ret; + ret = plug_lock_create(&pd->done); + if (ret < 0) + goto lock_err; + + /* start IPC pipeline thread */ + ret = pthread_create(&pd->ipc_thread, NULL, pipe_ipc_process_thread, pd); + if (ret < 0) { + fprintf(_sp->log, "failed to create IPC thread: %s\n", strerror(errno)); + ret = -errno; + goto lock2_err; + } + + return 0; + +lock2_err: + plug_lock_free(&pd->done); +lock_err: + plug_lock_free(&pd->ready); + return ret; +} + +int pipe_thread_free(struct sof_pipe *sp, int pipeline_id) +{ + struct pipethread_data *pipeline_ctx = sp->pipeline_ctx; + struct pipethread_data *pd; + int err; + + if (pipeline_id >= MAX_PIPELINES) { + fprintf(_sp->log, "error: pipeline ID %d out of range\n", pipeline_id); + return -EINVAL; + } + + if (!pipeline_ctx[pipeline_id].sp) { + fprintf(_sp->log, "error: pipeline ID %d not in use\n", pipeline_id); + return -EINVAL; + } + + pd = &pipeline_ctx[pipeline_id]; + + err = pthread_cancel(pd->ipc_thread); + if (err < 0) { + fprintf(_sp->log, "failed to create IPC thread: %s\n", strerror(errno)); + return -errno; + } + + plug_mq_free(&pd->ipc_tx_mq); + mq_unlink(pd->ipc_tx_mq.queue_name); + plug_mq_free(&pd->ipc_rx_mq); + mq_unlink(pd->ipc_rx_mq.queue_name); + + plug_lock_free(&pd->ready); + plug_lock_free(&pd->done); + + pd->sp = NULL; + return 0; +} diff --git a/tools/probes/probes_demux.c b/tools/probes/probes_demux.c index 3db021e8a6e3..a411eef117b9 100644 --- a/tools/probes/probes_demux.c +++ b/tools/probes/probes_demux.c @@ -139,8 +139,9 @@ int init_wave(struct dma_frame_parser *p, uint32_t buffer_id, uint32_t format) return i; } -void finalize_wave_files(struct wave_files *files) +void finalize_wave_files(struct dma_frame_parser *p) { + struct wave_files *files = p->files; uint32_t i, chunk_size; /* fill the header at the beginning of each file */ diff --git a/tools/probes/probes_demux.h b/tools/probes/probes_demux.h index a656d4c7af47..93aa89119a5e 100644 --- a/tools/probes/probes_demux.h +++ b/tools/probes/probes_demux.h @@ -24,4 +24,6 @@ void parser_fetch_free_buffer(struct dma_frame_parser *p, uint8_t **d, size_t *l int parser_parse_data(struct dma_frame_parser *p, size_t d_len); +void finalize_wave_files(struct dma_frame_parser *p); + #endif diff --git a/tools/probes/probes_main.c b/tools/probes/probes_main.c index 7b553709a446..cdba2c6347d5 100644 --- a/tools/probes/probes_main.c +++ b/tools/probes/probes_main.c @@ -66,6 +66,10 @@ void parse_data(const char *file_in, bool log_to_stdout) len = fread(data, 1, len, fd_in); ret = parser_parse_data(p, len); } while (!ret && !feof(fd_in)); + + if (!log_to_stdout) + finalize_wave_files(p); + } int main(int argc, char *argv[]) diff --git a/tools/rimage/.checkpatch.conf b/tools/rimage/.checkpatch.conf new file mode 100644 index 000000000000..98ddafcb3fb1 --- /dev/null +++ b/tools/rimage/.checkpatch.conf @@ -0,0 +1,6 @@ +--codespell +--codespellfile scripts/spelling.txt +--ignore C99_COMMENT_TOLERANCE +--no-tree +--strict +-g diff --git a/tools/rimage/.github/workflows/build.yml b/tools/rimage/.github/workflows/build.yml new file mode 100644 index 000000000000..2102fae4f8f0 --- /dev/null +++ b/tools/rimage/.github/workflows/build.yml @@ -0,0 +1,25 @@ +--- +# Basic build test + +name: build + +# yamllint disable-line rule:truthy +on: [pull_request, push, workflow_dispatch] + +env: + CMAKE_C_FLAGS: "-Werror -Wall -Wmissing-prototypes\ + -Wimplicit-fallthrough=3 -Wpointer-arith" + +jobs: + build-test: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + with: {fetch-depth: 50, submodules: recursive} + + - name: install tools + run: sudo apt update && sudo apt install -y ninja-build + + - name: build + run: cmake -B build/ -G Ninja + - run: cmake --build build/ diff --git a/tools/rimage/.github/workflows/cppcheck.yml b/tools/rimage/.github/workflows/cppcheck.yml new file mode 100644 index 000000000000..211e4004692c --- /dev/null +++ b/tools/rimage/.github/workflows/cppcheck.yml @@ -0,0 +1,30 @@ +--- +# SPDX-License-Identifier: BSD-3-Clause +# Tools that can save round-trips to github and a lot of time: +# +# yamllint -f parsable this.yml +# pip3 install ruamel.yaml.cmd +# yaml merge-expand this.yml exp.yml && diff -w -u this.yml exp.yml +# +# github.com also has a powerful web editor that can be used without +# committing. + +name: cppcheck + +# yamllint disable-line rule:truthy +on: [pull_request, push] + +jobs: + cppcheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: {fetch-depth: 50, submodules: recursive} + + - name: apt install cppcheck + run: sudo apt update && sudo apt-get -y install cppcheck + + # TODO enable more types of checks as they are fixed + - name: run cppcheck + run: cppcheck --platform=unix32 --force --max-configs=1024 + --inconclusive --quiet --inline-suppr . diff --git a/tools/rimage/.github/workflows/pull-request.yml b/tools/rimage/.github/workflows/pull-request.yml new file mode 100644 index 000000000000..c0400490b276 --- /dev/null +++ b/tools/rimage/.github/workflows/pull-request.yml @@ -0,0 +1,42 @@ +--- +# SPDX-License-Identifier: BSD-3-Clause +# Tools that can save round-trips to github and a lot of time: +# +# yamllint -f parsable this.yml +# pip3 install ruamel.yaml.cmd +# yaml merge-expand this.yml exp.yml && diff -w -u this.yml exp.yml +# +# github.com also has a powerful web editor that can be used without +# committing. + +name: codestyle + +# yamllint disable-line rule:truthy +on: [pull_request] + +jobs: + yamllint: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 50 + submodules: recursive + + - name: run yamllint + run: yamllint .github/workflows/*.yml + checkpatch: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: ${{ env.PR_FETCH_DEPTH }} + + - name: install codespell + run: sudo apt update && sudo apt install -y codespell + + - name: checkpatch.pl PR review + uses: webispy/checkpatch-action@v9 + env: + CHECKPATCH_COMMAND: ./scripts/checkpatch.pl diff --git a/tools/rimage/.gitignore b/tools/rimage/.gitignore new file mode 100644 index 000000000000..7693903fddf6 --- /dev/null +++ b/tools/rimage/.gitignore @@ -0,0 +1,2 @@ +build/ +.checkpatch-camelcase.git.* diff --git a/tools/rimage/CMakeLists.txt b/tools/rimage/CMakeLists.txt new file mode 100644 index 000000000000..8e0a5da7d267 --- /dev/null +++ b/tools/rimage/CMakeLists.txt @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.10) + +project(SOF_RIMAGE C) + +if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "No CMAKE_BUILD_TYPE, defaulting to Debug") + set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build Type" FORCE) +endif() + +add_executable(rimage + src/file_simple.c + src/cse.c + src/css.c + src/plat_auth.c + src/hash.c + src/pkcs1_5.c + src/manifest.c + src/ext_manifest.c + src/rimage.c + src/toml_utils.c + src/adsp_config.c + src/misc_utils.c + src/file_utils.c + src/elf_file.c + src/module.c + tomlc99/toml.c +) + +set_property(TARGET rimage PROPERTY C_STANDARD 99) + +target_compile_options(rimage PRIVATE + -Wall -Werror -Wmissing-prototypes -Wimplicit-fallthrough +) + +if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 9.1) + target_compile_options(rimage PRIVATE -Wno-char-subscripts) +endif() + +# Windows builds use MSYS2 https://www.msys2.org/ to get linux tools and headers. +# MSYS_INSTALL_DIR variable points to MSYS2 installation directory. +# You may pass it as environmental or cmake configure variable. +if(${CMAKE_HOST_WIN32}) + cmake_minimum_required(VERSION 3.20) + if(DEFINED ENV{MSYS_INSTALL_DIR} AND NOT MSYS_INSTALL_DIR) + set(MSYS_INSTALL_DIR $ENV{MSYS_INSTALL_DIR}) + endif() + + if(MSYS_INSTALL_DIR) + cmake_path(IS_ABSOLUTE MSYS_INSTALL_DIR IS_MSYS_INSTALL_DIR_ABSOLUTE) + if(NOT IS_MSYS_INSTALL_DIR_ABSOLUTE) + message(FATAL_ERROR "Please provide absolute path to MSYS2 installation + setting MSYS_INSTALL_DIR env variable") + endif() + # Include standard posix headers. Requires pacman openssl-devel package. + cmake_path(APPEND MSYS_INSTALL_DIR "usr" "include" OUTPUT_VARIABLE MSYS_SYSTEM_INCLUDE_PATH) + target_include_directories(rimage PRIVATE "${MSYS_SYSTEM_INCLUDE_PATH}") + endif() +endif() + +target_link_libraries(rimage PRIVATE crypto) + +target_include_directories(rimage PRIVATE + src/include/ + tomlc99/ +) diff --git a/tools/rimage/LICENSE b/tools/rimage/LICENSE new file mode 100644 index 000000000000..468893dff94b --- /dev/null +++ b/tools/rimage/LICENSE @@ -0,0 +1,97 @@ +/* + * BSD 3 Clause + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +// Copyright (c) 2003-2014 Cadence Design Systems, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +Files with 2-Clause BSD licence: + +src/include/rimage/elf.h + +/* + * Derived from: + * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $ + * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $ + * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $ + * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $ + * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $ + * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $ + * + * Copyright (c) 1996-1998 John D. Polstra. All rights reserved. + * Copyright (c) 2001 David E. O'Brien + * Portions Copyright 2009 The Go Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ diff --git a/tools/rimage/README.md b/tools/rimage/README.md new file mode 100644 index 000000000000..64fe71e11ce5 --- /dev/null +++ b/tools/rimage/README.md @@ -0,0 +1,105 @@ +# rimage + +`rimage` is a DSP firmware image creation and signing tool targeting +the DSP on certain Intel System-on-Chip (SoC). This is used by +the [Sound Open Firmware (SOF)](https://github.com/thesofproject/sof) +to generate binary image files. + +## Building + +Most SOF users never build `rimage` directly but as an ExternalProject +defined by CMake in SOF. This makes sure they always use an up-to-date +version of rimage and configuration files that have been fully tested. + +If needed, `rimage` can be built manually with the usual CMake commands: + +```shell +$ cmake -B build/ +$ make -C build/ help # lists all targets +$ make -C build/ +``` + +The `build/rimage` executable can then be copied to a directory in the +PATH. Zephyr users can run `west config rimage.path +/path/to/rimage/build/rimage`; Zephyr documentation and `west sign -h` +have more details. + +## Testing rimage changes with SOF Continuous Integration + +This section is about leveraging SOF validation to test rimage changes +_before_ submitting them to the rimage repository. + +Nothing here is actually specific to SOF and rimage; you can apply the +same test logic to any submodule and parent on Github. In fact the same +logic applies to submodule alternatives. Github is the only requirement. + +### Get familiar with git submodules + +This is unfortunately not optional for SOF and rimage. + +For various reasons submodules seem to confuse many git users. Maybe +because the versions of the submodules are not directly visible in some +configuration file like with most alternatives? Either way, an +unfortunate prerequisite before doing any rimage work is to get familiar +with git submodules in general. As submodules are built-in there are +many resources about them on the Internet. One possible starting point +is https://git-scm.com/book/en/v2/Git-Tools-Submodules but feel free +to use any other good tutorial instead. Make sure you actually practice +a tutorial; don't just read it. Practicing on a temporary and throw-away +copy of SOF + rimage is a great idea. + +Obviously, you also need to be familiar with regular Github pull +requests. + +### Run SOF tests on unmerged rimage commits + +First, push the rimage commits you want to be tested to any branch of +your rimage fork on Github. Do _not_ submit an rimage pull request yet. + +Note your rimage fork must have been created using the actual "fork" +button on Github so Github is aware of the connection with the upstream +rimage repo. In the top-left corner you should see `forked from +thesofproject/rimage` under the name of your fork. If not then search +the Internet for "re-attach detached github fork". + +Then, **pretend** these rimage commits have already been accepted and +merged (they have been neither) and submit to SOF a draft pull request +that updates the main SOF branch with your brand new rimage commits to +test. The only SOF commit in this SOF TEST pull request is an SOF commit +that updates the rimage pointer to the SHA of your last rimage +commit. If you're not sure how to do this then you must go back to the +previous section and practice submodules more. + +Submit this SOF pull request as a Github _draft_ so reviewers are _not_ +notified. Starting every pull request as a draft is always a good idea +but in this case this particular SOF pull request can be especially +confusing because it points at commits in a different repo and commits +that are not merged yet. So you _really_ don't want to bother busy +reviewers (here's a secret: some of the reviewers don't like submodules +either). You can freely switch back and forth between draft and ready +status and should indeed switch to draft if you forgot at submission +time but you can never "un-notify" reviewers. + +Github has very good support for submodules and will display your SOF +TEST pull request better than what the git command line can show. For +instance Github will list your rimage changes directly in the SOF Pull +Request. So if something looks unexpected on Github then it means you +did something wrong. Stop immediately (except for switching to draft if +you forgot) and ask the closest git guru for help. + +Search for "Submodule" in the build logs and make sure the last of your +new rimage commits has been checked out. + +Iterate and force-push your rimage branch and your SOF TEST pull request +until all the SOF tests pass. Then you can submit your rimage pull +request as usual. In the comments section of the rimage pull request, +point at your test results on the SOF side to impress the rimage +reviewers and get your rimage changes merged faster. + +Finally, after your rimage changes have been merged, you can if you want +submit one final SOF pull request that points to the final rimage +SHA. Or, if your rimage change is not urgently needed, you can just wait +for someone else to do it later. If you do it, copy the rimage git log +--oneline in the SOF commit message. Find some good (and less good) +rimage commit message examples at +https://github.com/thesofproject/sof/commits/main/rimage diff --git a/tools/rimage/config/apl.toml b/tools/rimage/config/apl.toml new file mode 100644 index 000000000000..e100c78a754c --- /dev/null +++ b/tools/rimage/config/apl.toml @@ -0,0 +1,57 @@ +version = [1, 8] + +[adsp] +name = "apl" +image_size = "0x0A0000" # (8 + 2) bank * 64KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0xBEFE0000" +size = "0x00002000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xA000A000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x9E000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xBE000000" + +[cse] +partition_name = "ADSP" +[[cse.entry]] +name = "ADSP.man" +offset = "0x58" +length = "0x378" +[[cse.entry]] +name = "cavs0015.met" +offset = "0x400" +length = "0x60" +[[cse.entry]] +name = "cavs0015" +offset = "0x480" +length = "0x0" # calculated by rimage + +[css] + +[signed_pkg] +name = "ADSP" +[[signed_pkg.module]] +name = "cavs0015.met" + +[partition_info] +name = "ADSP" +[[partition_info.module]] +name = "cavs0015.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x2000" diff --git a/tools/rimage/config/bdw.toml b/tools/rimage/config/bdw.toml new file mode 100644 index 000000000000..6b642fcd882e --- /dev/null +++ b/tools/rimage/config/bdw.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "bdw" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0" +size = "0x50000" +host_offset = "0x000A0000" +[[adsp.mem_zone]] +type = "DRAM" +base = "0x00400000" +size = "0xA0000" +host_offset = "0x0" diff --git a/tools/rimage/config/bsw.toml b/tools/rimage/config/bsw.toml new file mode 100644 index 000000000000..6746ca6cff34 --- /dev/null +++ b/tools/rimage/config/bsw.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "bsw" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0xFF2C0000" +size = "0x14000" +host_offset = "0x0C0000" +[[adsp.mem_zone]] +type = "DRAM" +base = "0xFF300000" +size = "0x28000" +host_offset = "0x100000" diff --git a/tools/rimage/config/byt.toml b/tools/rimage/config/byt.toml new file mode 100644 index 000000000000..4afd1c0dd523 --- /dev/null +++ b/tools/rimage/config/byt.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "byt" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0xFF2C0000" +size = "0x14000" +host_offset = "0x0C0000" +[[adsp.mem_zone]] +type = "DRAM" +base = "0xFF300000" +size = "0x28000" +host_offset = "0x100000" diff --git a/tools/rimage/config/cht.toml b/tools/rimage/config/cht.toml new file mode 100644 index 000000000000..2ed88370d16a --- /dev/null +++ b/tools/rimage/config/cht.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "cht" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0xFF2C0000" +size = "0x14000" +host_offset = "0x0C0000" +[[adsp.mem_zone]] +type = "DRAM" +base = "0xFF300000" +size = "0x28000" +host_offset = "0x100000" diff --git a/tools/rimage/config/cnl.toml b/tools/rimage/config/cnl.toml new file mode 100644 index 000000000000..ccf33fb68e2a --- /dev/null +++ b/tools/rimage/config/cnl.toml @@ -0,0 +1,61 @@ +version = [1, 8] + +[adsp] +name = "cnl" +image_size = "0x300000" # (47 + 1) bank * 64KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0xBEFE0000" +size = "0x00002000" +[[adsp.mem_zone]] +type = "IMR" +base = "0xB0038000" +size = "0x100000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xBE040000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x9E000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xBE000000" + +[cse] +partition_name = "ADSP" +[[cse.entry]] +name = "ADSP.man" +offset = "0x58" +length = "0x378" +[[cse.entry]] +name = "cavs0015.met" +offset = "0x400" +length = "0x60" +[[cse.entry]] +name = "cavs0015" +offset = "0x480" +length = "0x0" # calculated by rimage + +[css] + +[signed_pkg] +name = "ADSP" +[[signed_pkg.module]] +name = "cavs0015.met" + +[partition_info] +name = "ADSP" +[[partition_info.module]] +name = "cavs0015.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x30000" diff --git a/tools/rimage/config/hsw.toml b/tools/rimage/config/hsw.toml new file mode 100644 index 000000000000..2f96a675b89d --- /dev/null +++ b/tools/rimage/config/hsw.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "hsw" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0" +size = "0x60000" +host_offset = "0x80000" +[[adsp.mem_zone]] +type = "DRAM" +base = "0x00400000" +size = "0x80000" +host_offset = "0x0" diff --git a/tools/rimage/config/icl.toml b/tools/rimage/config/icl.toml new file mode 100644 index 000000000000..f6e0fc9cb209 --- /dev/null +++ b/tools/rimage/config/icl.toml @@ -0,0 +1,61 @@ +version = [1, 8] + +[adsp] +name = "icl" +image_size = "0x300000" # (47 + 1) bank * 64KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0xBEFE0000" +size = "0x00002000" +[[adsp.mem_zone]] +type = "IMR" +base = "0xB0038000" +size = "0x100000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xBE040000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x9E000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xBE000000" + +[cse] +partition_name = "ADSP" +[[cse.entry]] +name = "ADSP.man" +offset = "0x58" +length = "0x378" +[[cse.entry]] +name = "cavs0015.met" +offset = "0x400" +length = "0x60" +[[cse.entry]] +name = "cavs0015" +offset = "0x480" +length = "0x0" # calculated by rimage + +[css] + +[signed_pkg] +name = "ADSP" +[[signed_pkg.module]] +name = "cavs0015.met" + +[partition_info] +name = "ADSP" +[[partition_info.module]] +name = "cavs0015.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x30000" diff --git a/tools/rimage/config/imx8.toml b/tools/rimage/config/imx8.toml new file mode 100644 index 000000000000..865be902e840 --- /dev/null +++ b/tools/rimage/config/imx8.toml @@ -0,0 +1,20 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "imx8" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x596F8000" +size = "0x800" +host_offset = "0x10000" +[[adsp.mem_zone]] +type = "DRAM" +base = "0x596E8000" +size = "0x8000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "SRAM" +base = "0x92400000" +size = "0x800000" +host_offset = "0x0" diff --git a/tools/rimage/config/imx8m.toml b/tools/rimage/config/imx8m.toml new file mode 100644 index 000000000000..5b7ba20870bd --- /dev/null +++ b/tools/rimage/config/imx8m.toml @@ -0,0 +1,20 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "imx8m" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x3b6F8000" +size = "0x800" +host_offset = "0x10000" +[[adsp.mem_zone]] +type = "DRAM" +base = "0x3B6E8000" +size = "0x8000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "SRAM" +base = "0x92400000" +size = "0x800000" +host_offset = "0x0" diff --git a/tools/rimage/config/imx8ulp.toml b/tools/rimage/config/imx8ulp.toml new file mode 100644 index 000000000000..7fd4c16a52f3 --- /dev/null +++ b/tools/rimage/config/imx8ulp.toml @@ -0,0 +1,20 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "imx8ulp" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x21170000" +size = "0x10000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "DRAM" +base = "0x21180000" +size = "0x10000" +host_offset = "0x10000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0x1a000000" +size = "0x800000" +host_offset = "0x0" diff --git a/tools/rimage/config/imx8x.toml b/tools/rimage/config/imx8x.toml new file mode 100644 index 000000000000..ea9059c174ae --- /dev/null +++ b/tools/rimage/config/imx8x.toml @@ -0,0 +1,20 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "imx8x" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x596F8000" +size = "0x800" +host_offset = "0x10000" +[[adsp.mem_zone]] +type = "DRAM" +base = "0x596e8000" +size = "0x8000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "SRAM" +base = "0x92400000" +size = "0x800000" +host_offset = "0x0" diff --git a/tools/rimage/config/jsl.toml b/tools/rimage/config/jsl.toml new file mode 100644 index 000000000000..bec0e6bd3a7e --- /dev/null +++ b/tools/rimage/config/jsl.toml @@ -0,0 +1,61 @@ +version = [1, 8] + +[adsp] +name = "icl" +image_size = "0x110000" # (16 + 1) bank * 64KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0xBEFE0000" +size = "0x00002000" +[[adsp.mem_zone]] +type = "IMR" +base = "0xB0038000" +size = "0x100000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xBE040000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x9E000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xBE000000" + +[cse] +partition_name = "ADSP" +[[cse.entry]] +name = "ADSP.man" +offset = "0x58" +length = "0x378" +[[cse.entry]] +name = "cavs0015.met" +offset = "0x400" +length = "0x60" +[[cse.entry]] +name = "cavs0015" +offset = "0x480" +length = "0x0" # calculated by rimage + +[css] + +[signed_pkg] +name = "ADSP" +[[signed_pkg.module]] +name = "cavs0015.met" + +[partition_info] +name = "ADSP" +[[partition_info.module]] +name = "cavs0015.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x30000" diff --git a/tools/rimage/config/kbl.toml b/tools/rimage/config/kbl.toml new file mode 100644 index 000000000000..f1c83d594905 --- /dev/null +++ b/tools/rimage/config/kbl.toml @@ -0,0 +1,30 @@ +version = [1, 5] + +[adsp] +name = "kbl" +image_size = "0x200000" # (30 + 2) bank * 64KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0xBEFE0000" +size = "0x00002000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xA000A000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x9E000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xBE000000" + +[css] + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0" +hw_buf_base_addr = "0xBE500000" +hw_buf_length = "0x4A000" diff --git a/tools/rimage/config/lnl.toml b/tools/rimage/config/lnl.toml new file mode 100644 index 000000000000..9c245b9ca8e9 --- /dev/null +++ b/tools/rimage/config/lnl.toml @@ -0,0 +1,571 @@ +version = [3, 0] + +[adsp] +name = "lnl" +image_size = "0x2C0000" # (22) bank * 128KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0x1FF80000" +size = "0x400" +[[adsp.mem_zone]] +type = "IMR" +base = "0xA104A000" +size = "0x2000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xa00f0000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x40000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xA0000000" + +[cse] +partition_name = "ADSP" +[[cse.entry]] +name = "ADSP.man" +offset = "0x5c" +length = "0x4b8" +[[cse.entry]] +name = "ADSP.met" +offset = "0x4c0" +length = "0x70" +[[cse.entry]] +name = "ADSP" +offset = "0x540" +length = "0x0" # calculated by rimage + +[css] + +[signed_pkg] +name = "ADSP" +partition_usage = "0x23" +[[signed_pkg.module]] +name = "ADSP.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x40000" + +[module] +count = 24 + [[module.entry]] + name = "BRNGUP" + uuid = "2B79E4F3-4675-F649-89DF-3BC194A91AEB" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + [[module.entry]] + name = "BASEFW" + uuid = "0E398C32-5ADE-BA4B-93B1-C50432280EE4" + affinity_mask = "3" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + [[module.entry]] + name = "MIXIN" + uuid = "39656EB2-3B71-4049-8D3F-F92CD5C43C09" + affinity_mask = "0x1" + instance_count = "30" + domain_types = "0" + load_type = "0" + module_type = "1" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [ 0, 0, 0, 0, 296, 644000, 45, 60, 0, 0, 0, + 1, 0, 0, 0, 296, 669900, 48, 64, 0, 0, 0, + 2, 0, 0, 0, 296, 934000, 96, 128, 0, 0, 0, + 3, 0, 0, 0, 296, 1137000, 96, 128, 0, 0, 0, + 4, 0, 0, 0, 296, 1482000, 48, 64, 0, 0, 0, + 5, 0, 0, 0, 296, 1746000, 96, 128, 0, 0, 0, + 6, 0, 0, 0, 296, 2274000, 192, 256, 0, 0, 0, + 7, 0, 0, 0, 296, 2700000, 48, 64, 0, 0, 0, + 8, 0, 0, 0, 296, 2964000, 96, 128, 0, 0, 0, + 9, 0, 0, 0, 296, 3492000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "MIXOUT" + uuid = "3C56505A-24D7-418F-BDDC-C1F5A3AC2AE0" + affinity_mask = "0x1" + instance_count = "30" + domain_types = "0" + load_type = "0" + module_type = "2" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 520, 649600, 48, 64, 0, 0, 0, + 1, 0, 0, 0, 520, 966300, 96, 128, 0, 0, 0, + 2, 0, 0, 0, 520, 2101000, 48, 64, 0, 0, 0, + 3, 0, 0, 0, 520, 2500800, 192, 256, 0, 0, 0, + 4, 0, 0, 0, 520, 2616700, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 520, 2964500, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 520, 4202000, 96, 128, 0, 0, 0, + 7, 0, 0, 0, 520, 3730000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "COPIER" + uuid = "9BA00C83-CA12-4A83-943C-1FA2E82F9DDA" + affinity_mask = "0x1" + instance_count = "32" + domain_types = "0" + load_type = "0" + module_type = "3" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [ 0, 0, 0, 0, 280, 640100, 45, 60, 0, 0, 0, + 1, 0, 0, 0, 280, 1106300, 192, 192, 0, 0, 0, + 2, 0, 0, 0, 280, 1573000, 45, 45, 0, 0, 0, + 3, 0, 0, 0, 280, 2040600, 192, 256, 0, 0, 0, + 4, 0, 0, 0, 280, 2507500, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 280, 2999000, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 280, 3501000, 45, 60, 0, 0, 0, + 7, 0, 0, 0, 280, 3927000, 192, 256, 0, 0, 0, + 8, 0, 0, 0, 280, 4424000, 192, 256, 0, 0, 0, + 9, 0, 0, 0, 280, 4941000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "PEAKVOL" + uuid = "8A171323-94A3-4E1D-AFE9-FE5DBAA4C393" + affinity_mask = "0x1" + instance_count = "10" + domain_types = "0" + load_type = "0" + module_type = "4" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 480, 1114000, 48, 64, 0, 0, 0, + 1, 0, 0, 0, 480, 3321600, 192, 256, 0, 0, 0, + 2, 0, 0, 0, 480, 3786000, 192, 256, 0, 0, 0, + 3, 0, 0, 0, 480, 4333000, 48, 64, 0, 0, 0, + 4, 0, 0, 0, 480, 4910000, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 480, 5441000, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 480, 6265000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "GAIN" + uuid = "61BCA9A8-18D0-4A18-8E7B-2639219804B7" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 416, 914000, 48, 64, 0, 0, 0, + 1, 0, 0, 0, 416, 1321600, 192, 256, 0, 0, 0, + 2, 0, 0, 0, 416, 1786000, 192, 256, 0, 0, 0, + 3, 0, 0, 0, 416, 2333000, 48, 64, 0, 0, 0, + 4, 0, 0, 0, 416, 2910000, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 416, 3441000, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 416, 4265000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "ASRC" + uuid = "66B4402D-B468-42F2-81A7-B37121863DD4" + affinity_mask = "0x3" + instance_count = "2" + domain_types = "0" + + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + pin = [0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x45ff] + + mod_cfg = [0, 0, 0, 0, 20480, 4065600, 24, 22, 0, 0, 0, + 1, 0, 0, 0, 20480, 5616000, 8, 25, 0, 0, 0, + 2, 0, 0, 0, 20480, 7319200, 24, 27, 0, 0, 0, + 3, 0, 0, 0, 20480, 9155300, 8, 27, 0, 0, 0, + 4, 0, 0, 0, 20480, 10972600, 48, 54, 0, 0, 0, + 5, 0, 0, 0, 20480, 12661000, 16, 36, 0, 0, 0, + 6, 0, 0, 0, 20480, 14448500, 48, 96, 0, 0, 0, + 7, 0, 0, 0, 20480, 16145000, 19, 68, 0, 0, 0, + 8, 0, 0, 0, 20480, 17861300, 45, 102, 0, 0, 0, + 9, 0, 0, 0, 20480, 21425900, 8, 36, 0, 0, 0, + 10, 0, 0, 0, 20480, 22771000, 32, 102, 0, 0, 0, + 11, 0, 0, 0, 20480, 23439000, 48, 27, 0, 0, 0, + 12, 0, 0, 0, 20480, 33394000, 48, 51, 0, 0, 0, + 13, 0, 0, 0, 20480, 36140000, 16, 96, 0, 0, 0, + 14, 0, 0, 0, 20480, 38003000, 16, 68, 0, 0, 0, + 15, 0, 0, 0, 20480, 39787000, 45, 51, 0, 0, 0] + + [[module.entry]] + name = "SRC" + uuid = "E61BB28D-149A-4C1F-B709-46823EF5F5AE" + affinity_mask = "0x1" + #instance_count = "10" + domain_types = "0" + load_type = "0" + module_type = "7" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xffff, 0xc, 0x8, 0x05ff, + 1, 0, 0xf6c9, 0xc, 0x8, 0x05ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 12832, 1365500, 0, 0, 0, 1365, 0, + 1, 0, 0, 0, 12832, 2302300, 0, 0, 0, 2302, 0, + 2, 0, 0, 0, 12832, 3218200, 0, 0, 0, 3218, 0, + 3, 0, 0, 0, 12832, 4169700, 0, 0, 0, 4169, 0, + 4, 0, 0, 0, 12832, 5095100, 0, 0, 0, 5095, 0, + 5, 0, 0, 0, 12832, 6014800, 0, 0, 0, 6014, 0, + 6, 0, 0, 0, 12832, 6963500, 0, 0, 0, 6963, 0, + 7, 0, 0, 0, 12832, 7791000, 0, 0, 0, 7791, 0, + 8, 0, 0, 0, 12832, 8843000, 0, 0, 0, 8843, 0, + 9, 0, 0, 0, 12832, 9755100, 0, 0, 0, 9755, 0, + 10, 0, 0, 0, 12832, 10726500, 0, 0, 0, 10726, 0, + 11, 0, 0, 0, 12832, 11624100, 0, 0, 0, 11624, 0, + 12, 0, 0, 0, 12832, 12518700, 0, 0, 0, 12518, 0, + 13, 0, 0, 0, 12832, 13555000, 0, 0, 0, 13555, 0, + 14, 0, 0, 0, 12832, 14144500, 0, 0, 0, 14144, 0, + 15, 0, 0, 0, 12832, 15809800, 0, 0, 0, 15809, 0, + 16, 0, 0, 0, 12832, 16749000, 0, 0, 0, 16749, 0, + 17, 0, 0, 0, 12832, 18433500, 0, 0, 0, 18433, 0, + 18, 0, 0, 0, 12832, 19425900, 0, 0, 0, 19425, 0, + 19, 0, 0, 0, 12832, 20396900, 0, 0, 0, 20396, 0, + 20, 0, 0, 0, 12832, 20881000, 0, 0, 0, 20881, 0, + 21, 0, 0, 0, 12832, 23431000, 0, 0, 0, 23431, 0, + 22, 0, 0, 0, 12832, 30471000, 0, 0, 0, 30471, 0] + + [[module.entry]] + name = "MICSEL" + uuid = "32FE92C1-1E17-4FC2-9758-C7F3542E980A" + affinity_mask = "0x1" + instance_count = "8" + domain_types = "0" + load_type = "0" + init_config = "1" + module_type = "0xC" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xe, 0xa, 0x45ff, 1, 0, 0xfeef, 0xe, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 960, 488500, 16, 16, 0, 0, 0, + 1, 0, 0, 0, 960, 964500, 16, 16, 0, 0, 0, + 2, 0, 0, 0, 960, 2003000, 16, 16, 0, 0, 0] + + [[module.entry]] + name = "UPDWMIX" + uuid = "42F8060C-832F-4DBF-B247-51E961997B34" + affinity_mask = "0x1" + instance_count = "15" + domain_types = "0" + load_type = "0" + module_type = "5" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xffff, 0xc, 0x8, 0x05ff, + 1, 0, 0xffff, 0xc, 0x8, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 216, 706000, 12, 16, 0, 0, 0, + 1, 0, 0, 0, 216, 1271000, 8, 8, 0, 0, 0, + 2, 0, 0, 0, 216, 1839000, 89, 118, 0, 0, 0, + 3, 0, 0, 0, 216, 2435000, 48, 64, 0, 0, 0, + 4, 0, 0, 0, 216, 3343000, 192, 192, 0, 0, 0, + 5, 0, 0, 0, 216, 3961000, 177, 177, 0, 0, 0, + 6, 0, 0, 0, 216, 4238000, 192, 256, 0, 0, 0, + 7, 0, 0, 0, 216, 6691000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "PROBE" + uuid = "7CAD0808-AB10-CD23-EF45-12AB34CD56EF" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 100000, 48, 48, 0, 1000, 0] + + [[module.entry]] + name = "MUX" + uuid = "64ce6e35-857a-4878-ace8-e2a2f42e3069" + affinity_mask = "0x1" + instance_count = "15" + domain_types = "0" + load_type = "0" + module_type = "6" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 280, 460700, 16, 16, 0, 0, 0] + + [[module.entry]] + name = "KDTEST" + uuid = "EBA8D51F-7827-47B5-82EE-DE6E7743AF67" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "8" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 480, 1114000, 64, 64, 0, 0, 0] + + [[module.entry]] + name = "KPB" + uuid = "A8A0CB32-4A77-4DB1-85C7-53D7EE07BCE6" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0xB" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 14400, 1114000, 16, 16, 0, 0, 0] + + # smart amp test module config + [[module.entry]] + name = "SMATEST" + uuid = "167A961E-8AE4-11EA-89F1-000C29CE1635" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + init_config = "1" + module_type = "0xD" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # eq iir module config + [[module.entry]] + name = "EQIIR" + uuid = "5150C0E6-27F9-4EC8-8351-C705B642D12F" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # eq fir module config + [[module.entry]] + name = "EQFIR" + uuid = "43A90CE7-f3A5-41Df-AC06-BA98651AE6A3" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # Aria module config + [[module.entry]] + name = "ARIA" + uuid = "99F7166D-372C-43EF-81F6-22007AA15F03" + affinity_mask = "0x1" + instance_count = "8" + domain_types = "0" + load_type = "0" + init_config = "1" + module_type = "30" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 260, 1063000, 16, 21, 0, 0, 0, + 1, 0, 0, 0, 260, 1873500, 192, 256, 0, 0, 0, + 2, 0, 0, 0, 260, 2680000, 32, 42, 0, 0, 0, + 3, 0, 0, 0, 260, 3591000, 64, 85, 0, 0, 0, + 4, 0, 0, 0, 260, 4477000, 96, 128, 0, 0, 0, + 5, 0, 0, 0, 260, 7195000, 192, 192, 0, 0, 0] + + # DRC module config + [[module.entry]] + name = "DRC" + uuid = "B36EE4DA-006F-47F9-A06D-FECBE2D8B6CE" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # Crossover module config + # Note: Crossover has init_config set to 1 to let kernel know that the base_cfg_ext needs to + # be appended to the IPC payload. The Extension is needed to know the output pin indices. + [[module.entry]] + name = "XOVER" + uuid = "948C9AD1-806A-4131-AD6C-B2BDA9E35A9F" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + init_config = "1" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # Multiband-DRC module config + [[module.entry]] + name = "MB_DRC" + uuid = "0D9F2256-8E4F-47B3-8448-239A334F1191" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # DCblock module config + [[module.entry]] + name = "DCBLOCK" + uuid = "B809EFAF-5681-42B1-9ED6-04BB012DD384" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # TDFB module config + [[module.entry]] + name = "TDFB" + uuid = "DD511749-D9FA-455C-B3A7-13585693F1AF" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] diff --git a/tools/rimage/config/mt8186.toml b/tools/rimage/config/mt8186.toml new file mode 100644 index 000000000000..80b011b4bfd4 --- /dev/null +++ b/tools/rimage/config/mt8186.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "mt8186" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x4e100000" +size = "0x00100000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "SRAM" +base = "0x60000000" +size = "0x00600000" +host_offset = "0x0" diff --git a/tools/rimage/config/mt8188.toml b/tools/rimage/config/mt8188.toml new file mode 100644 index 000000000000..0dcc4b4b3244 --- /dev/null +++ b/tools/rimage/config/mt8188.toml @@ -0,0 +1,15 @@ +version = [1, 0] # parse_adsp_config_v1_0() + +[adsp] +name = "mt8188" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x4e100000" +size = "0x00080000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "SRAM" +base = "0x60000000" +size = "0x00600000" +host_offset = "0x0" diff --git a/tools/rimage/config/mt8195.toml b/tools/rimage/config/mt8195.toml new file mode 100644 index 000000000000..5c8abc92557a --- /dev/null +++ b/tools/rimage/config/mt8195.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "mt8195" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x40000000" +size = "0x00040000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "SRAM" +base = "0x60000000" +size = "0x00600000" +host_offset = "0x0" diff --git a/tools/rimage/config/mtl.toml b/tools/rimage/config/mtl.toml new file mode 100644 index 000000000000..2d2742c91c83 --- /dev/null +++ b/tools/rimage/config/mtl.toml @@ -0,0 +1,632 @@ +version = [3, 0] + +[adsp] +name = "mtl" +image_size = "0x2C0000" # (22) bank * 128KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0x1FF80000" +size = "0x400" +[[adsp.mem_zone]] +type = "IMR" +base = "0xA104A000" +size = "0x2000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xa00f0000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x40000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xA0000000" + +[cse] +partition_name = "ADSP" +[[cse.entry]] +name = "ADSP.man" +offset = "0x5c" +length = "0x4b8" +[[cse.entry]] +name = "ADSP.met" +offset = "0x4c0" +length = "0x70" +[[cse.entry]] +name = "ADSP" +offset = "0x540" +length = "0x0" # calculated by rimage + +[css] + +[signed_pkg] +name = "ADSP" +partition_usage = "0x23" +[[signed_pkg.module]] +name = "ADSP.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x40000" + +[module] +count = 25 + [[module.entry]] + name = "BRNGUP" + uuid = "2B79E4F3-4675-F649-89DF-3BC194A91AEB" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + [[module.entry]] + name = "BASEFW" + uuid = "0E398C32-5ADE-BA4B-93B1-C50432280EE4" + affinity_mask = "3" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + [[module.entry]] + name = "MIXIN" + uuid = "39656EB2-3B71-4049-8D3F-F92CD5C43C09" + affinity_mask = "0x1" + instance_count = "30" + domain_types = "0" + load_type = "0" + module_type = "1" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [1, 0, 0, 0, 296, 4996000, 384, 384, 0, 4996, 0, + 2, 0, 0, 0, 296, 2652000, 384, 384, 0, 2652, 0, + 3, 0, 0, 0, 296, 2928000, 512, 512, 0, 2928, 0, + 4, 0, 0, 0, 296, 2572000, 128, 128, 0, 2572, 0, + 5, 0, 0, 0, 296, 3760000, 1536, 1536, 0, 3760, 0] + + [[module.entry]] + name = "MIXOUT" + uuid = "3C56505A-24D7-418F-BDDC-C1F5A3AC2AE0" + affinity_mask = "0x1" + instance_count = "30" + domain_types = "0" + load_type = "0" + module_type = "2" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [1, 0, 0, 0, 520, 2280000, 384, 384, 0, 2280, 0, + 2, 0, 0, 0, 520, 1988000, 384, 384, 0, 1988, 0, + 3, 0, 0, 0, 520, 7631000, 512, 512, 0, 7631, 0, + 4, 0, 0, 0, 520, 1953000, 128, 128, 0, 1953, 0, + 5, 0, 0, 0, 520, 2301000, 1536, 1536, 0, 2301, 0] + + [[module.entry]] + name = "COPIER" + uuid = "9BA00C83-CA12-4A83-943C-1FA2E82F9DDA" + affinity_mask = "0x1" + instance_count = "32" + domain_types = "0" + load_type = "0" + module_type = "3" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [1, 0, 0, 0, 280, 4918000, 768, 768, 0, 4918, 0, + 2, 0, 0, 0, 280, 6526000, 768, 768, 0, 6526, 0, + 3, 0, 0, 0, 280, 6388000, 384, 384, 0, 6388, 0, + 4, 0, 0, 0, 280, 4682000, 512, 512, 0, 4682, 0, + 5, 0, 0, 0, 280, 5738000, 512, 512, 0, 5738, 0, + 6, 0, 0, 0, 280, 6250000, 256, 256, 0, 6250, 0, + 7, 0, 0, 0, 280, 6460000, 768, 768, 0, 6460, 0, + 8, 0, 0, 0, 280, 7116000, 768, 768, 0, 7116, 0, + 9, 0, 0, 0, 280, 6008000, 384, 384, 0, 6008, 0, + 10, 0, 0, 0, 280, 6258000, 512, 512, 0, 6258, 0, + 11, 0, 0, 0, 280, 7188000, 1024, 1024, 0, 7188, 0, + 12, 0, 0, 0, 280, 7272000, 1536, 1536, 0, 7272, 0, + 13, 0, 0, 0, 280, 6290000, 768, 768, 0, 6290, 0, + 14, 0, 0, 0, 280, 6604000, 1024, 1024, 0, 6604, 0, + 15, 0, 0, 0, 280, 6198000, 384, 384, 0, 6198, 0, + 16, 0, 0, 0, 280, 6250000, 384, 384, 0, 6250, 0, + 17, 0, 0, 0, 280, 6258000, 256, 256, 0, 6258, 0, + 18, 0, 0, 0, 280, 4354000, 256, 256, 0, 4354, 0, + 19, 0, 0, 0, 280, 6198000, 256, 256, 0, 6198, 0, + 20, 0, 0, 0, 280, 6250000, 128, 128, 0, 6250, 0, + 21, 0, 0, 0, 280, 6250000, 128, 128, 0, 6250, 0, + 22, 0, 0, 0, 280, 6206000, 128, 128, 0, 6206, 0, + 23, 0, 0, 0, 280, 4170000, 64, 64, 0, 4170, 0, + 24, 0, 0, 0, 280, 4234000, 96, 96, 0, 4234, 0, + 25, 0, 0, 0, 280, 6198000, 96, 96, 0, 6198, 0, + 26, 0, 0, 0, 280, 6250000, 96, 96, 0, 6250, 0, + 27, 0, 0, 0, 280, 6198000, 192, 192, 0, 6198, 0, + 28, 0, 0, 0, 280, 6258000, 192, 192, 0, 6258, 0, + 29, 0, 0, 0, 280, 6392000, 720, 720, 0, 6392, 0, + 30, 0, 0, 0, 280, 6250000, 360, 360, 0, 6250, 0, + 31, 0, 0, 0, 280, 5326000, 360, 360, 0, 5326, 0, + 32, 0, 0, 0, 280, 6258000, 180, 180, 0, 6258, 0, + 33, 0, 0, 0, 280, 4354000, 256, 256, 0, 4354, 0, + 34, 0, 0, 0, 280, 4898000, 256, 256, 0, 4898, 0, + 35, 0, 0, 0, 280, 6246000, 128, 128, 0, 6246, 0, + 36, 0, 0, 0, 280, 6250000, 192, 192, 0, 6250, 0, + 37, 0, 0, 0, 280, 6250000, 48, 48, 0, 6250, 0, + 38, 0, 0, 0, 280, 4170000, 64, 64, 0, 4170, 0, + 39, 0, 0, 0, 280, 6198000, 64, 64, 0, 6198, 0, + 40, 0, 0, 0, 280, 6246000, 32, 32, 0, 6246, 0, + 41, 0, 0, 0, 280, 5272000, 192, 384, 0, 5272, 0] + + [[module.entry]] + name = "PEAKVOL" + uuid = "8A171323-94A3-4E1D-AFE9-FE5DBAA4C393" + affinity_mask = "0x1" + instance_count = "10" + domain_types = "0" + load_type = "0" + module_type = "4" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [1, 0, 0, 0, 480, 11667000, 384, 384, 0, 11667, 0, + 2, 0, 0, 0, 480, 5943000, 192, 192, 0, 5943, 0, + 3, 0, 0, 0, 480, 12567000, 720, 720, 0, 12567, 0, + 4, 0, 0, 0, 480, 7360000, 768, 768, 0, 7360, 0, + 5, 0, 0, 0, 480, 12236000, 1536, 1536, 0, 12236, 0] + + [[module.entry]] + name = "GAIN" + uuid = "61BCA9A8-18D0-4A18-8E7B-2639219804B7" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [1, 0, 0, 0, 416, 12100000, 1536, 1536, 0, 12100, 0, + 2, 0, 0, 0, 416, 10183000, 384, 384, 0, 10183, 0, + 3, 0, 0, 0, 416, 8192000, 512, 512, 0, 8192, 0, + 4, 0, 0, 0, 416, 10091000, 128, 128, 0, 10091, 0, + 5, 0, 0, 0, 416, 5908000, 768, 768, 0, 5908, 0] + + [[module.entry]] + name = "ASRC" + uuid = "66B4402D-B468-42F2-81A7-B37121863DD4" + affinity_mask = "0x3" + instance_count = "2" + domain_types = "0" + + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + pin = [0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x45ff] + + mod_cfg = [1, 0, 0, 0, 20480, 21808000, 64, 192, 0, 21808, 0, + 2, 0, 0, 0, 20480, 45820000, 64, 384, 0, 45820, 0, + 3, 0, 0, 0, 20480, 75236000, 512, 1440, 0, 75236, 0, + 4, 0, 0, 0, 20480, 79732000, 512, 1536, 0, 79732, 0, + 5, 0, 0, 0, 20480, 50411000, 184, 384, 0, 50411, 0, + 6, 0, 0, 0, 20480, 24236000, 192, 128, 0, 24236, 0, + 7, 0, 0, 0, 20480, 46753000, 192, 384, 0, 46753, 0, + 8, 0, 0, 0, 20480, 30032000, 256, 256, 0, 30032, 0, + 9, 0, 0, 0, 20480, 48676000, 256, 384, 0, 48676, 0, + 10, 0, 0, 0, 20480, 46548000, 360, 360, 0, 46548, 0, + 11, 0, 0, 0, 20480, 94372000, 1440, 1536, 0, 94372, 0, + 12, 0, 0, 0, 20480, 42912000, 1536, 512, 0, 42912, 0, + 13, 0, 0, 0, 20480, 31871000, 384, 192, 0, 31871, 0, + 14, 0, 0, 0, 20480, 34216000, 384, 256, 0, 34216, 0, + 15, 0, 0, 0, 20480, 83448000, 1536, 1440, 0, 83448, 0] + + [[module.entry]] + name = "SRC" + uuid = "E61BB28D-149A-4C1F-B709-46823EF5F5AE" + affinity_mask = "0x1" + #instance_count = "10" + domain_types = "0" + load_type = "0" + module_type = "7" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xffff, 0xc, 0x8, 0x05ff, + 1, 0, 0xf6c9, 0xc, 0x8, 0x05ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [1, 0, 0, 0, 12832, 15976000, 128, 512, 0, 15976, 0, + 2, 0, 0, 0, 12832, 15340000, 64, 256, 0, 15340, 0, + 3, 0, 0, 0, 12832, 21880000, 96, 512, 0, 21880, 0, + 4, 0, 0, 0, 12832, 19968000, 48, 256, 0, 19968, 0, + 5, 0, 0, 0, 12832, 18236000, 64, 256, 0, 18236, 0, + 6, 0, 0, 0, 12832, 15244000, 32, 256, 0, 15244, 0, + 7, 0, 0, 0, 12832, 56028000, 1536, 512, 0, 56028, 0, + 8, 0, 0, 0, 12832, 46740000, 768, 256, 0, 46740, 0, + 9, 0, 0, 0, 12832, 24656000, 768, 512, 0, 24656, 0, + 10, 0, 0, 0, 12832, 23516000, 384, 256, 0, 23516, 0, + 11, 0, 0, 0, 12832, 29368000, 384, 488, 0, 29368, 0, + 12, 0, 0, 0, 12832, 27164000, 192, 244, 0, 27164, 0, + 13, 0, 0, 0, 12832, 15892000, 384, 384, 0, 15892, 0, + 14, 0, 0, 0, 12832, 19916000, 192, 512, 0, 19916, 0, + 15, 0, 0, 0, 12832, 19176000, 96, 256, 0, 19176, 0, + 16, 0, 0, 0, 12832, 12676000, 192, 192, 0, 12676, 0, + 17, 0, 0, 0, 12832, 16280000, 384, 320, 0, 16280, 0, + 18, 0, 0, 0, 12832, 13076000, 192, 160, 0, 13076, 0, + 19, 0, 0, 0, 12832, 11440000, 384, 256, 0, 11440, 0, + 20, 0, 0, 0, 12832, 10996000, 192, 128, 0, 10996, 0, + 21, 0, 0, 0, 12832, 11428000, 384, 192, 0, 11428, 0, + 22, 0, 0, 0, 12832, 10740000, 192, 96, 0, 10740, 0, + 23, 0, 0, 0, 12832, 29936000, 360, 512, 0, 29936, 0, + 24, 0, 0, 0, 12832, 27696000, 180, 256, 0, 27696, 0, + 25, 0, 0, 0, 12832, 18368000, 256, 512, 0, 18368, 0, + 26, 0, 0, 0, 12832, 15204000, 128, 256, 0, 15204, 0] + + [[module.entry]] + name = "MICSEL" + uuid = "32FE92C1-1E17-4FC2-9758-C7F3542E980A" + affinity_mask = "0x1" + instance_count = "8" + domain_types = "0" + load_type = "0" + init_config = "1" + module_type = "0xC" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xe, 0xa, 0x45ff, 1, 0, 0xfeef, 0xe, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 960, 488500, 16, 16, 0, 0, 0, + 1, 0, 0, 0, 960, 964500, 16, 16, 0, 0, 0, + 2, 0, 0, 0, 960, 2003000, 16, 16, 0, 0, 0] + + [[module.entry]] + name = "UPDWMIX" + uuid = "42F8060C-832F-4DBF-B247-51E961997B34" + affinity_mask = "0x1" + instance_count = "15" + domain_types = "0" + load_type = "0" + module_type = "5" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xffff, 0xc, 0x8, 0x05ff, + 1, 0, 0xffff, 0xc, 0x8, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [1, 0, 0, 0, 216, 5044000, 384, 192, 0, 5044, 0, + 2, 0, 0, 0, 216, 2660000, 384, 384, 0, 2660, 0, + 3, 0, 0, 0, 216, 3164000, 576, 384, 0, 3164, 0, + 4, 0, 0, 0, 216, 3316000, 768, 384, 0, 3316, 0, + 5, 0, 0, 0, 216, 5264000, 768, 384, 0, 5264, 0, + 6, 0, 0, 0, 216, 5440000, 768, 384, 0, 5440, 0, + 7, 0, 0, 0, 216, 2888000, 768, 192, 0, 2888, 0, + 8, 0, 0, 0, 216, 2856000, 768, 192, 0, 2856, 0, + 9, 0, 0, 0, 216, 2876000, 768, 192, 0, 2876, 0, + 10, 0, 0, 0, 216, 2956000, 960, 192, 0, 2956, 0, + 11, 0, 0, 0, 216, 2888000, 1152, 192, 0, 2888, 0, + 12, 0, 0, 0, 216, 2888000, 1152, 192, 0, 2888, 0, + 13, 0, 0, 0, 216, 2816000, 1536, 192, 0, 2816, 0, + 14, 0, 0, 0, 216, 2468000, 192, 384, 0, 2468, 0, + 15, 0, 0, 0, 216, 3084000, 576, 384, 0, 3084, 0, + 16, 0, 0, 0, 216, 3442000, 960, 384, 0, 3442, 0, + 17, 0, 0, 0, 216, 3478000, 1152, 384, 0, 3478, 0, + 18, 0, 0, 0, 216, 3478000, 1152, 384, 0, 3478, 0, + 19, 0, 0, 0, 216, 3736000, 1536, 384, 0, 3736, 0, + 20, 0, 0, 0, 216, 3216000, 192, 1152, 0, 3216, 0, + 21, 0, 0, 0, 216, 3308000, 384, 1152, 0, 3308, 0, + 22, 0, 0, 0, 216, 3616000, 768, 1152, 0, 3616, 0, + 23, 0, 0, 0, 216, 3616000, 768, 1152, 0, 3616, 0, + 24, 0, 0, 0, 216, 4916000, 1536, 1152, 0, 4916, 0, + 25, 0, 0, 0, 216, 3228000, 192, 1152, 0, 3228, 0, + 26, 0, 0, 0, 216, 3452000, 384, 1152, 0, 3452, 0, + 27, 0, 0, 0, 216, 4016000, 768, 1152, 0, 4016, 0, + 28, 0, 0, 0, 216, 5080000, 1536, 1152, 0, 5080, 0, + 29, 0, 0, 0, 216, 3552000, 384, 1536, 0, 3552, 0, + 30, 0, 0, 0, 216, 3728000, 768, 1152, 0, 3728, 0] + + [[module.entry]] + name = "PROBE" + uuid = "7CAD0808-AB10-CD23-EF45-12AB34CD56EF" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 100000, 48, 48, 0, 1000, 0] + + [[module.entry]] + name = "MUX" + uuid = "64ce6e35-857a-4878-ace8-e2a2f42e3069" + affinity_mask = "0x1" + instance_count = "15" + domain_types = "0" + load_type = "0" + module_type = "6" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 280, 460700, 16, 16, 0, 0, 0] + + [[module.entry]] + name = "KDTEST" + uuid = "EBA8D51F-7827-47B5-82EE-DE6E7743AF67" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "8" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 480, 1114000, 64, 64, 0, 0, 0] + + [[module.entry]] + name = "KPB" + uuid = "A8A0CB32-4A77-4DB1-85C7-53D7EE07BCE6" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0xB" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 14400, 1114000, 16, 16, 0, 0, 0] + + # smart amp test module config + [[module.entry]] + name = "SMATEST" + uuid = "167A961E-8AE4-11EA-89F1-000C29CE1635" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + init_config = "1" + module_type = "0xD" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 296, 5000000, 384, 384, 0, 5000, 0] + + # eq iir module config + [[module.entry]] + name = "EQIIR" + uuid = "5150C0E6-27F9-4EC8-8351-C705B642D12F" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 1000, 0, + 0, 0, 0, 0, 4096, 20663000, 768, 768, 0, 20663, 0] + + # eq fir module config + [[module.entry]] + name = "EQFIR" + uuid = "43A90CE7-f3A5-41Df-AC06-BA98651AE6A3" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # Aria module config + [[module.entry]] + name = "ARIA" + uuid = "99F7166D-372C-43EF-81F6-22007AA15F03" + affinity_mask = "0x1" + instance_count = "8" + domain_types = "0" + load_type = "0" + init_config = "1" + module_type = "30" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 260, 1063000, 16, 21, 0, 0, 0, + 1, 0, 0, 0, 260, 1873500, 192, 256, 0, 0, 0, + 2, 0, 0, 0, 260, 2680000, 32, 42, 0, 0, 0, + 3, 0, 0, 0, 260, 3591000, 64, 85, 0, 0, 0, + 4, 0, 0, 0, 260, 4477000, 96, 128, 0, 0, 0, + 5, 0, 0, 0, 260, 7195000, 192, 192, 0, 0, 0] + + # DRC module config + [[module.entry]] + name = "DRC" + uuid = "B36EE4DA-006F-47F9-A06D-FECBE2D8B6CE" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # Crossover module config + # Note: Crossover has init_config set to 1 to let kernel know that the base_cfg_ext needs to + # be appended to the IPC payload. The Extension is needed to know the output pin indices. + [[module.entry]] + name = "XOVER" + uuid = "948C9AD1-806A-4131-AD6C-B2BDA9E35A9F" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + init_config = "1" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # Multiband-DRC module config + [[module.entry]] + name = "MB_DRC" + uuid = "0D9F2256-8E4F-47B3-8448-239A334F1191" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # DCblock module config + [[module.entry]] + name = "DCBLOCK" + uuid = "B809EFAF-5681-42B1-9ED6-04BB012DD384" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + [[module.entry]] + name = "RTC_AEC" + uuid = "B780A0A6-269F-466F-B477-23DFA05AF758" + affinity_mask = "0x3" + instance_count = "1" + domain_types = "0" + load_type = "1" + module_type = "10" + init_config = "1" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0x8, 0x2, 0x2, 0x1, + 0, 0, 0x8, 0x2, 0x2, 0x4, + 1, 0, 0x8, 0x2, 0x2, 0x1] + + # TDFB module config + [[module.entry]] + name = "TDFB" + uuid = "DD511749-D9FA-455C-B3A7-13585693F1AF" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] diff --git a/tools/rimage/config/rmb.toml b/tools/rimage/config/rmb.toml new file mode 100644 index 000000000000..7d43f3a3dc33 --- /dev/null +++ b/tools/rimage/config/rmb.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "rmb" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x7F000000" +size = "0x40000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "DRAM" +base = "0xE0000000" +size = "0xE0000" +host_offset = "0x0" diff --git a/tools/rimage/config/rn.toml b/tools/rimage/config/rn.toml new file mode 100644 index 000000000000..d4e0b34b685c --- /dev/null +++ b/tools/rimage/config/rn.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "rn" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x20000000" +size = "0x40000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "DRAM" +base = "0x21000000" +size = "0xE0000" +host_offset = "0x0" diff --git a/tools/rimage/config/skl.toml b/tools/rimage/config/skl.toml new file mode 100644 index 000000000000..0fff3a382bbf --- /dev/null +++ b/tools/rimage/config/skl.toml @@ -0,0 +1,30 @@ +version = [1, 5] + +[adsp] +name = "skl" +image_size = "0x200000" # (30 + 2) bank * 64KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0xBEFE0000" +size = "0x00002000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xA000A000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x9E000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xBE000000" + +[css] + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0" +hw_buf_base_addr = "0xBE500000" +hw_buf_length = "0x4A000" diff --git a/tools/rimage/config/sue.toml b/tools/rimage/config/sue.toml new file mode 100644 index 000000000000..7579c7fcfb06 --- /dev/null +++ b/tools/rimage/config/sue.toml @@ -0,0 +1,31 @@ +version = [1, 5] + +[adsp] +name = "sue" +image_size = "0x300000" # (47 + 1) bank * 64KB +exec_boot_ldr = 1 +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0xBEFE0000" +size = "0x00002000" +[[adsp.mem_zone]] +type = "IMR" +base = "0xb0038000" +size = "0x100000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xbe000000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x9E000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xBE000000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x2000" diff --git a/tools/rimage/config/tgl-cavs.toml b/tools/rimage/config/tgl-cavs.toml new file mode 100644 index 000000000000..320c1f3531e4 --- /dev/null +++ b/tools/rimage/config/tgl-cavs.toml @@ -0,0 +1,498 @@ +version = [2, 5] + +[adsp] +name = "tgl" +image_size = "0x2F0000" +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0x9F180000" +size = "0x00002000" +[[adsp.mem_zone]] +type = "IMR" +base = "0xB0000000" +size = "0x1000000" +[[adsp.mem_zone]] +type = "HP-SRAM" +base = "0xBE000000" +size = "0x800000" +[[adsp.mem_zone]] +type = "LP-SRAM" +base = "0xBE800000" +size = "0x40" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x9E000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xBE000000" + +[cse] +partition_name = "ADSP" +[[cse.entry]] +name = "ADSP.man" +offset = "0x5c" +length = "0x464" +[[cse.entry]] +name = "cavs0015.met" +offset = "0x4c0" +length = "0x70" +[[cse.entry]] +name = "cavs0015" +offset = "0x540" +length = "0x0" # calculated by rimage + +[css] + +[signed_pkg] +name = "ADSP" +[[signed_pkg.module]] +name = "cavs0015.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x30000" + +[module] +count = 21 + [[module.entry]] + name = "BRNGUP" + uuid = "61EB0CB9-34D8-4F59-A21D-04C54C21D3A4" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + [[module.entry]] + name = "BASEFW" + uuid = "383B9BE2-3518-4DB0-8891-B1470A8914F8" + affinity_mask = "3" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + [[module.entry]] + name = "MIXIN" + uuid = "39656EB2-3B71-4049-8D3F-F92CD5C43C09" + affinity_mask = "0x1" + instance_count = "30" + domain_types = "0" + load_type = "0" + module_type = "1" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [ 0, 0, 0, 0, 296, 644000, 45, 60, 0, 0, 0, + 1, 0, 0, 0, 296, 669900, 48, 64, 0, 0, 0, + 2, 0, 0, 0, 296, 934000, 96, 128, 0, 0, 0, + 3, 0, 0, 0, 296, 1137000, 96, 128, 0, 0, 0, + 4, 0, 0, 0, 296, 1482000, 48, 64, 0, 0, 0, + 5, 0, 0, 0, 296, 1746000, 96, 128, 0, 0, 0, + 6, 0, 0, 0, 296, 2274000, 192, 256, 0, 0, 0, + 7, 0, 0, 0, 296, 2700000, 48, 64, 0, 0, 0, + 8, 0, 0, 0, 296, 2964000, 96, 128, 0, 0, 0, + 9, 0, 0, 0, 296, 3492000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "MIXOUT" + uuid = "3C56505A-24D7-418F-BDDC-C1F5A3AC2AE0" + affinity_mask = "0x1" + instance_count = "30" + domain_types = "0" + load_type = "0" + module_type = "2" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [1, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 520, 649600, 48, 64, 0, 0, 0, + 1, 0, 0, 0, 520, 966300, 96, 128, 0, 0, 0, + 2, 0, 0, 0, 520, 2101000, 48, 64, 0, 0, 0, + 3, 0, 0, 0, 520, 2500800, 192, 256, 0, 0, 0, + 4, 0, 0, 0, 520, 2616700, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 520, 2964500, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 520, 4202000, 96, 128, 0, 0, 0, + 7, 0, 0, 0, 520, 3730000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "COPIER" + uuid = "9BA00C83-CA12-4A83-943C-1FA2E82F9DDA" + affinity_mask = "0x1" + instance_count = "32" + domain_types = "0" + load_type = "0" + module_type = "3" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [ 0, 0, 0, 0, 280, 640100, 45, 60, 0, 0, 0, + 1, 0, 0, 0, 280, 1106300, 192, 192, 0, 0, 0, + 2, 0, 0, 0, 280, 1573000, 45, 45, 0, 0, 0, + 3, 0, 0, 0, 280, 2040600, 192, 256, 0, 0, 0, + 4, 0, 0, 0, 280, 2507500, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 280, 2999000, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 280, 3501000, 45, 60, 0, 0, 0, + 7, 0, 0, 0, 280, 3927000, 192, 256, 0, 0, 0, + 8, 0, 0, 0, 280, 4424000, 192, 256, 0, 0, 0, + 9, 0, 0, 0, 280, 4941000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "PEAKVOL" + uuid = "8A171323-94A3-4E1D-AFE9-FE5DBAA4C393" + affinity_mask = "0x1" + instance_count = "10" + domain_types = "0" + load_type = "0" + module_type = "4" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 480, 1114000, 48, 64, 0, 0, 0, + 1, 0, 0, 0, 480, 3321600, 192, 256, 0, 0, 0, + 2, 0, 0, 0, 480, 3786000, 192, 256, 0, 0, 0, + 3, 0, 0, 0, 480, 4333000, 48, 64, 0, 0, 0, + 4, 0, 0, 0, 480, 4910000, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 480, 5441000, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 480, 6265000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "GAIN" + uuid = "61BCA9A8-18D0-4A18-8E7B-2639219804B7" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 416, 914000, 48, 64, 0, 0, 0, + 1, 0, 0, 0, 416, 1321600, 192, 256, 0, 0, 0, + 2, 0, 0, 0, 416, 1786000, 192, 256, 0, 0, 0, + 3, 0, 0, 0, 416, 2333000, 48, 64, 0, 0, 0, + 4, 0, 0, 0, 416, 2910000, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 416, 3441000, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 416, 4265000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "PROBE" + uuid = "7CAD0808-AB10-CD23-EF45-12AB34CD56EF" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 100000, 48, 48, 0, 1000, 0] + + [[module.entry]] + name = "SRCINTC" + uuid = "e61bb28d-149a-4c1f-b709-46823ef5f5ae" + affinity_mask = "0xF" + instance_count = "10" + domain_types = "0" + load_type = "0" + module_type = "0x7" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xffff, 0xc, 0x8, 0x45ff, + 1, 0, 0xf6c9, 0xc, 0x8, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 12832, 1365500, 0, 0, 0, 1365, 0, + 1, 0, 0, 0, 12832, 2302300, 0, 0, 0, 2302, 0, + 2, 0, 0, 0, 12832, 3218200, 0, 0, 0, 3218, 0, + 3, 0, 0, 0, 12832, 4169700, 0, 0, 0, 4169, 0, + 4, 0, 0, 0, 12832, 5095100, 0, 0, 0, 5095, 0, + 5, 0, 0, 0, 12832, 6014800, 0, 0, 0, 6014, 0, + 6, 0, 0, 0, 12832, 6963500, 0, 0, 0, 6963, 0, + 7, 0, 0, 0, 12832, 7791000, 0, 0, 0, 7791, 0, + 8, 0, 0, 0, 12832, 8843000, 0, 0, 0, 8843, 0, + 9, 0, 0, 0, 12832, 9755100, 0, 0, 0, 9755, 0, + 10, 0, 0, 0, 12832, 10726500, 0, 0, 0, 10726, 0, + 11, 0, 0, 0, 12832, 11624100, 0, 0, 0, 11624, 0, + 12, 0, 0, 0, 12832, 12518700, 0, 0, 0, 12518, 0, + 13, 0, 0, 0, 12832, 13555000, 0, 0, 0, 13555, 0, + 14, 0, 0, 0, 12832, 14144500, 0, 0, 0, 14144, 0, + 15, 0, 0, 0, 12832, 15809800, 0, 0, 0, 15809, 0, + 16, 0, 0, 0, 12832, 16749000, 0, 0, 0, 16749, 0, + 17, 0, 0, 0, 12832, 18433500, 0, 0, 0, 18433, 0, + 18, 0, 0, 0, 12832, 19425900, 0, 0, 0, 19425, 0, + 19, 0, 0, 0, 12832, 20396900, 0, 0, 0, 20396, 0, + 20, 0, 0, 0, 12832, 20881000, 0, 0, 0, 20881, 0, + 21, 0, 0, 0, 12832, 23431000, 0, 0, 0, 23431, 0, + 22, 0, 0, 0, 12832, 30471000, 0, 0, 0, 30471, 0] + + # smart amp test module config + [[module.entry]] + name = "SMATEST" + uuid = "167A961E-8AE4-11EA-89F1-000C29CE1635" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0xD" + init_config = "1" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # eq iir module config + [[module.entry]] + name = "EQIIR" + uuid = "5150C0E6-27F9-4EC8-8351-C705B642D12F" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # eq fir module config + [[module.entry]] + name = "EQFIR" + uuid = "43A90CE7-f3A5-41Df-AC06-BA98651AE6A3" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + [[module.entry]] + name = "KDTEST" + uuid = "EBA8D51F-7827-47B5-82EE-DE6E7743AF67" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "1" + module_type = "8" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 480, 1114000, 64, 64, 0, 0, 0] + + [[module.entry]] + name = "KPB" + uuid = "D8218443-5FF3-4A4C-B388-6CFE07B9562E" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "1" + module_type = "0xB" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 14400, 1114000, 16, 16, 0, 0, 0] + + [[module.entry]] + name = "MICSEL" + uuid = "32FE92C1-1E17-4FC2-9758-C7F3542E980A" + affinity_mask = "0x1" + instance_count = "8" + domain_types = "0" + load_type = "0" + module_type = "0xC" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xe, 0xa, 0x45ff, 1, 0, 0xfeef, 0xe, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 960, 488500, 16, 16, 0, 0, 0, + 1, 0, 0, 0, 960, 964500, 16, 16, 0, 0, 0, + 2, 0, 0, 0, 960, 2003000, 16, 16, 0, 0, 0] + + # Aria module config + [[module.entry]] + name = "ARIA" + uuid = "99F7166D-372C-43EF-81F6-22007AA15F03" + affinity_mask = "0x1" + instance_count = "8" + domain_types = "0" + load_type = "0" + init_config = "1" + module_type = "30" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 260, 1063000, 16, 21, 0, 0, 0, + 1, 0, 0, 0, 260, 1873500, 192, 256, 0, 0, 0, + 2, 0, 0, 0, 260, 2680000, 32, 42, 0, 0, 0, + 3, 0, 0, 0, 260, 3591000, 64, 85, 0, 0, 0, + 4, 0, 0, 0, 260, 4477000, 96, 128, 0, 0, 0, + 5, 0, 0, 0, 260, 7195000, 192, 192, 0, 0, 0] + + # DRC module config + [[module.entry]] + name = "DRC" + uuid = "B36EE4DA-006F-47F9-A06D-FECBE2D8B6CE" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # Crossover module config + # Note: Crossover has init_config set to 1 to let kernel know that the base_cfg_ext needs to + # be appended to the IPC payload. The Extension is needed to know the output pin indices. + [[module.entry]] + name = "XOVER" + uuid = "948C9AD1-806A-4131-AD6C-B2BDA9E35A9F" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + init_config = "1" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # Multiband-DRC module config + [[module.entry]] + name = "MB_DRC" + uuid = "0D9F2256-8E4F-47B3-8448-239A334F1191" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # DCblock module config + [[module.entry]] + name = "DCBLOCK" + uuid = "B809EFAF-5681-42B1-9ED6-04BB012DD384" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # TDFB module config + [[module.entry]] + name = "TDFB" + uuid = "DD511749-D9FA-455C-B3A7-13585693F1AF" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] diff --git a/tools/rimage/config/tgl-h-cavs.toml b/tools/rimage/config/tgl-h-cavs.toml new file mode 100644 index 000000000000..61c3c01ad464 --- /dev/null +++ b/tools/rimage/config/tgl-h-cavs.toml @@ -0,0 +1,498 @@ +version = [2, 5] + +[adsp] +name = "tgl" +image_size = "0x1F0000" # (30 + 1) bank * 64KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0x9F180000" +size = "0x00002000" +[[adsp.mem_zone]] +type = "IMR" +base = "0xB0000000" +size = "0x1000000" +[[adsp.mem_zone]] +type = "HP-SRAM" +base = "0xBE000000" +size = "0x800000" +[[adsp.mem_zone]] +type = "LP-SRAM" +base = "0xBE800000" +size = "0x40" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x9E000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xBE000000" + +[cse] +partition_name = "ADSP" +[[cse.entry]] +name = "ADSP.man" +offset = "0x5c" +length = "0x464" +[[cse.entry]] +name = "cavs0015.met" +offset = "0x4c0" +length = "0x70" +[[cse.entry]] +name = "cavs0015" +offset = "0x540" +length = "0x0" # calculated by rimage + +[css] + +[signed_pkg] +name = "ADSP" +[[signed_pkg.module]] +name = "cavs0015.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x30000" + +[module] +count = 21 + [[module.entry]] + name = "BRNGUP" + uuid = "61EB0CB9-34D8-4F59-A21D-04C54C21D3A4" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + [[module.entry]] + name = "BASEFW" + uuid = "383B9BE2-3518-4DB0-8891-B1470A8914F8" + affinity_mask = "3" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0" + auto_start = "0" + + [[module.entry]] + name = "MIXIN" + uuid = "39656EB2-3B71-4049-8D3F-F92CD5C43C09" + affinity_mask = "0x1" + instance_count = "30" + domain_types = "0" + load_type = "0" + module_type = "1" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [ 0, 0, 0, 0, 296, 644000, 45, 60, 0, 0, 0, + 1, 0, 0, 0, 296, 669900, 48, 64, 0, 0, 0, + 2, 0, 0, 0, 296, 934000, 96, 128, 0, 0, 0, + 3, 0, 0, 0, 296, 1137000, 96, 128, 0, 0, 0, + 4, 0, 0, 0, 296, 1482000, 48, 64, 0, 0, 0, + 5, 0, 0, 0, 296, 1746000, 96, 128, 0, 0, 0, + 6, 0, 0, 0, 296, 2274000, 192, 256, 0, 0, 0, + 7, 0, 0, 0, 296, 2700000, 48, 64, 0, 0, 0, + 8, 0, 0, 0, 296, 2964000, 96, 128, 0, 0, 0, + 9, 0, 0, 0, 296, 3492000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "MIXOUT" + uuid = "3C56505A-24D7-418F-BDDC-C1F5A3AC2AE0" + affinity_mask = "0x1" + instance_count = "30" + domain_types = "0" + load_type = "0" + module_type = "2" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [1, 0, 0xfeef, 0xc, 0x8, 0x45ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 1, 0, 0xfeef, 0xc, 0x8, 0x1ff, + 0, 0, 0xfeef, 0xc, 0x8, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 520, 649600, 48, 64, 0, 0, 0, + 1, 0, 0, 0, 520, 966300, 96, 128, 0, 0, 0, + 2, 0, 0, 0, 520, 2101000, 48, 64, 0, 0, 0, + 3, 0, 0, 0, 520, 2500800, 192, 256, 0, 0, 0, + 4, 0, 0, 0, 520, 2616700, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 520, 2964500, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 520, 4202000, 96, 128, 0, 0, 0, + 7, 0, 0, 0, 520, 3730000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "COPIER" + uuid = "9BA00C83-CA12-4A83-943C-1FA2E82F9DDA" + affinity_mask = "0x1" + instance_count = "32" + domain_types = "0" + load_type = "0" + module_type = "3" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [ 0, 0, 0, 0, 280, 640100, 45, 60, 0, 0, 0, + 1, 0, 0, 0, 280, 1106300, 192, 192, 0, 0, 0, + 2, 0, 0, 0, 280, 1573000, 45, 45, 0, 0, 0, + 3, 0, 0, 0, 280, 2040600, 192, 256, 0, 0, 0, + 4, 0, 0, 0, 280, 2507500, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 280, 2999000, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 280, 3501000, 45, 60, 0, 0, 0, + 7, 0, 0, 0, 280, 3927000, 192, 256, 0, 0, 0, + 8, 0, 0, 0, 280, 4424000, 192, 256, 0, 0, 0, + 9, 0, 0, 0, 280, 4941000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "PEAKVOL" + uuid = "8A171323-94A3-4E1D-AFE9-FE5DBAA4C393" + affinity_mask = "0x1" + instance_count = "10" + domain_types = "0" + load_type = "0" + module_type = "4" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 480, 1114000, 48, 64, 0, 0, 0, + 1, 0, 0, 0, 480, 3321600, 192, 256, 0, 0, 0, + 2, 0, 0, 0, 480, 3786000, 192, 256, 0, 0, 0, + 3, 0, 0, 0, 480, 4333000, 48, 64, 0, 0, 0, + 4, 0, 0, 0, 480, 4910000, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 480, 5441000, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 480, 6265000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "GAIN" + uuid = "61BCA9A8-18D0-4A18-8E7B-2639219804B7" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 416, 914000, 48, 64, 0, 0, 0, + 1, 0, 0, 0, 416, 1321600, 192, 256, 0, 0, 0, + 2, 0, 0, 0, 416, 1786000, 192, 256, 0, 0, 0, + 3, 0, 0, 0, 416, 2333000, 48, 64, 0, 0, 0, + 4, 0, 0, 0, 416, 2910000, 192, 256, 0, 0, 0, + 5, 0, 0, 0, 416, 3441000, 192, 256, 0, 0, 0, + 6, 0, 0, 0, 416, 4265000, 192, 256, 0, 0, 0] + + [[module.entry]] + name = "PROBE" + uuid = "7CAD0808-AB10-CD23-EF45-12AB34CD56EF" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 100000, 48, 48, 0, 1000, 0] + + [[module.entry]] + name = "SRCINTC" + uuid = "e61bb28d-149a-4c1f-b709-46823ef5f5ae" + affinity_mask = "0xF" + instance_count = "10" + domain_types = "0" + load_type = "0" + module_type = "0x7" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xffff, 0xc, 0x8, 0x45ff, + 1, 0, 0xf6c9, 0xc, 0x8, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 12832, 1365500, 0, 0, 0, 1365, 0, + 1, 0, 0, 0, 12832, 2302300, 0, 0, 0, 2302, 0, + 2, 0, 0, 0, 12832, 3218200, 0, 0, 0, 3218, 0, + 3, 0, 0, 0, 12832, 4169700, 0, 0, 0, 4169, 0, + 4, 0, 0, 0, 12832, 5095100, 0, 0, 0, 5095, 0, + 5, 0, 0, 0, 12832, 6014800, 0, 0, 0, 6014, 0, + 6, 0, 0, 0, 12832, 6963500, 0, 0, 0, 6963, 0, + 7, 0, 0, 0, 12832, 7791000, 0, 0, 0, 7791, 0, + 8, 0, 0, 0, 12832, 8843000, 0, 0, 0, 8843, 0, + 9, 0, 0, 0, 12832, 9755100, 0, 0, 0, 9755, 0, + 10, 0, 0, 0, 12832, 10726500, 0, 0, 0, 10726, 0, + 11, 0, 0, 0, 12832, 11624100, 0, 0, 0, 11624, 0, + 12, 0, 0, 0, 12832, 12518700, 0, 0, 0, 12518, 0, + 13, 0, 0, 0, 12832, 13555000, 0, 0, 0, 13555, 0, + 14, 0, 0, 0, 12832, 14144500, 0, 0, 0, 14144, 0, + 15, 0, 0, 0, 12832, 15809800, 0, 0, 0, 15809, 0, + 16, 0, 0, 0, 12832, 16749000, 0, 0, 0, 16749, 0, + 17, 0, 0, 0, 12832, 18433500, 0, 0, 0, 18433, 0, + 18, 0, 0, 0, 12832, 19425900, 0, 0, 0, 19425, 0, + 19, 0, 0, 0, 12832, 20396900, 0, 0, 0, 20396, 0, + 20, 0, 0, 0, 12832, 20881000, 0, 0, 0, 20881, 0, + 21, 0, 0, 0, 12832, 23431000, 0, 0, 0, 23431, 0, + 22, 0, 0, 0, 12832, 30471000, 0, 0, 0, 30471, 0] + + # smart amp test module config + [[module.entry]] + name = "SMATEST" + uuid = "167A961E-8AE4-11EA-89F1-000C29CE1635" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "0" + module_type = "0xD" + init_config = "1" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # eq iir module config + [[module.entry]] + name = "EQIIR" + uuid = "5150C0E6-27F9-4EC8-8351-C705B642D12F" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # eq fir module config + [[module.entry]] + name = "EQFIR" + uuid = "43A90CE7-f3A5-41Df-AC06-BA98651AE6A3" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + [[module.entry]] + name = "KDTEST" + uuid = "EBA8D51F-7827-47B5-82EE-DE6E7743AF67" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "1" + module_type = "8" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 480, 1114000, 64, 64, 0, 0, 0] + + [[module.entry]] + name = "KPB" + uuid = "D8218443-5FF3-4A4C-B388-6CFE07B9562E" + affinity_mask = "0x1" + instance_count = "1" + domain_types = "0" + load_type = "1" + module_type = "0xB" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 14400, 1114000, 16, 16, 0, 0, 0] + + [[module.entry]] + name = "MICSEL" + uuid = "32FE92C1-1E17-4FC2-9758-C7F3542E980A" + affinity_mask = "0x1" + instance_count = "8" + domain_types = "0" + load_type = "0" + module_type = "0xC" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xe, 0xa, 0x45ff, 1, 0, 0xfeef, 0xe, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 960, 488500, 16, 16, 0, 0, 0, + 1, 0, 0, 0, 960, 964500, 16, 16, 0, 0, 0, + 2, 0, 0, 0, 960, 2003000, 16, 16, 0, 0, 0] + + # Aria module config + [[module.entry]] + name = "ARIA" + uuid = "99F7166D-372C-43EF-81F6-22007AA15F03" + affinity_mask = "0x1" + instance_count = "8" + domain_types = "0" + load_type = "0" + init_config = "1" + module_type = "30" + auto_start = "0" + sched_caps = [1, 0x00008000] + + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xa, 0x45ff, + 1, 0, 0xfeef, 0xf, 0xa, 0x45ff] + + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 260, 1063000, 16, 21, 0, 0, 0, + 1, 0, 0, 0, 260, 1873500, 192, 256, 0, 0, 0, + 2, 0, 0, 0, 260, 2680000, 32, 42, 0, 0, 0, + 3, 0, 0, 0, 260, 3591000, 64, 85, 0, 0, 0, + 4, 0, 0, 0, 260, 4477000, 96, 128, 0, 0, 0, + 5, 0, 0, 0, 260, 7195000, 192, 192, 0, 0, 0] + + # DRC module config + [[module.entry]] + name = "DRC" + uuid = "B36EE4DA-006F-47F9-A06D-FECBE2D8B6CE" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # Crossover module config + # Note: Crossover has init_config set to 1 to let kernel know that the base_cfg_ext needs to + # be appended to the IPC payload. The Extension is needed to know the output pin indices. + [[module.entry]] + name = "XOVER" + uuid = "948C9AD1-806A-4131-AD6C-B2BDA9E35A9F" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + init_config = "1" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # Multiband-DRC module config + [[module.entry]] + name = "MB_DRC" + uuid = "0D9F2256-8E4F-47B3-8448-239A334F1191" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # DCblock module config + [[module.entry]] + name = "DCBLOCK" + uuid = "B809EFAF-5681-42B1-9ED6-04BB012DD384" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + # TDFB module config + [[module.entry]] + name = "TDFB" + uuid = "DD511749-D9FA-455C-B3A7-13585693F1AF" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] diff --git a/tools/rimage/config/tgl-h.toml b/tools/rimage/config/tgl-h.toml new file mode 100644 index 000000000000..997e1a832899 --- /dev/null +++ b/tools/rimage/config/tgl-h.toml @@ -0,0 +1,56 @@ +version = [2, 5] + +[adsp] +name = "tgl" +image_size = "0x1F0000" # (30 + 1) bank * 64KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0x9F180000" +size = "0x00002000" +[[adsp.mem_zone]] +type = "IMR" +base = "0xB0038000" +size = "0x100000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xBE040000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x9E000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xBE000000" + +[cse] +partition_name = "ADSP" +[[cse.entry]] +name = "ADSP.man" +offset = "0x5c" +length = "0x464" +[[cse.entry]] +name = "cavs0015.met" +offset = "0x4c0" +length = "0x70" +[[cse.entry]] +name = "cavs0015" +offset = "0x540" +length = "0x0" # calculated by rimage + +[css] + +[signed_pkg] +name = "ADSP" +[[signed_pkg.module]] +name = "cavs0015.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x30000" diff --git a/tools/rimage/config/tgl.toml b/tools/rimage/config/tgl.toml new file mode 100644 index 000000000000..9a64c694c7f8 --- /dev/null +++ b/tools/rimage/config/tgl.toml @@ -0,0 +1,56 @@ +version = [2, 5] + +[adsp] +name = "tgl" +image_size = "0x2F0000" # (46 + 1) bank * 64KB +alias_mask = "0xE0000000" + +[[adsp.mem_zone]] +type = "ROM" +base = "0x9F180000" +size = "0x00002000" +[[adsp.mem_zone]] +type = "IMR" +base = "0xB0038000" +size = "0x100000" +[[adsp.mem_zone]] +type = "SRAM" +base = "0xBE040000" +size = "0x100000" + +[[adsp.mem_alias]] +type = "uncached" +base = "0x9E000000" +[[adsp.mem_alias]] +type = "cached" +base = "0xBE000000" + +[cse] +partition_name = "ADSP" +[[cse.entry]] +name = "ADSP.man" +offset = "0x5c" +length = "0x464" +[[cse.entry]] +name = "cavs0015.met" +offset = "0x4c0" +length = "0x70" +[[cse.entry]] +name = "cavs0015" +offset = "0x540" +length = "0x0" # calculated by rimage + +[css] + +[signed_pkg] +name = "ADSP" +[[signed_pkg.module]] +name = "cavs0015.met" + +[adsp_file] +[[adsp_file.comp]] +base_offset = "0x2000" + +[fw_desc.header] +name = "ADSPFW" +load_offset = "0x30000" diff --git a/tools/rimage/config/vangogh.toml b/tools/rimage/config/vangogh.toml new file mode 100644 index 000000000000..c5acdb9c9ba3 --- /dev/null +++ b/tools/rimage/config/vangogh.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "vangogh" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x20000000" +size = "0x40000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "DRAM" +base = "0xE0000000" +size = "0x100000" +host_offset = "0x0" diff --git a/tools/rimage/scripts/checkpatch.pl b/tools/rimage/scripts/checkpatch.pl new file mode 100755 index 000000000000..ce33a3b0ac98 --- /dev/null +++ b/tools/rimage/scripts/checkpatch.pl @@ -0,0 +1,6845 @@ +#!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0 +# +# (c) 2001, Dave Jones. (the file handling bit) +# (c) 2005, Joel Schopp (the ugly bit) +# (c) 2007,2008, Andy Whitcroft (new conditions, test suite) +# (c) 2008-2010 Andy Whitcroft +# (c) 2010-2018 Joe Perches + +use strict; +use warnings; +use POSIX; +use File::Basename; +use Cwd 'abs_path'; +use Term::ANSIColor qw(:constants); +use Encode qw(decode encode); + +my $P = $0; +my $D = dirname(abs_path($P)); + +my $V = '0.32'; + +use Getopt::Long qw(:config no_auto_abbrev); + +my $SOF = 1; # enables SOF-specific behaviour +my $quiet = 0; +my $tree = 1; +my $chk_signoff = 1; +my $chk_patch = 1; +my $tst_only; +my $emacs = 0; +my $terse = 0; +my $showfile = 0; +my $file = 0; +my $git = 0; +my %git_commits = (); +my $check = 0; +my $check_orig = 0; +my $summary = 1; +my $mailback = 0; +my $summary_file = 0; +my $show_types = 0; +my $list_types = 0; +my $fix = 0; +my $fix_inplace = 0; +my $root; +my %debug; +my %camelcase = (); +my %use_type = (); +my @use = (); +my %ignore_type = (); +my @ignore = (); +my $help = 0; +my $configuration_file = ".checkpatch.conf"; +my $max_line_length = 100; +my $ignore_perl_version = 0; +my $minimum_perl_version = 5.10.0; +my $min_conf_desc_length = 4; +my $spelling_file = "$D/spelling.txt"; +my $codespell = 0; +my $codespellfile = "/usr/share/codespell/dictionary.txt"; +my $conststructsfile = "$D/const_structs.checkpatch"; +my $typedefsfile = ""; +my $color = "auto"; +my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE +# git output parsing needs US English output, so first set backtick child process LANGUAGE +my $git_command ='export LANGUAGE=en_US.UTF-8; git'; + +sub help { + my ($exitcode) = @_; + + print << "EOM"; +Usage: $P [OPTION]... [FILE]... +Version: $V + +Options: + -q, --quiet quiet + --no-tree run without a kernel tree + --no-signoff do not check for 'Signed-off-by' line + --patch treat FILE as patchfile (default) + --emacs emacs compile window format + --terse one line per report + --showfile emit diffed file position, not input file position + -g, --git treat FILE as a single commit or git revision range + single git commit with: + + ^ + ~n + multiple git commits with: + .. + ... + - + git merges are ignored + -f, --file treat FILE as regular source file + --subjective, --strict enable more subjective tests + --list-types list the possible message types + --types TYPE(,TYPE2...) show only these comma separated message types + --ignore TYPE(,TYPE2...) ignore various comma separated message types + --show-types show the specific message type in the output + --max-line-length=n set the maximum line length, (default $max_line_length) + if exceeded, warn on patches + requires --strict for use with --file + --min-conf-desc-length=n set the min description length, if shorter, warn + --root=PATH PATH to the kernel tree root + --no-summary suppress the per-file summary + --mailback only produce a report in case of warnings/errors + --summary-file include the filename in summary + --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of + 'values', 'possible', 'type', and 'attr' (default + is all off) + --test-only=WORD report only warnings/errors containing WORD + literally + --fix EXPERIMENTAL - may create horrible results + If correctable single-line errors exist, create + ".EXPERIMENTAL-checkpatch-fixes" + with potential errors corrected to the preferred + checkpatch style + --fix-inplace EXPERIMENTAL - may create horrible results + Is the same as --fix, but overwrites the input + file. It's your fault if there's no backup or git + --ignore-perl-version override checking of perl version. expect + runtime errors. + --codespell Use the codespell dictionary for spelling/typos + (default:/usr/share/codespell/dictionary.txt) + --codespellfile Use this codespell dictionary + --typedefsfile Read additional types from this file + --color[=WHEN] Use colors 'always', 'never', or only when output + is a terminal ('auto'). Default is 'auto'. + -h, --help, --version display this help and exit + +When FILE is - read standard input. +EOM + + exit($exitcode); +} + +sub uniq { + my %seen; + return grep { !$seen{$_}++ } @_; +} + +sub list_types { + my ($exitcode) = @_; + + my $count = 0; + + local $/ = undef; + + open(my $script, '<', abs_path($P)) or + die "$P: Can't read '$P' $!\n"; + + my $text = <$script>; + close($script); + + my @types = (); + # Also catch when type or level is passed through a variable + for ($text =~ /(?:(?:\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) { + push (@types, $_); + } + @types = sort(uniq(@types)); + print("#\tMessage type\n\n"); + foreach my $type (@types) { + print(++$count . "\t" . $type . "\n"); + } + + exit($exitcode); +} + +my $conf = which_conf($configuration_file); +if (-f $conf) { + my @conf_args; + open(my $conffile, '<', "$conf") + or warn "$P: Can't find a readable $configuration_file file $!\n"; + + while (<$conffile>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + $line =~ s/\s+/ /g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + + my @words = split(" ", $line); + foreach my $word (@words) { + last if ($word =~ m/^#/); + push (@conf_args, $word); + } + } + close($conffile); + unshift(@ARGV, @conf_args) if @conf_args; +} + +# Perl's Getopt::Long allows options to take optional arguments after a space. +# Prevent --color by itself from consuming other arguments +foreach (@ARGV) { + if ($_ eq "--color" || $_ eq "-color") { + $_ = "--color=$color"; + } +} + +GetOptions( + 'q|quiet+' => \$quiet, + 'tree!' => \$tree, + 'signoff!' => \$chk_signoff, + 'patch!' => \$chk_patch, + 'emacs!' => \$emacs, + 'terse!' => \$terse, + 'showfile!' => \$showfile, + 'f|file!' => \$file, + 'g|git!' => \$git, + 'subjective!' => \$check, + 'strict!' => \$check, + 'ignore=s' => \@ignore, + 'types=s' => \@use, + 'show-types!' => \$show_types, + 'list-types!' => \$list_types, + 'max-line-length=i' => \$max_line_length, + 'min-conf-desc-length=i' => \$min_conf_desc_length, + 'root=s' => \$root, + 'summary!' => \$summary, + 'mailback!' => \$mailback, + 'summary-file!' => \$summary_file, + 'fix!' => \$fix, + 'fix-inplace!' => \$fix_inplace, + 'ignore-perl-version!' => \$ignore_perl_version, + 'debug=s' => \%debug, + 'test-only=s' => \$tst_only, + 'codespell!' => \$codespell, + 'codespellfile=s' => \$codespellfile, + 'typedefsfile=s' => \$typedefsfile, + 'color=s' => \$color, + 'no-color' => \$color, #keep old behaviors of -nocolor + 'nocolor' => \$color, #keep old behaviors of -nocolor + 'h|help' => \$help, + 'version' => \$help +) or help(1); + +help(0) if ($help); + +list_types(0) if ($list_types); + +$fix = 1 if ($fix_inplace); +$check_orig = $check; + +my $exit = 0; + +my $perl_version_ok = 1; +if ($^V && $^V lt $minimum_perl_version) { + $perl_version_ok = 0; + printf "$P: requires at least perl version %vd\n", $minimum_perl_version; + exit(1) if (!$ignore_perl_version); +} + +#if no filenames are given, push '-' to read patch from stdin +if ($#ARGV < 0) { + push(@ARGV, '-'); +} + +if ($color =~ /^[01]$/) { + $color = !$color; +} elsif ($color =~ /^always$/i) { + $color = 1; +} elsif ($color =~ /^never$/i) { + $color = 0; +} elsif ($color =~ /^auto$/i) { + $color = (-t STDOUT); +} else { + die "Invalid color mode: $color\n"; +} + +sub hash_save_array_words { + my ($hashRef, $arrayRef) = @_; + + my @array = split(/,/, join(',', @$arrayRef)); + foreach my $word (@array) { + $word =~ s/\s*\n?$//g; + $word =~ s/^\s*//g; + $word =~ s/\s+/ /g; + $word =~ tr/[a-z]/[A-Z]/; + + next if ($word =~ m/^\s*#/); + next if ($word =~ m/^\s*$/); + + $hashRef->{$word}++; + } +} + +sub hash_show_words { + my ($hashRef, $prefix) = @_; + + if (keys %$hashRef) { + print "\nNOTE: $prefix message types:"; + foreach my $word (sort keys %$hashRef) { + print " $word"; + } + print "\n"; + } +} + +hash_save_array_words(\%ignore_type, \@ignore); +hash_save_array_words(\%use_type, \@use); + +my $dbg_values = 0; +my $dbg_possible = 0; +my $dbg_type = 0; +my $dbg_attr = 0; +for my $key (keys %debug) { + ## no critic + eval "\${dbg_$key} = '$debug{$key}';"; + die "$@" if ($@); +} + +my $rpt_cleaners = 0; + +if ($terse) { + $emacs = 1; + $quiet++; +} + +if ($tree) { + if (defined $root) { + if (!top_of_kernel_tree($root)) { + die "$P: $root: --root does not point at a valid tree\n"; + } + } else { + if (top_of_kernel_tree('.')) { + $root = '.'; + } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ && + top_of_kernel_tree($1)) { + $root = $1; + } + } + + if (!defined $root) { + print "Must be run from the top-level dir. of a kernel tree\n"; + exit(2); + } +} + +my $emitted_corrupt = 0; + +our $Ident = qr{ + [A-Za-z_][A-Za-z\d_]* + (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)* + }x; +our $Storage = qr{extern|static|asmlinkage}; +our $Sparse = qr{ + __user| + __kernel| + __force| + __iomem| + __must_check| + __kprobes| + __ref| + __refconst| + __refdata| + __rcu| + __private + }x; +our $InitAttributePrefix = qr{__(?:mem|cpu|dev|net_|)}; +our $InitAttributeData = qr{$InitAttributePrefix(?:initdata\b)}; +our $InitAttributeConst = qr{$InitAttributePrefix(?:initconst\b)}; +our $InitAttributeInit = qr{$InitAttributePrefix(?:init\b)}; +our $InitAttribute = qr{$InitAttributeData|$InitAttributeConst|$InitAttributeInit}; + +# Notes to $Attribute: +# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check +our $Attribute = qr{ + const| + __percpu| + __nocast| + __safe| + __bitwise| + __packed__| + __packed2__| + __naked| + __maybe_unused| + __always_unused| + __noreturn| + __used| + __cold| + __pure| + __noclone| + __deprecated| + __read_mostly| + __ro_after_init| + __kprobes| + $InitAttribute| + ____cacheline_aligned| + ____cacheline_aligned_in_smp| + ____cacheline_internodealigned_in_smp| + __weak + }x; +our $Modifier; +our $Inline = qr{inline|__always_inline|noinline|__inline|__inline__}; +our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; +our $Lval = qr{$Ident(?:$Member)*}; + +our $Int_type = qr{(?i)llu|ull|ll|lu|ul|l|u}; +our $Binary = qr{(?i)0b[01]+$Int_type?}; +our $Hex = qr{(?i)0x[0-9a-f]+$Int_type?}; +our $Int = qr{[0-9]+$Int_type?}; +our $Octal = qr{0[0-7]+$Int_type?}; +our $String = qr{"[X\t]*"}; +our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?}; +our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?}; +our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?}; +our $Float = qr{$Float_hex|$Float_dec|$Float_int}; +our $Constant = qr{$Float|$Binary|$Octal|$Hex|$Int}; +our $Assignment = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=}; +our $Compare = qr{<=|>=|==|!=|<|(?}; +our $Arithmetic = qr{\+|-|\*|\/|%}; +our $Operators = qr{ + <=|>=|==|!=| + =>|->|<<|>>|<|>|!|~| + &&|\|\||,|\^|\+\+|--|&|\||$Arithmetic + }x; + +our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x; + +our $BasicType; +our $NonptrType; +our $NonptrTypeMisordered; +our $NonptrTypeWithAttr; +our $Type; +our $TypeMisordered; +our $Declare; +our $DeclareMisordered; + +our $NON_ASCII_UTF8 = qr{ + [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 +}x; + +our $UTF8 = qr{ + [\x09\x0A\x0D\x20-\x7E] # ASCII + | $NON_ASCII_UTF8 +}x; + +our $typeC99Typedefs = qr{(?:__)?(?:[us]_?)?int_?(?:8|16|32|64)_t}; +our $typeOtherOSTypedefs = qr{(?x: + u_(?:char|short|int|long) | # bsd + u(?:nchar|short|int|long) # sysv +)}; +our $typeKernelTypedefs = qr{(?x: + (?:__)?(?:u|s|be|le)(?:8|16|32|64)| + atomic_t +)}; +our $typeTypedefs = qr{(?x: + $typeC99Typedefs\b| + $typeOtherOSTypedefs\b| + $typeKernelTypedefs\b +)}; + +our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b}; + +our $logFunctions = qr{(?x: + printk(?:_ratelimited|_once|_deferred_once|_deferred|)| + (?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| + TP_printk| + WARN(?:_RATELIMIT|_ONCE|)| + panic| + MODULE_[A-Z_]+| + seq_vprintf|seq_printf|seq_puts| + trace[a-z_]+ +)}; + +our $allocFunctions = qr{(?x: + (?:(?:devm_)? + (?:kv|k|v)[czm]alloc(?:_node|_array)? | + kstrdup(?:_const)? | + kmemdup(?:_nul)?) | + (?:\w+)?alloc_skb(?:ip_align)? | + # dev_alloc_skb/netdev_alloc_skb, et al + dma_alloc_coherent +)}; + +our $signature_tags = qr{(?xi: + Signed-off-by:| + Co-developed-by:| + Acked-by:| + Tested-by:| + Reviewed-by:| + Reported-by:| + Suggested-by:| + To:| + Cc: +)}; + +our @typeListMisordered = ( + qr{char\s+(?:un)?signed}, + qr{int\s+(?:(?:un)?signed\s+)?short\s}, + qr{int\s+short(?:\s+(?:un)?signed)}, + qr{short\s+int(?:\s+(?:un)?signed)}, + qr{(?:un)?signed\s+int\s+short}, + qr{short\s+(?:un)?signed}, + qr{long\s+int\s+(?:un)?signed}, + qr{int\s+long\s+(?:un)?signed}, + qr{long\s+(?:un)?signed\s+int}, + qr{int\s+(?:un)?signed\s+long}, + qr{int\s+(?:un)?signed}, + qr{int\s+long\s+long\s+(?:un)?signed}, + qr{long\s+long\s+int\s+(?:un)?signed}, + qr{long\s+long\s+(?:un)?signed\s+int}, + qr{long\s+long\s+(?:un)?signed}, + qr{long\s+(?:un)?signed}, +); + +our @typeList = ( + qr{void}, + qr{(?:(?:un)?signed\s+)?char}, + qr{(?:(?:un)?signed\s+)?short\s+int}, + qr{(?:(?:un)?signed\s+)?short}, + qr{(?:(?:un)?signed\s+)?int}, + qr{(?:(?:un)?signed\s+)?long\s+int}, + qr{(?:(?:un)?signed\s+)?long\s+long\s+int}, + qr{(?:(?:un)?signed\s+)?long\s+long}, + qr{(?:(?:un)?signed\s+)?long}, + qr{(?:un)?signed}, + qr{float}, + qr{double}, + qr{bool}, + qr{struct\s+$Ident}, + qr{union\s+$Ident}, + qr{enum\s+$Ident}, + qr{${Ident}_t}, + qr{${Ident}_handler}, + qr{${Ident}_handler_fn}, + @typeListMisordered, +); + +our $C90_int_types = qr{(?x: + long\s+long\s+int\s+(?:un)?signed| + long\s+long\s+(?:un)?signed\s+int| + long\s+long\s+(?:un)?signed| + (?:(?:un)?signed\s+)?long\s+long\s+int| + (?:(?:un)?signed\s+)?long\s+long| + int\s+long\s+long\s+(?:un)?signed| + int\s+(?:(?:un)?signed\s+)?long\s+long| + + long\s+int\s+(?:un)?signed| + long\s+(?:un)?signed\s+int| + long\s+(?:un)?signed| + (?:(?:un)?signed\s+)?long\s+int| + (?:(?:un)?signed\s+)?long| + int\s+long\s+(?:un)?signed| + int\s+(?:(?:un)?signed\s+)?long| + + int\s+(?:un)?signed| + (?:(?:un)?signed\s+)?int +)}; + +our @typeListFile = (); +our @typeListWithAttr = ( + @typeList, + qr{struct\s+$InitAttribute\s+$Ident}, + qr{union\s+$InitAttribute\s+$Ident}, +); + +our @modifierList = ( + qr{fastcall}, +); +our @modifierListFile = (); + +our @mode_permission_funcs = ( + ["module_param", 3], + ["module_param_(?:array|named|string)", 4], + ["module_param_array_named", 5], + ["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)", 2], + ["proc_create(?:_data|)", 2], + ["(?:CLASS|DEVICE|SENSOR|SENSOR_DEVICE|IIO_DEVICE)_ATTR", 2], + ["IIO_DEV_ATTR_[A-Z_]+", 1], + ["SENSOR_(?:DEVICE_|)ATTR_2", 2], + ["SENSOR_TEMPLATE(?:_2|)", 3], + ["__ATTR", 2], +); + +#Create a search pattern for all these functions to speed up a loop below +our $mode_perms_search = ""; +foreach my $entry (@mode_permission_funcs) { + $mode_perms_search .= '|' if ($mode_perms_search ne ""); + $mode_perms_search .= $entry->[0]; +} +$mode_perms_search = "(?:${mode_perms_search})"; + +our %deprecated_apis = ( + "synchronize_rcu_bh" => "synchronize_rcu", + "synchronize_rcu_bh_expedited" => "synchronize_rcu_expedited", + "call_rcu_bh" => "call_rcu", + "rcu_barrier_bh" => "rcu_barrier", + "synchronize_sched" => "synchronize_rcu", + "synchronize_sched_expedited" => "synchronize_rcu_expedited", + "call_rcu_sched" => "call_rcu", + "rcu_barrier_sched" => "rcu_barrier", + "get_state_synchronize_sched" => "get_state_synchronize_rcu", + "cond_synchronize_sched" => "cond_synchronize_rcu", +); + +#Create a search pattern for all these strings to speed up a loop below +our $deprecated_apis_search = ""; +foreach my $entry (keys %deprecated_apis) { + $deprecated_apis_search .= '|' if ($deprecated_apis_search ne ""); + $deprecated_apis_search .= $entry; +} +$deprecated_apis_search = "(?:${deprecated_apis_search})"; + +our $mode_perms_world_writable = qr{ + S_IWUGO | + S_IWOTH | + S_IRWXUGO | + S_IALLUGO | + 0[0-7][0-7][2367] +}x; + +our %mode_permission_string_types = ( + "S_IRWXU" => 0700, + "S_IRUSR" => 0400, + "S_IWUSR" => 0200, + "S_IXUSR" => 0100, + "S_IRWXG" => 0070, + "S_IRGRP" => 0040, + "S_IWGRP" => 0020, + "S_IXGRP" => 0010, + "S_IRWXO" => 0007, + "S_IROTH" => 0004, + "S_IWOTH" => 0002, + "S_IXOTH" => 0001, + "S_IRWXUGO" => 0777, + "S_IRUGO" => 0444, + "S_IWUGO" => 0222, + "S_IXUGO" => 0111, +); + +#Create a search pattern for all these strings to speed up a loop below +our $mode_perms_string_search = ""; +foreach my $entry (keys %mode_permission_string_types) { + $mode_perms_string_search .= '|' if ($mode_perms_string_search ne ""); + $mode_perms_string_search .= $entry; +} +our $single_mode_perms_string_search = "(?:${mode_perms_string_search})"; +our $multi_mode_perms_string_search = qr{ + ${single_mode_perms_string_search} + (?:\s*\|\s*${single_mode_perms_string_search})* +}x; + +sub perms_to_octal { + my ($string) = @_; + + return trim($string) if ($string =~ /^\s*0[0-7]{3,3}\s*$/); + + my $val = ""; + my $oval = ""; + my $to = 0; + my $curpos = 0; + my $lastpos = 0; + while ($string =~ /\b(($single_mode_perms_string_search)\b(?:\s*\|\s*)?\s*)/g) { + $curpos = pos($string); + my $match = $2; + my $omatch = $1; + last if ($lastpos > 0 && ($curpos - length($omatch) != $lastpos)); + $lastpos = $curpos; + $to |= $mode_permission_string_types{$match}; + $val .= '\s*\|\s*' if ($val ne ""); + $val .= $match; + $oval .= $omatch; + } + $oval =~ s/^\s*\|\s*//; + $oval =~ s/\s*\|\s*$//; + return sprintf("%04o", $to); +} + +our $allowed_asm_includes = qr{(?x: + irq| + memory| + time| + reboot +)}; +# memory.h: ARM has a custom one + +# Load common spelling mistakes and build regular expression list. +my $misspellings; +my %spelling_fix; + +if (open(my $spelling, '<', $spelling_file)) { + while (<$spelling>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + + my ($suspect, $fix) = split(/\|\|/, $line); + + $spelling_fix{$suspect} = $fix; + } + close($spelling); +} else { + warn "No typos will be found - file '$spelling_file': $!\n"; +} + +if ($codespell) { + if (open(my $spelling, '<', $codespellfile)) { + while (<$spelling>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + next if ($line =~ m/, disabled/i); + + $line =~ s/,.*$//; + + my ($suspect, $fix) = split(/->/, $line); + + $spelling_fix{$suspect} = $fix; + } + close($spelling); + } else { + warn "No codespell typos will be found - file '$codespellfile': $!\n"; + } +} + +$misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix; + +sub read_words { + my ($wordsRef, $file) = @_; + + if (open(my $words, '<', $file)) { + while (<$words>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + if ($line =~ /\s/) { + print("$file: '$line' invalid - ignored\n"); + next; + } + + $$wordsRef .= '|' if ($$wordsRef ne ""); + $$wordsRef .= $line; + } + close($file); + return 1; + } + + return 0; +} + +my $const_structs = ""; +read_words(\$const_structs, $conststructsfile) + or warn "No structs that should be const will be found - file '$conststructsfile': $!\n"; + +my $typeOtherTypedefs = ""; +if (length($typedefsfile)) { + read_words(\$typeOtherTypedefs, $typedefsfile) + or warn "No additional types will be considered - file '$typedefsfile': $!\n"; +} +$typeTypedefs .= '|' . $typeOtherTypedefs if ($typeOtherTypedefs ne ""); + +sub build_types { + my $mods = "(?x: \n" . join("|\n ", (@modifierList, @modifierListFile)) . "\n)"; + my $all = "(?x: \n" . join("|\n ", (@typeList, @typeListFile)) . "\n)"; + my $Misordered = "(?x: \n" . join("|\n ", @typeListMisordered) . "\n)"; + my $allWithAttr = "(?x: \n" . join("|\n ", @typeListWithAttr) . "\n)"; + $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; + $BasicType = qr{ + (?:$typeTypedefs\b)| + (?:${all}\b) + }x; + $NonptrType = qr{ + (?:$Modifier\s+|const\s+)* + (?: + (?:typeof|__typeof__)\s*\([^\)]*\)| + (?:$typeTypedefs\b)| + (?:${all}\b) + ) + (?:\s+$Modifier|\s+const)* + }x; + $NonptrTypeMisordered = qr{ + (?:$Modifier\s+|const\s+)* + (?: + (?:${Misordered}\b) + ) + (?:\s+$Modifier|\s+const)* + }x; + $NonptrTypeWithAttr = qr{ + (?:$Modifier\s+|const\s+)* + (?: + (?:typeof|__typeof__)\s*\([^\)]*\)| + (?:$typeTypedefs\b)| + (?:${allWithAttr}\b) + ) + (?:\s+$Modifier|\s+const)* + }x; + $Type = qr{ + $NonptrType + (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+)? + (?:\s+$Inline|\s+$Modifier)* + }x; + $TypeMisordered = qr{ + $NonptrTypeMisordered + (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+)? + (?:\s+$Inline|\s+$Modifier)* + }x; + $Declare = qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type}; + $DeclareMisordered = qr{(?:$Storage\s+(?:$Inline\s+)?)?$TypeMisordered}; +} +build_types(); + +our $Typecast = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*}; + +# Using $balanced_parens, $LvalOrFunc, or $FuncArg +# requires at least perl version v5.10.0 +# Any use must be runtime checked with $^V + +our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/; +our $LvalOrFunc = qr{((?:[\&\*]\s*)?$Lval)\s*($balanced_parens{0,1})\s*}; +our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)}; + +our $declaration_macros = qr{(?x: + (?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(| + (?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(| + (?:$Storage\s+)?${Type}\s+uninitialized_var\s*\(| + (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\( +)}; + +sub deparenthesize { + my ($string) = @_; + return "" if (!defined($string)); + + while ($string =~ /^\s*\(.*\)\s*$/) { + $string =~ s@^\s*\(\s*@@; + $string =~ s@\s*\)\s*$@@; + } + + $string =~ s@\s+@ @g; + + return $string; +} + +sub seed_camelcase_file { + my ($file) = @_; + + return if (!(-f $file)); + + local $/; + + open(my $include_file, '<', "$file") + or warn "$P: Can't read '$file' $!\n"; + my $text = <$include_file>; + close($include_file); + + my @lines = split('\n', $text); + + foreach my $line (@lines) { + next if ($line !~ /(?:[A-Z][a-z]|[a-z][A-Z])/); + if ($line =~ /^[ \t]*(?:#[ \t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)/) { + $camelcase{$1} = 1; + } elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[\(\[,;]/) { + $camelcase{$1} = 1; + } elsif ($line =~ /^\s*(?:union|struct|enum)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[;\{]/) { + $camelcase{$1} = 1; + } + } +} + +sub is_maintained_obsolete { + my ($filename) = @_; + + return 0 if (!$tree || !(-e "$root/scripts/get_maintainer.pl")); + + my $status = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`; + + return $status =~ /obsolete/i; +} + +sub is_SPDX_License_valid { + my ($license) = @_; + + return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$root/.git")); + + my $root_path = abs_path($root); + my $status = `cd "$root_path"; echo "$license" | python scripts/spdxcheck.py -`; + return 0 if ($status ne ""); + return 1; +} + +my $camelcase_seeded = 0; +sub seed_camelcase_includes { + return if ($camelcase_seeded); + + my $files; + my $camelcase_cache = ""; + my @include_files = (); + + $camelcase_seeded = 1; + + if (-e ".git") { + my $git_last_include_commit = `${git_command} log --no-merges --pretty=format:"%h%n" -1 -- include`; + chomp $git_last_include_commit; + $camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit"; + } else { + my $last_mod_date = 0; + $files = `find $root/include -name "*.h"`; + @include_files = split('\n', $files); + foreach my $file (@include_files) { + my $date = POSIX::strftime("%Y%m%d%H%M", + localtime((stat $file)[9])); + $last_mod_date = $date if ($last_mod_date < $date); + } + $camelcase_cache = ".checkpatch-camelcase.date.$last_mod_date"; + } + + if ($camelcase_cache ne "" && -f $camelcase_cache) { + open(my $camelcase_file, '<', "$camelcase_cache") + or warn "$P: Can't read '$camelcase_cache' $!\n"; + while (<$camelcase_file>) { + chomp; + $camelcase{$_} = 1; + } + close($camelcase_file); + + return; + } + + if (-e ".git") { + $files = `${git_command} ls-files "include/*.h"`; + @include_files = split('\n', $files); + } + + foreach my $file (@include_files) { + seed_camelcase_file($file); + } + + if ($camelcase_cache ne "") { + unlink glob ".checkpatch-camelcase.*"; + open(my $camelcase_file, '>', "$camelcase_cache") + or warn "$P: Can't write '$camelcase_cache' $!\n"; + foreach (sort { lc($a) cmp lc($b) } keys(%camelcase)) { + print $camelcase_file ("$_\n"); + } + close($camelcase_file); + } +} + +sub git_commit_info { + my ($commit, $id, $desc) = @_; + + return ($id, $desc) if ((which("git") eq "") || !(-e ".git")); + + my $output = `${git_command} log --no-color --format='%H %s' -1 $commit 2>&1`; + $output =~ s/^\s*//gm; + my @lines = split("\n", $output); + + return ($id, $desc) if ($#lines < 0); + + if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous/) { +# Maybe one day convert this block of bash into something that returns +# all matching commit ids, but it's very slow... +# +# echo "checking commits $1..." +# git rev-list --remotes | grep -i "^$1" | +# while read line ; do +# git log --format='%H %s' -1 $line | +# echo "commit $(cut -c 1-12,41-)" +# done + } elsif ($lines[0] =~ /^fatal: ambiguous argument '$commit': unknown revision or path not in the working tree\./) { + $id = undef; + } else { + $id = substr($lines[0], 0, 12); + $desc = substr($lines[0], 41); + } + + return ($id, $desc); +} + +$chk_signoff = 0 if ($file); + +my @rawlines = (); +my @lines = (); +my @fixed = (); +my @fixed_inserted = (); +my @fixed_deleted = (); +my $fixlinenr = -1; + +# If input is git commits, extract all commits from the commit expressions. +# For example, HEAD-3 means we need check 'HEAD, HEAD~1, HEAD~2'. +die "$P: No git repository found\n" if ($git && !-e ".git"); + +if ($git) { + my @commits = (); + foreach my $commit_expr (@ARGV) { + my $git_range; + if ($commit_expr =~ m/^(.*)-(\d+)$/) { + $git_range = "-$2 $1"; + } elsif ($commit_expr =~ m/\.\./) { + $git_range = "$commit_expr"; + } else { + $git_range = "-1 $commit_expr"; + } + my $lines = `${git_command} log --no-color --no-merges --pretty=format:'%H %s' $git_range`; + foreach my $line (split(/\n/, $lines)) { + $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/; + next if (!defined($1) || !defined($2)); + my $sha1 = $1; + my $subject = $2; + unshift(@commits, $sha1); + $git_commits{$sha1} = $subject; + } + } + die "$P: no git commits after extraction!\n" if (@commits == 0); + @ARGV = @commits; +} + +my $vname; +$allow_c99_comments = !defined $ignore_type{"C99_COMMENT_TOLERANCE"}; +for my $filename (@ARGV) { + my $FILE; + if ($git) { + open($FILE, '-|', "git format-patch -M --stdout -1 $filename") || + die "$P: $filename: git format-patch failed - $!\n"; + } elsif ($file) { + open($FILE, '-|', "diff -u /dev/null $filename") || + die "$P: $filename: diff failed - $!\n"; + } elsif ($filename eq '-') { + open($FILE, '<&STDIN'); + } else { + open($FILE, '<', "$filename") || + die "$P: $filename: open failed - $!\n"; + } + if ($filename eq '-') { + $vname = 'Your patch'; + } elsif ($git) { + $vname = "Commit " . substr($filename, 0, 12) . ' ("' . $git_commits{$filename} . '")'; + } else { + $vname = $filename; + } + while (<$FILE>) { + chomp; + push(@rawlines, $_); + } + close($FILE); + + if ($#ARGV > 0 && $quiet == 0) { + print '-' x length($vname) . "\n"; + print "$vname\n"; + print '-' x length($vname) . "\n"; + } + + if (!process($filename)) { + $exit = 1; + } + @rawlines = (); + @lines = (); + @fixed = (); + @fixed_inserted = (); + @fixed_deleted = (); + $fixlinenr = -1; + @modifierListFile = (); + @typeListFile = (); + build_types(); +} + +if (!$quiet) { + hash_show_words(\%use_type, "Used"); + hash_show_words(\%ignore_type, "Ignored"); + + if (!$perl_version_ok) { + print << "EOM" + +NOTE: perl $^V is not modern enough to detect all possible issues. + An upgrade to at least perl $minimum_perl_version is suggested. +EOM + } + if ($exit) { + print << "EOM" + +NOTE: If any of the errors are false positives, please report + them to the maintainer, see CHECKPATCH in MAINTAINERS. +EOM + } +} + +exit($exit); + +sub top_of_kernel_tree { + my ($root) = @_; + + my @tree_check = ( + "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile", + "README", "Documentation", "arch", "include", "drivers", + "fs", "init", "ipc", "kernel", "lib", "scripts", + ); + + if ($SOF) { + @tree_check = ( + "LICENCE", "README.md", "rimage", "tools", + "scripts", "doc", "src", "CODEOWNERS", + "CMakeLists.txt", + ); + } + + foreach my $check (@tree_check) { + if (! -e $root . '/' . $check) { + return 0; + } + } + return 1; +} + +sub parse_email { + my ($formatted_email) = @_; + + my $name = ""; + my $address = ""; + my $comment = ""; + + if ($formatted_email =~ /^(.*)<(\S+\@\S+)>(.*)$/) { + $name = $1; + $address = $2; + $comment = $3 if defined $3; + } elsif ($formatted_email =~ /^\s*<(\S+\@\S+)>(.*)$/) { + $address = $1; + $comment = $2 if defined $2; + } elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) { + $address = $1; + $comment = $2 if defined $2; + $formatted_email =~ s/\Q$address\E.*$//; + $name = $formatted_email; + $name = trim($name); + $name =~ s/^\"|\"$//g; + # If there's a name left after stripping spaces and + # leading quotes, and the address doesn't have both + # leading and trailing angle brackets, the address + # is invalid. ie: + # "joe smith joe@smith.com" bad + # "joe smith ]+>$/) { + $name = ""; + $address = ""; + $comment = ""; + } + } + + $name = trim($name); + $name =~ s/^\"|\"$//g; + $address = trim($address); + $address =~ s/^\<|\>$//g; + + if ($name =~ /[^\w \-]/i) { ##has "must quote" chars + $name =~ s/(?"; + } + + return $formatted_email; +} + +sub which { + my ($bin) = @_; + + foreach my $path (split(/:/, $ENV{PATH})) { + if (-e "$path/$bin") { + return "$path/$bin"; + } + } + + return ""; +} + +sub which_conf { + my ($conf) = @_; + + foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) { + if (-e "$path/$conf") { + return "$path/$conf"; + } + } + + return ""; +} + +sub expand_tabs { + my ($str) = @_; + + my $res = ''; + my $n = 0; + for my $c (split(//, $str)) { + if ($c eq "\t") { + $res .= ' '; + $n++; + for (; ($n % 8) != 0; $n++) { + $res .= ' '; + } + next; + } + $res .= $c; + $n++; + } + + return $res; +} +sub copy_spacing { + (my $res = shift) =~ tr/\t/ /c; + return $res; +} + +sub line_stats { + my ($line) = @_; + + # Drop the diff line leader and expand tabs + $line =~ s/^.//; + $line = expand_tabs($line); + + # Pick the indent from the front of the line. + my ($white) = ($line =~ /^(\s*)/); + + return (length($line), length($white)); +} + +my $sanitise_quote = ''; + +sub sanitise_line_reset { + my ($in_comment) = @_; + + if ($in_comment) { + $sanitise_quote = '*/'; + } else { + $sanitise_quote = ''; + } +} +sub sanitise_line { + my ($line) = @_; + + my $res = ''; + my $l = ''; + + my $qlen = 0; + my $off = 0; + my $c; + + # Always copy over the diff marker. + $res = substr($line, 0, 1); + + for ($off = 1; $off < length($line); $off++) { + $c = substr($line, $off, 1); + + # Comments we are whacking completely including the begin + # and end, all to $;. + if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { + $sanitise_quote = '*/'; + + substr($res, $off, 2, "$;$;"); + $off++; + next; + } + if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') { + $sanitise_quote = ''; + substr($res, $off, 2, "$;$;"); + $off++; + next; + } + if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') { + $sanitise_quote = '//'; + + substr($res, $off, 2, $sanitise_quote); + $off++; + next; + } + + # A \ in a string means ignore the next character. + if (($sanitise_quote eq "'" || $sanitise_quote eq '"') && + $c eq "\\") { + substr($res, $off, 2, 'XX'); + $off++; + next; + } + # Regular quotes. + if ($c eq "'" || $c eq '"') { + if ($sanitise_quote eq '') { + $sanitise_quote = $c; + + substr($res, $off, 1, $c); + next; + } elsif ($sanitise_quote eq $c) { + $sanitise_quote = ''; + } + } + + #print "c<$c> SQ<$sanitise_quote>\n"; + if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") { + substr($res, $off, 1, $;); + } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") { + substr($res, $off, 1, $;); + } elsif ($off != 0 && $sanitise_quote && $c ne "\t") { + substr($res, $off, 1, 'X'); + } else { + substr($res, $off, 1, $c); + } + } + + if ($sanitise_quote eq '//') { + $sanitise_quote = ''; + } + + # The pathname on a #include may be surrounded by '<' and '>'. + if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) { + my $clean = 'X' x length($1); + $res =~ s@\<.*\>@<$clean>@; + + # The whole of a #error is a string. + } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) { + my $clean = 'X' x length($1); + $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@; + } + + if ($allow_c99_comments && $res =~ m@(//.*$)@) { + my $match = $1; + $res =~ s/\Q$match\E/"$;" x length($match)/e; + } + + return $res; +} + +sub get_quoted_string { + my ($line, $rawline) = @_; + + return "" if (!defined($line) || !defined($rawline)); + return "" if ($line !~ m/($String)/g); + return substr($rawline, $-[0], $+[0] - $-[0]); +} + +sub ctx_statement_block { + my ($linenr, $remain, $off) = @_; + my $line = $linenr - 1; + my $blk = ''; + my $soff = $off; + my $coff = $off - 1; + my $coff_set = 0; + + my $loff = 0; + + my $type = ''; + my $level = 0; + my @stack = (); + my $p; + my $c; + my $len = 0; + + my $remainder; + while (1) { + @stack = (['', 0]) if ($#stack == -1); + + #warn "CSB: blk<$blk> remain<$remain>\n"; + # If we are about to drop off the end, pull in more + # context. + if ($off >= $len) { + for (; $remain > 0; $line++) { + last if (!defined $lines[$line]); + next if ($lines[$line] =~ /^-/); + $remain--; + $loff = $len; + $blk .= $lines[$line] . "\n"; + $len = length($blk); + $line++; + last; + } + # Bail if there is no further context. + #warn "CSB: blk<$blk> off<$off> len<$len>\n"; + if ($off >= $len) { + last; + } + if ($level == 0 && substr($blk, $off) =~ /^.\s*#\s*define/) { + $level++; + $type = '#'; + } + } + $p = $c; + $c = substr($blk, $off, 1); + $remainder = substr($blk, $off); + + #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n"; + + # Handle nested #if/#else. + if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) { + push(@stack, [ $type, $level ]); + } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) { + ($type, $level) = @{$stack[$#stack - 1]}; + } elsif ($remainder =~ /^#\s*endif\b/) { + ($type, $level) = @{pop(@stack)}; + } + + # Statement ends at the ';' or a close '}' at the + # outermost level. + if ($level == 0 && $c eq ';') { + last; + } + + # An else is really a conditional as long as its not else if + if ($level == 0 && $coff_set == 0 && + (!defined($p) || $p =~ /(?:\s|\}|\+)/) && + $remainder =~ /^(else)(?:\s|{)/ && + $remainder !~ /^else\s+if\b/) { + $coff = $off + length($1) - 1; + $coff_set = 1; + #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n"; + #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n"; + } + + if (($type eq '' || $type eq '(') && $c eq '(') { + $level++; + $type = '('; + } + if ($type eq '(' && $c eq ')') { + $level--; + $type = ($level != 0)? '(' : ''; + + if ($level == 0 && $coff < $soff) { + $coff = $off; + $coff_set = 1; + #warn "CSB: mark coff<$coff>\n"; + } + } + if (($type eq '' || $type eq '{') && $c eq '{') { + $level++; + $type = '{'; + } + if ($type eq '{' && $c eq '}') { + $level--; + $type = ($level != 0)? '{' : ''; + + if ($level == 0) { + if (substr($blk, $off + 1, 1) eq ';') { + $off++; + } + last; + } + } + # Preprocessor commands end at the newline unless escaped. + if ($type eq '#' && $c eq "\n" && $p ne "\\") { + $level--; + $type = ''; + $off++; + last; + } + $off++; + } + # We are truly at the end, so shuffle to the next line. + if ($off == $len) { + $loff = $len + 1; + $line++; + $remain--; + } + + my $statement = substr($blk, $soff, $off - $soff + 1); + my $condition = substr($blk, $soff, $coff - $soff + 1); + + #warn "STATEMENT<$statement>\n"; + #warn "CONDITION<$condition>\n"; + + #print "coff<$coff> soff<$off> loff<$loff>\n"; + + return ($statement, $condition, + $line, $remain + 1, $off - $loff + 1, $level); +} + +sub statement_lines { + my ($stmt) = @_; + + # Strip the diff line prefixes and rip blank lines at start and end. + $stmt =~ s/(^|\n)./$1/g; + $stmt =~ s/^\s*//; + $stmt =~ s/\s*$//; + + my @stmt_lines = ($stmt =~ /\n/g); + + return $#stmt_lines + 2; +} + +sub statement_rawlines { + my ($stmt) = @_; + + my @stmt_lines = ($stmt =~ /\n/g); + + return $#stmt_lines + 2; +} + +sub statement_block_size { + my ($stmt) = @_; + + $stmt =~ s/(^|\n)./$1/g; + $stmt =~ s/^\s*{//; + $stmt =~ s/}\s*$//; + $stmt =~ s/^\s*//; + $stmt =~ s/\s*$//; + + my @stmt_lines = ($stmt =~ /\n/g); + my @stmt_statements = ($stmt =~ /;/g); + + my $stmt_lines = $#stmt_lines + 2; + my $stmt_statements = $#stmt_statements + 1; + + if ($stmt_lines > $stmt_statements) { + return $stmt_lines; + } else { + return $stmt_statements; + } +} + +sub ctx_statement_full { + my ($linenr, $remain, $off) = @_; + my ($statement, $condition, $level); + + my (@chunks); + + # Grab the first conditional/block pair. + ($statement, $condition, $linenr, $remain, $off, $level) = + ctx_statement_block($linenr, $remain, $off); + #print "F: c<$condition> s<$statement> remain<$remain>\n"; + push(@chunks, [ $condition, $statement ]); + if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) { + return ($level, $linenr, @chunks); + } + + # Pull in the following conditional/block pairs and see if they + # could continue the statement. + for (;;) { + ($statement, $condition, $linenr, $remain, $off, $level) = + ctx_statement_block($linenr, $remain, $off); + #print "C: c<$condition> s<$statement> remain<$remain>\n"; + last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s)); + #print "C: push\n"; + push(@chunks, [ $condition, $statement ]); + } + + return ($level, $linenr, @chunks); +} + +sub ctx_block_get { + my ($linenr, $remain, $outer, $open, $close, $off) = @_; + my $line; + my $start = $linenr - 1; + my $blk = ''; + my @o; + my @c; + my @res = (); + + my $level = 0; + my @stack = ($level); + for ($line = $start; $remain > 0; $line++) { + next if ($rawlines[$line] =~ /^-/); + $remain--; + + $blk .= $rawlines[$line]; + + # Handle nested #if/#else. + if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) { + push(@stack, $level); + } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) { + $level = $stack[$#stack - 1]; + } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) { + $level = pop(@stack); + } + + foreach my $c (split(//, $lines[$line])) { + ##print "C<$c>L<$level><$open$close>O<$off>\n"; + if ($off > 0) { + $off--; + next; + } + + if ($c eq $close && $level > 0) { + $level--; + last if ($level == 0); + } elsif ($c eq $open) { + $level++; + } + } + + if (!$outer || $level <= 1) { + push(@res, $rawlines[$line]); + } + + last if ($level == 0); + } + + return ($level, @res); +} +sub ctx_block_outer { + my ($linenr, $remain) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0); + return @r; +} +sub ctx_block { + my ($linenr, $remain) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0); + return @r; +} +sub ctx_statement { + my ($linenr, $remain, $off) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off); + return @r; +} +sub ctx_block_level { + my ($linenr, $remain) = @_; + + return ctx_block_get($linenr, $remain, 0, '{', '}', 0); +} +sub ctx_statement_level { + my ($linenr, $remain, $off) = @_; + + return ctx_block_get($linenr, $remain, 0, '(', ')', $off); +} + +sub ctx_locate_comment { + my ($first_line, $end_line) = @_; + + # Catch a comment on the end of the line itself. + my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); + return $current_comment if (defined $current_comment); + + # Look through the context and try and figure out if there is a + # comment. + my $in_comment = 0; + $current_comment = ''; + for (my $linenr = $first_line; $linenr < $end_line; $linenr++) { + my $line = $rawlines[$linenr - 1]; + #warn " $line\n"; + if ($linenr == $first_line and $line =~ m@^.\s*\*@) { + $in_comment = 1; + } + if ($line =~ m@/\*@) { + $in_comment = 1; + } + if (!$in_comment && $current_comment ne '') { + $current_comment = ''; + } + $current_comment .= $line . "\n" if ($in_comment); + if ($line =~ m@\*/@) { + $in_comment = 0; + } + } + + chomp($current_comment); + return($current_comment); +} +sub ctx_has_comment { + my ($first_line, $end_line) = @_; + my $cmt = ctx_locate_comment($first_line, $end_line); + + ##print "LINE: $rawlines[$end_line - 1 ]\n"; + ##print "CMMT: $cmt\n"; + + return ($cmt ne ''); +} + +sub raw_line { + my ($linenr, $cnt) = @_; + + my $offset = $linenr - 1; + $cnt++; + + my $line; + while ($cnt) { + $line = $rawlines[$offset++]; + next if (defined($line) && $line =~ /^-/); + $cnt--; + } + + return $line; +} + +sub get_stat_real { + my ($linenr, $lc) = @_; + + my $stat_real = raw_line($linenr, 0); + for (my $count = $linenr + 1; $count <= $lc; $count++) { + $stat_real = $stat_real . "\n" . raw_line($count, 0); + } + + return $stat_real; +} + +sub get_stat_here { + my ($linenr, $cnt, $here) = @_; + + my $herectx = $here . "\n"; + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + + return $herectx; +} + +sub cat_vet { + my ($vet) = @_; + my ($res, $coded); + + $res = ''; + while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) { + $res .= $1; + if ($2 ne '') { + $coded = sprintf("^%c", unpack('C', $2) + 64); + $res .= $coded; + } + } + $res =~ s/$/\$/; + + return $res; +} + +my $av_preprocessor = 0; +my $av_pending; +my @av_paren_type; +my $av_pend_colon; + +sub annotate_reset { + $av_preprocessor = 0; + $av_pending = '_'; + @av_paren_type = ('E'); + $av_pend_colon = 'O'; +} + +sub annotate_values { + my ($stream, $type) = @_; + + my $res; + my $var = '_' x length($stream); + my $cur = $stream; + + print "$stream\n" if ($dbg_values > 1); + + while (length($cur)) { + @av_paren_type = ('E') if ($#av_paren_type < 0); + print " <" . join('', @av_paren_type) . + "> <$type> <$av_pending>" if ($dbg_values > 1); + if ($cur =~ /^(\s+)/o) { + print "WS($1)\n" if ($dbg_values > 1); + if ($1 =~ /\n/ && $av_preprocessor) { + $type = pop(@av_paren_type); + $av_preprocessor = 0; + } + + } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') { + print "CAST($1)\n" if ($dbg_values > 1); + push(@av_paren_type, $type); + $type = 'c'; + + } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) { + print "DECLARE($1)\n" if ($dbg_values > 1); + $type = 'T'; + + } elsif ($cur =~ /^($Modifier)\s*/) { + print "MODIFIER($1)\n" if ($dbg_values > 1); + $type = 'T'; + + } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) { + print "DEFINE($1,$2)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + push(@av_paren_type, $type); + if ($2 ne '') { + $av_pending = 'N'; + } + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) { + print "UNDEF($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + push(@av_paren_type, $type); + + } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) { + print "PRE_START($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + + push(@av_paren_type, $type); + push(@av_paren_type, $type); + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) { + print "PRE_RESTART($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + + push(@av_paren_type, $av_paren_type[$#av_paren_type]); + + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:endif))/o) { + print "PRE_END($1)\n" if ($dbg_values > 1); + + $av_preprocessor = 1; + + # Assume all arms of the conditional end as this + # one does, and continue as if the #endif was not here. + pop(@av_paren_type); + push(@av_paren_type, $type); + $type = 'E'; + + } elsif ($cur =~ /^(\\\n)/o) { + print "PRECONT($1)\n" if ($dbg_values > 1); + + } elsif ($cur =~ /^(__attribute__)\s*\(?/o) { + print "ATTR($1)\n" if ($dbg_values > 1); + $av_pending = $type; + $type = 'N'; + + } elsif ($cur =~ /^(sizeof)\s*(\()?/o) { + print "SIZEOF($1)\n" if ($dbg_values > 1); + if (defined $2) { + $av_pending = 'V'; + } + $type = 'N'; + + } elsif ($cur =~ /^(if|while|for)\b/o) { + print "COND($1)\n" if ($dbg_values > 1); + $av_pending = 'E'; + $type = 'N'; + + } elsif ($cur =~/^(case)/o) { + print "CASE($1)\n" if ($dbg_values > 1); + $av_pend_colon = 'C'; + $type = 'N'; + + } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) { + print "KEYWORD($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(\()/o) { + print "PAREN('$1')\n" if ($dbg_values > 1); + push(@av_paren_type, $av_pending); + $av_pending = '_'; + $type = 'N'; + + } elsif ($cur =~ /^(\))/o) { + my $new_type = pop(@av_paren_type); + if ($new_type ne '_') { + $type = $new_type; + print "PAREN('$1') -> $type\n" + if ($dbg_values > 1); + } else { + print "PAREN('$1')\n" if ($dbg_values > 1); + } + + } elsif ($cur =~ /^($Ident)\s*\(/o) { + print "FUNC($1)\n" if ($dbg_values > 1); + $type = 'V'; + $av_pending = 'V'; + + } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) { + if (defined $2 && $type eq 'C' || $type eq 'T') { + $av_pend_colon = 'B'; + } elsif ($type eq 'E') { + $av_pend_colon = 'L'; + } + print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1); + $type = 'V'; + + } elsif ($cur =~ /^($Ident|$Constant)/o) { + print "IDENT($1)\n" if ($dbg_values > 1); + $type = 'V'; + + } elsif ($cur =~ /^($Assignment)/o) { + print "ASSIGN($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~/^(;|{|})/) { + print "END($1)\n" if ($dbg_values > 1); + $type = 'E'; + $av_pend_colon = 'O'; + + } elsif ($cur =~/^(,)/) { + print "COMMA($1)\n" if ($dbg_values > 1); + $type = 'C'; + + } elsif ($cur =~ /^(\?)/o) { + print "QUESTION($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(:)/o) { + print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1); + + substr($var, length($res), 1, $av_pend_colon); + if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') { + $type = 'E'; + } else { + $type = 'N'; + } + $av_pend_colon = 'O'; + + } elsif ($cur =~ /^(\[)/o) { + print "CLOSE($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) { + my $variant; + + print "OPV($1)\n" if ($dbg_values > 1); + if ($type eq 'V') { + $variant = 'B'; + } else { + $variant = 'U'; + } + + substr($var, length($res), 1, $variant); + $type = 'N'; + + } elsif ($cur =~ /^($Operators)/o) { + print "OP($1)\n" if ($dbg_values > 1); + if ($1 ne '++' && $1 ne '--') { + $type = 'N'; + } + + } elsif ($cur =~ /(^.)/o) { + print "C($1)\n" if ($dbg_values > 1); + } + if (defined $1) { + $cur = substr($cur, length($1)); + $res .= $type x length($1); + } + } + + return ($res, $var); +} + +sub possible { + my ($possible, $line) = @_; + my $notPermitted = qr{(?: + ^(?: + $Modifier| + $Storage| + $Type| + DEFINE_\S+ + )$| + ^(?: + goto| + return| + case| + else| + asm|__asm__| + do| + \#| + \#\#| + )(?:\s|$)| + ^(?:typedef|struct|enum)\b + )}x; + warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2); + if ($possible !~ $notPermitted) { + # Check for modifiers. + $possible =~ s/\s*$Storage\s*//g; + $possible =~ s/\s*$Sparse\s*//g; + if ($possible =~ /^\s*$/) { + + } elsif ($possible =~ /\s/) { + $possible =~ s/\s*$Type\s*//g; + for my $modifier (split(' ', $possible)) { + if ($modifier !~ $notPermitted) { + warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible); + push(@modifierListFile, $modifier); + } + } + + } else { + warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible); + push(@typeListFile, $possible); + } + build_types(); + } else { + warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1); + } +} + +my $prefix = ''; + +sub show_type { + my ($type) = @_; + + $type =~ tr/[a-z]/[A-Z]/; + + return defined $use_type{$type} if (scalar keys %use_type > 0); + + return !defined $ignore_type{$type}; +} + +sub report { + my ($level, $type, $msg) = @_; + + if (!show_type($type) || + (defined $tst_only && $msg !~ /\Q$tst_only\E/)) { + return 0; + } + my $output = ''; + if ($color) { + if ($level eq 'ERROR') { + $output .= RED; + } elsif ($level eq 'WARNING') { + $output .= YELLOW; + } else { + $output .= GREEN; + } + } + $output .= $prefix . $level . ':'; + if ($show_types) { + $output .= BLUE if ($color); + $output .= "$type:"; + } + $output .= RESET if ($color); + $output .= ' ' . $msg . "\n"; + + if ($showfile) { + my @lines = split("\n", $output, -1); + splice(@lines, 1, 1); + $output = join("\n", @lines); + } + $output = (split('\n', $output))[0] . "\n" if ($terse); + + push(our @report, $output); + + return 1; +} + +sub report_dump { + our @report; +} + +sub fixup_current_range { + my ($lineRef, $offset, $length) = @_; + + if ($$lineRef =~ /^\@\@ -\d+,\d+ \+(\d+),(\d+) \@\@/) { + my $o = $1; + my $l = $2; + my $no = $o + $offset; + my $nl = $l + $length; + $$lineRef =~ s/\+$o,$l \@\@/\+$no,$nl \@\@/; + } +} + +sub fix_inserted_deleted_lines { + my ($linesRef, $insertedRef, $deletedRef) = @_; + + my $range_last_linenr = 0; + my $delta_offset = 0; + + my $old_linenr = 0; + my $new_linenr = 0; + + my $next_insert = 0; + my $next_delete = 0; + + my @lines = (); + + my $inserted = @{$insertedRef}[$next_insert++]; + my $deleted = @{$deletedRef}[$next_delete++]; + + foreach my $old_line (@{$linesRef}) { + my $save_line = 1; + my $line = $old_line; #don't modify the array + if ($line =~ /^(?:\+\+\+|\-\-\-)\s+\S+/) { #new filename + $delta_offset = 0; + } elsif ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@/) { #new hunk + $range_last_linenr = $new_linenr; + fixup_current_range(\$line, $delta_offset, 0); + } + + while (defined($deleted) && ${$deleted}{'LINENR'} == $old_linenr) { + $deleted = @{$deletedRef}[$next_delete++]; + $save_line = 0; + fixup_current_range(\$lines[$range_last_linenr], $delta_offset--, -1); + } + + while (defined($inserted) && ${$inserted}{'LINENR'} == $old_linenr) { + push(@lines, ${$inserted}{'LINE'}); + $inserted = @{$insertedRef}[$next_insert++]; + $new_linenr++; + fixup_current_range(\$lines[$range_last_linenr], $delta_offset++, 1); + } + + if ($save_line) { + push(@lines, $line); + $new_linenr++; + } + + $old_linenr++; + } + + return @lines; +} + +sub fix_insert_line { + my ($linenr, $line) = @_; + + my $inserted = { + LINENR => $linenr, + LINE => $line, + }; + push(@fixed_inserted, $inserted); +} + +sub fix_delete_line { + my ($linenr, $line) = @_; + + my $deleted = { + LINENR => $linenr, + LINE => $line, + }; + + push(@fixed_deleted, $deleted); +} + +sub ERROR { + my ($type, $msg) = @_; + + if (report("ERROR", $type, $msg)) { + our $clean = 0; + our $cnt_error++; + return 1; + } + return 0; +} +sub WARN { + my ($type, $msg) = @_; + + if (report("WARNING", $type, $msg)) { + our $clean = 0; + our $cnt_warn++; + return 1; + } + return 0; +} +sub CHK { + my ($type, $msg) = @_; + + if ($check && report("CHECK", $type, $msg)) { + our $clean = 0; + our $cnt_chk++; + return 1; + } + return 0; +} + +sub check_absolute_file { + my ($absolute, $herecurr) = @_; + my $file = $absolute; + + ##print "absolute<$absolute>\n"; + + # See if any suffix of this path is a path within the tree. + while ($file =~ s@^[^/]*/@@) { + if (-f "$root/$file") { + ##print "file<$file>\n"; + last; + } + } + if (! -f _) { + return 0; + } + + # It is, so see if the prefix is acceptable. + my $prefix = $absolute; + substr($prefix, -length($file)) = ''; + + ##print "prefix<$prefix>\n"; + if ($prefix ne ".../") { + WARN("USE_RELATIVE_PATH", + "use relative pathname instead of absolute in changelog text\n" . $herecurr); + } +} + +sub trim { + my ($string) = @_; + + $string =~ s/^\s+|\s+$//g; + + return $string; +} + +sub ltrim { + my ($string) = @_; + + $string =~ s/^\s+//; + + return $string; +} + +sub rtrim { + my ($string) = @_; + + $string =~ s/\s+$//; + + return $string; +} + +sub string_find_replace { + my ($string, $find, $replace) = @_; + + $string =~ s/$find/$replace/g; + + return $string; +} + +sub tabify { + my ($leading) = @_; + + my $source_indent = 8; + my $max_spaces_before_tab = $source_indent - 1; + my $spaces_to_tab = " " x $source_indent; + + #convert leading spaces to tabs + 1 while $leading =~ s@^([\t]*)$spaces_to_tab@$1\t@g; + #Remove spaces before a tab + 1 while $leading =~ s@^([\t]*)( {1,$max_spaces_before_tab})\t@$1\t@g; + + return "$leading"; +} + +sub pos_last_openparen { + my ($line) = @_; + + my $pos = 0; + + my $opens = $line =~ tr/\(/\(/; + my $closes = $line =~ tr/\)/\)/; + + my $last_openparen = 0; + + if (($opens == 0) || ($closes >= $opens)) { + return -1; + } + + my $len = length($line); + + for ($pos = 0; $pos < $len; $pos++) { + my $string = substr($line, $pos); + if ($string =~ /^($FuncArg|$balanced_parens)/) { + $pos += length($1) - 1; + } elsif (substr($line, $pos, 1) eq '(') { + $last_openparen = $pos; + } elsif (index($string, '(') == -1) { + last; + } + } + + return length(expand_tabs(substr($line, 0, $last_openparen))) + 1; +} + +sub process { + my $filename = shift; + + my $linenr=0; + my $prevline=""; + my $prevrawline=""; + my $stashline=""; + my $stashrawline=""; + + my $length; + my $indent; + my $previndent=0; + my $stashindent=0; + + our $clean = 1; + my $signoff = 0; + my $author = ''; + my $authorsignoff = 0; + my $is_patch = 0; + my $is_binding_patch = -1; + my $in_header_lines = $file ? 0 : 1; + my $in_commit_log = 0; #Scanning lines before patch + my $has_commit_log = 0; #Encountered lines before patch + my $commit_log_lines = 0; #Number of commit log lines + my $commit_log_possible_stack_dump = 0; + my $commit_log_long_line = 0; + my $commit_log_has_diff = 0; + my $reported_maintainer_file = 0; + my $reported_abi_update = 0; + my $last_abi_file = ''; + my $non_utf8_charset = 0; + + my $last_blank_line = 0; + my $last_coalesced_string_linenr = -1; + + our @report = (); + our $cnt_lines = 0; + our $cnt_error = 0; + our $cnt_warn = 0; + our $cnt_chk = 0; + + # Trace the real file/line as we go. + my $realfile = ''; + my $realline = 0; + my $realcnt = 0; + my $here = ''; + my $context_function; #undef'd unless there's a known function + my $in_comment = 0; + my $comment_edge = 0; + my $first_line = 0; + my $p1_prefix = ''; + + my $prev_values = 'E'; + + # suppression flags + my %suppress_ifbraces; + my %suppress_whiletrailers; + my %suppress_export; + my $suppress_statement = 0; + + my %signatures = (); + + # Pre-scan the patch sanitizing the lines. + # Pre-scan the patch looking for any __setup documentation. + # + my @setup_docs = (); + my $setup_docs = 0; + + my $camelcase_file_seeded = 0; + + my $checklicenseline = 1; + + sanitise_line_reset(); + my $line; + foreach my $rawline (@rawlines) { + $linenr++; + $line = $rawline; + + push(@fixed, $rawline) if ($fix); + + if ($rawline=~/^\+\+\+\s+(\S+)/) { + $setup_docs = 0; + if ($1 =~ m@Documentation/admin-guide/kernel-parameters.rst$@) { + $setup_docs = 1; + } + #next; + } + if ($rawline =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { + $realline=$1-1; + if (defined $2) { + $realcnt=$3+1; + } else { + $realcnt=1+1; + } + $in_comment = 0; + + # Guestimate if this is a continuing comment. Run + # the context looking for a comment "edge". If this + # edge is a close comment then we must be in a comment + # at context start. + my $edge; + my $cnt = $realcnt; + for (my $ln = $linenr + 1; $cnt > 0; $ln++) { + next if (defined $rawlines[$ln - 1] && + $rawlines[$ln - 1] =~ /^-/); + $cnt--; + #print "RAW<$rawlines[$ln - 1]>\n"; + last if (!defined $rawlines[$ln - 1]); + if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ && + $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) { + ($edge) = $1; + last; + } + } + if (defined $edge && $edge eq '*/') { + $in_comment = 1; + } + + # Guestimate if this is a continuing comment. If this + # is the start of a diff block and this line starts + # ' *' then it is very likely a comment. + if (!defined $edge && + $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@) + { + $in_comment = 1; + } + + ##print "COMMENT:$in_comment edge<$edge> $rawline\n"; + sanitise_line_reset($in_comment); + + } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) { + # Standardise the strings and chars within the input to + # simplify matching -- only bother with positive lines. + $line = sanitise_line($rawline); + } + + # Check if ABI is being updated. If so, there's probably no need to + # emit the "does ABI need updating?" message on file add/move/delete + if ($SOF && + ($line =~ /\+#define SOF_ABI_MAJOR*/ || + $line =~ /\+#define SOF_ABI_MINOR*/ || + $line =~ /\+#define SOF_ABI_PATCH*/)) { + $reported_abi_update = 1; + } + + push(@lines, $line); + + if ($realcnt > 1) { + $realcnt-- if ($line =~ /^(?:\+| |$)/); + } else { + $realcnt = 0; + } + + #print "==>$rawline\n"; + #print "-->$line\n"; + + if ($setup_docs && $line =~ /^\+/) { + push(@setup_docs, $line); + } + } + + $prefix = ''; + + $realcnt = 0; + $linenr = 0; + $fixlinenr = -1; + foreach my $line (@lines) { + $linenr++; + $fixlinenr++; + my $sline = $line; #copy of $line + $sline =~ s/$;/ /g; #with comments as spaces + + my $rawline = $rawlines[$linenr - 1]; + +# check if it's a mode change, rename or start of a patch + if (!$in_commit_log && + ($line =~ /^ mode change [0-7]+ => [0-7]+ \S+\s*$/ || + ($line =~ /^rename (?:from|to) \S+\s*$/ || + $line =~ /^diff --git a\/[\w\/\.\_\-]+ b\/\S+\s*$/))) { + $is_patch = 1; + } + +#extract the line range in the file after the patch is applied + if (!$in_commit_log && + $line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) { + my $context = $4; + $is_patch = 1; + $first_line = $linenr + 1; + $realline=$1-1; + if (defined $2) { + $realcnt=$3+1; + } else { + $realcnt=1+1; + } + annotate_reset(); + $prev_values = 'E'; + + %suppress_ifbraces = (); + %suppress_whiletrailers = (); + %suppress_export = (); + $suppress_statement = 0; + if ($context =~ /\b(\w+)\s*\(/) { + $context_function = $1; + } else { + undef $context_function; + } + next; + +# track the line number as we move through the hunk, note that +# new versions of GNU diff omit the leading space on completely +# blank context lines so we need to count that too. + } elsif ($line =~ /^( |\+|$)/) { + $realline++; + $realcnt-- if ($realcnt != 0); + + # Measure the line length and indent. + ($length, $indent) = line_stats($rawline); + + # Track the previous line. + ($prevline, $stashline) = ($stashline, $line); + ($previndent, $stashindent) = ($stashindent, $indent); + ($prevrawline, $stashrawline) = ($stashrawline, $rawline); + + #warn "line<$line>\n"; + + } elsif ($realcnt == 1) { + $realcnt--; + } + + my $hunk_line = ($realcnt != 0); + + $here = "#$linenr: " if (!$file); + $here = "#$realline: " if ($file); + + my $found_file = 0; + # extract the filename as it passes + if ($line =~ /^diff --git.*?(\S+)$/) { + $realfile = $1; + $realfile =~ s@^([^/]*)/@@ if (!$file); + $in_commit_log = 0; + $found_file = 1; + } elsif ($line =~ /^\+\+\+\s+(\S+)/) { + $realfile = $1; + $realfile =~ s@^([^/]*)/@@ if (!$file); + $in_commit_log = 0; + + $p1_prefix = $1; + if (!$file && $tree && $p1_prefix ne '' && + -e "$root/$p1_prefix") { + WARN("PATCH_PREFIX", + "patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); + } + + if ($realfile =~ m@^include/asm/@) { + ERROR("MODIFIED_INCLUDE_ASM", + "do not modify files in include/asm, change architecture specific files in include/asm-\n" . "$here$rawline\n"); + } + $found_file = 1; + } + +#make up the handle for any error we report on this line + if ($showfile) { + $prefix = "$realfile:$realline: " + } elsif ($emacs) { + if ($file) { + $prefix = "$filename:$realline: "; + } else { + $prefix = "$filename:$linenr: "; + } + } + + if ($found_file) { + if (is_maintained_obsolete($realfile)) { + WARN("OBSOLETE", + "$realfile is marked as 'obsolete' in the MAINTAINERS hierarchy. No unnecessary modifications please.\n"); + } + if ($realfile =~ m@^(?:drivers/net/|net/|drivers/staging/)@) { + $check = 1; + } else { + $check = $check_orig; + } + $checklicenseline = 1; + + if ($realfile !~ /^MAINTAINERS/) { + my $last_binding_patch = $is_binding_patch; + + $is_binding_patch = () = $realfile =~ m@^(?:Documentation/devicetree/|include/dt-bindings/)@; + + if (($last_binding_patch != -1) && + ($last_binding_patch ^ $is_binding_patch)) { + WARN("DT_SPLIT_BINDING_PATCH", + "DT binding docs and includes should be a separate patch. See: Documentation/devicetree/bindings/submitting-patches.txt\n"); + } + } + + next; + } + + $here .= "FILE: $realfile:$realline:" if ($realcnt != 0); + + my $hereline = "$here\n$rawline\n"; + my $herecurr = "$here\n$rawline\n"; + my $hereprev = "$here\n$prevrawline\n$rawline\n"; + + $cnt_lines++ if ($realcnt != 0); + +# Verify the existence of a commit log if appropriate +# 2 is used because a $signature is counted in $commit_log_lines + if ($in_commit_log) { + if ($line !~ /^\s*$/) { + $commit_log_lines++; #could be a $signature + } + } elsif ($has_commit_log && $commit_log_lines < 2) { + WARN("COMMIT_MESSAGE", + "Missing commit description - Add an appropriate one\n"); + $commit_log_lines = 2; #warn only once + } + +# Check if the commit log has what seems like a diff which can confuse patch + if ($in_commit_log && !$commit_log_has_diff && + (($line =~ m@^\s+diff\b.*a/[\w/]+@ && + $line =~ m@^\s+diff\b.*a/([\w/]+)\s+b/$1\b@) || + $line =~ m@^\s*(?:\-\-\-\s+a/|\+\+\+\s+b/)@ || + $line =~ m/^\s*\@\@ \-\d+,\d+ \+\d+,\d+ \@\@/)) { + ERROR("DIFF_IN_COMMIT_MSG", + "Avoid using diff content in the commit message - patch(1) might not work\n" . $herecurr); + $commit_log_has_diff = 1; + } + +# Check for incorrect file permissions + if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { + my $permhere = $here . "FILE: $realfile\n"; + if ($realfile !~ m@scripts/@ && + $realfile !~ /\.(py|pl|awk|sh)$/) { + ERROR("EXECUTE_PERMISSIONS", + "do not set execute permissions for source files\n" . $permhere); + } + } + +# Check the patch for a From: + if (decode("MIME-Header", $line) =~ /^From:\s*(.*)/) { + $author = $1; + $author = encode("utf8", $author) if ($line =~ /=\?utf-8\?/i); + $author =~ s/"//g; + } + +# Check the patch for a signoff: + if ($line =~ /^\s*signed-off-by:/i) { + $signoff++; + $in_commit_log = 0; + if ($author ne '') { + my $l = $line; + $l =~ s/"//g; + if ($l =~ /^\s*signed-off-by:\s*\Q$author\E/i) { + $authorsignoff = 1; + } + } + } + + +# Check if MAINTAINERS is being updated. If so, there's probably no need to +# emit the "does MAINTAINERS need updating?" message on file add/move/delete + if ($line =~ /^\s*MAINTAINERS\s*\|/) { + $reported_maintainer_file = 1; + } + +# Check signature styles + if (!$in_header_lines && + $line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) { + my $space_before = $1; + my $sign_off = $2; + my $space_after = $3; + my $email = $4; + my $ucfirst_sign_off = ucfirst(lc($sign_off)); + + if ($sign_off !~ /$signature_tags/) { + WARN("BAD_SIGN_OFF", + "Non-standard signature: $sign_off\n" . $herecurr); + } + if (defined $space_before && $space_before ne "") { + if (WARN("BAD_SIGN_OFF", + "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = + "$ucfirst_sign_off $email"; + } + } + if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) { + if (WARN("BAD_SIGN_OFF", + "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = + "$ucfirst_sign_off $email"; + } + + } + if (!defined $space_after || $space_after ne " ") { + if (WARN("BAD_SIGN_OFF", + "Use a single space after $ucfirst_sign_off\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = + "$ucfirst_sign_off $email"; + } + } + + my ($email_name, $email_address, $comment) = parse_email($email); + my $suggested_email = format_email(($email_name, $email_address)); + if ($suggested_email eq "") { + ERROR("BAD_SIGN_OFF", + "Unrecognized email address: '$email'\n" . $herecurr); + } else { + my $dequoted = $suggested_email; + $dequoted =~ s/^"//; + $dequoted =~ s/" $comment" ne $email && + "$suggested_email$comment" ne $email) { + WARN("BAD_SIGN_OFF", + "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr); + } + } + +# Check for duplicate signatures + my $sig_nospace = $line; + $sig_nospace =~ s/\s//g; + $sig_nospace = lc($sig_nospace); + if (defined $signatures{$sig_nospace}) { + WARN("BAD_SIGN_OFF", + "Duplicate signature\n" . $herecurr); + } else { + $signatures{$sig_nospace} = 1; + } + +# Check Co-developed-by: immediately followed by Signed-off-by: with same name and email + if ($sign_off =~ /^co-developed-by:$/i) { + if ($email eq $author) { + WARN("BAD_SIGN_OFF", + "Co-developed-by: should not be used to attribute nominal patch author '$author'\n" . "$here\n" . $rawline); + } + if (!defined $lines[$linenr]) { + WARN("BAD_SIGN_OFF", + "Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline); + } elsif ($rawlines[$linenr] !~ /^\s*signed-off-by:\s*(.*)/i) { + WARN("BAD_SIGN_OFF", + "Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]); + } elsif ($1 ne $email) { + WARN("BAD_SIGN_OFF", + "Co-developed-by and Signed-off-by: name/email do not match \n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]); + } + } + } + +# Check email subject for common tools that don't need to be mentioned + if ($in_header_lines && + $line =~ /^Subject:.*\b(?:checkpatch|sparse|smatch)\b[^:]/i) { + WARN("EMAIL_SUBJECT", + "A patch subject line should describe the change not the tool that found it\n" . $herecurr); + } + +# Check for unwanted Gerrit info + if ($in_commit_log && $line =~ /^\s*change-id:/i) { + ERROR("GERRIT_CHANGE_ID", + "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr); + } + +# Check if the commit log is in a possible stack dump + if ($in_commit_log && !$commit_log_possible_stack_dump && + ($line =~ /^\s*(?:WARNING:|BUG:)/ || + $line =~ /^\s*\[\s*\d+\.\d{6,6}\s*\]/ || + # timestamp + $line =~ /^\s*\[\<[0-9a-fA-F]{8,}\>\]/) || + $line =~ /^(?:\s+\w+:\s+[0-9a-fA-F]+){3,3}/ || + $line =~ /^\s*\#\d+\s*\[[0-9a-fA-F]+\]\s*\w+ at [0-9a-fA-F]+/) { + # stack dump address styles + $commit_log_possible_stack_dump = 1; + } + +# Check for line lengths > 75 in commit log, warn once + if ($in_commit_log && !$commit_log_long_line && + length($line) > 75 && + !($line =~ /^\s*[a-zA-Z0-9_\/\.]+\s+\|\s+\d+/ || + # file delta changes + $line =~ /^\s*(?:[\w\.\-]+\/)++[\w\.\-]+:/ || + # filename then : + $line =~ /^\s*(?:Fixes:|Link:)/i || + # A Fixes: or Link: line + $commit_log_possible_stack_dump)) { + WARN("COMMIT_LOG_LONG_LINE", + "Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $herecurr); + $commit_log_long_line = 1; + } + +# Reset possible stack dump if a blank line is found + if ($in_commit_log && $commit_log_possible_stack_dump && + $line =~ /^\s*$/) { + $commit_log_possible_stack_dump = 0; + } + +# Check for git id commit length and improperly formed commit descriptions + if ($in_commit_log && !$commit_log_possible_stack_dump && + $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink):/i && + $line !~ /^This reverts commit [0-9a-f]{7,40}/ && + ($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i || + ($line =~ /(?:\s|^)[0-9a-f]{12,40}(?:[\s"'\(\[]|$)/i && + $line !~ /[\<\[][0-9a-f]{12,40}[\>\]]/i && + $line !~ /\bfixes:\s*[0-9a-f]{12,40}/i))) { + my $init_char = "c"; + my $orig_commit = ""; + my $short = 1; + my $long = 0; + my $case = 1; + my $space = 1; + my $hasdesc = 0; + my $hasparens = 0; + my $id = '0123456789ab'; + my $orig_desc = "commit description"; + my $description = ""; + + if ($line =~ /\b(c)ommit\s+([0-9a-f]{5,})\b/i) { + $init_char = $1; + $orig_commit = lc($2); + } elsif ($line =~ /\b([0-9a-f]{12,40})\b/i) { + $orig_commit = lc($1); + } + + $short = 0 if ($line =~ /\bcommit\s+[0-9a-f]{12,40}/i); + $long = 1 if ($line =~ /\bcommit\s+[0-9a-f]{41,}/i); + $space = 0 if ($line =~ /\bcommit [0-9a-f]/i); + $case = 0 if ($line =~ /\b[Cc]ommit\s+[0-9a-f]{5,40}[^A-F]/); + if ($line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("([^"]+)"\)/i) { + $orig_desc = $1; + $hasparens = 1; + } elsif ($line =~ /\bcommit\s+[0-9a-f]{5,}\s*$/i && + defined $rawlines[$linenr] && + $rawlines[$linenr] =~ /^\s*\("([^"]+)"\)/) { + $orig_desc = $1; + $hasparens = 1; + } elsif ($line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("[^"]+$/i && + defined $rawlines[$linenr] && + $rawlines[$linenr] =~ /^\s*[^"]+"\)/) { + $line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("([^"]+)$/i; + $orig_desc = $1; + $rawlines[$linenr] =~ /^\s*([^"]+)"\)/; + $orig_desc .= " " . $1; + $hasparens = 1; + } + + ($id, $description) = git_commit_info($orig_commit, + $id, $orig_desc); + + if (defined($id) && + ($short || $long || $space || $case || ($orig_desc ne $description) || !$hasparens)) { + ERROR("GIT_COMMIT_ID", + "Please use git commit description style 'commit <12+ chars of sha1> (\"\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $herecurr); + } + } + +# Check for added, moved or deleted files + if (!$SOF && + (!$reported_maintainer_file && !$in_commit_log && + ($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ || + $line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ || + ($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ && + (defined($1) || defined($2)))))) { + $is_patch = 1; + $reported_maintainer_file = 1; + WARN("FILE_PATH_CHANGES", + "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); + } + +# Check for wrappage within a valid hunk of the file + if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { + ERROR("CORRUPTED_PATCH", + "patch seems to be corrupt (line wrapped?)\n" . + $herecurr) if (!$emitted_corrupt++); + } + +# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php + if (($realfile =~ /^$/ || $line =~ /^\+/) && + $rawline !~ m/^$UTF8*$/) { + my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/); + + my $blank = copy_spacing($rawline); + my $ptr = substr($blank, 0, length($utf8_prefix)) . "^"; + my $hereptr = "$hereline$ptr\n"; + + CHK("INVALID_UTF8", + "Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr); + } + +# Check if it's the start of a commit log +# (not a header line and we haven't seen the patch filename) + if ($in_header_lines && $realfile =~ /^$/ && + !($rawline =~ /^\s+(?:\S|$)/ || + $rawline =~ /^(?:commit\b|from\b|[\w-]+:)/i)) { + $in_header_lines = 0; + $in_commit_log = 1; + $has_commit_log = 1; + } + +# Check if there is UTF-8 in a commit log when a mail header has explicitly +# declined it, i.e defined some charset where it is missing. + if ($in_header_lines && + $rawline =~ /^Content-Type:.+charset="(.+)".*$/ && + $1 !~ /utf-8/i) { + $non_utf8_charset = 1; + } + + if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ && + $rawline =~ /$NON_ASCII_UTF8/) { + WARN("UTF8_BEFORE_PATCH", + "8-bit UTF-8 used in possible commit log\n" . $herecurr); + } + +# Check for absolute kernel paths in commit message + if ($tree && $in_commit_log) { + while ($line =~ m{(?:^|\s)(/\S*)}g) { + my $file = $1; + + if ($file =~ m{^(.*?)(?::\d+)+:?$} && + check_absolute_file($1, $herecurr)) { + # + } else { + check_absolute_file($file, $herecurr); + } + } + } + +# Check for various typo / spelling mistakes + if (defined($misspellings) && + ($in_commit_log || $line =~ /^(?:\+|Subject:)/i)) { + while ($rawline =~ /(?:^|[^a-z@])($misspellings)(?:\b|$|[^a-z@])/gi) { + my $typo = $1; + my $typo_fix = $spelling_fix{lc($typo)}; + $typo_fix = ucfirst($typo_fix) if ($typo =~ /^[A-Z]/); + $typo_fix = uc($typo_fix) if ($typo =~ /^[A-Z]+$/); + my $msg_level = \&WARN; + $msg_level = \&CHK if ($file); + if (&{$msg_level}("TYPO_SPELLING", + "'$typo' may be misspelled - perhaps '$typo_fix'?\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(^|[^A-Za-z@])($typo)($|[^A-Za-z@])/$1$typo_fix$3/; + } + } + } + +# check for invalid commit id + if ($in_commit_log && $line =~ /(^fixes:|\bcommit)\s+([0-9a-f]{6,40})\b/i) { + my $id; + my $description; + ($id, $description) = git_commit_info($2, undef, undef); + if (!defined($id)) { + WARN("UNKNOWN_COMMIT_ID", + "Unknown commit id '$2', maybe rebased or not pulled?\n" . $herecurr); + } + } + +# ignore non-hunk lines and lines being removed + next if (!$hunk_line || $line =~ /^-/); + +#trailing whitespace + if ($line =~ /^\+.*\015/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + if (ERROR("DOS_LINE_ENDINGS", + "DOS line endings\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/[\s\015]+$//; + } + } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + if (ERROR("TRAILING_WHITESPACE", + "trailing whitespace\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/\s+$//; + } + + $rpt_cleaners = 1; + } + +# Check for FSF mailing addresses. + if ($rawline =~ /\bwrite to the Free/i || + $rawline =~ /\b675\s+Mass\s+Ave/i || + $rawline =~ /\b59\s+Temple\s+Pl/i || + $rawline =~ /\b51\s+Franklin\s+St/i) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + my $msg_level = \&ERROR; + $msg_level = \&CHK if ($file); + &{$msg_level}("FSF_MAILING_ADDRESS", + "Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.\n" . $herevet) + } + +# check for Kconfig help text having a real description +# Only applies when adding the entry originally, after that we do not have +# sufficient context to determine whether it is indeed long enough. + if ($realfile =~ /Kconfig/ && + # 'choice' is usually the last thing on the line (though + # Kconfig supports named choices), so use a word boundary + # (\b) rather than a whitespace character (\s) + $line =~ /^\+\s*(?:config|menuconfig|choice)\b/) { + my $length = 0; + my $cnt = $realcnt; + my $ln = $linenr + 1; + my $f; + my $is_start = 0; + my $is_end = 0; + for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) { + $f = $lines[$ln - 1]; + $cnt-- if ($lines[$ln - 1] !~ /^-/); + $is_end = $lines[$ln - 1] =~ /^\+/; + + next if ($f =~ /^-/); + last if (!$file && $f =~ /^\@\@/); + + if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { + $is_start = 1; + } elsif ($lines[$ln - 1] =~ /^\+\s*(?:help|---help---)\s*$/) { + if ($lines[$ln - 1] =~ "---help---") { + WARN("CONFIG_DESCRIPTION", + "prefer 'help' over '---help---' for new help texts\n" . $herecurr); + } + $length = -1; + } + + $f =~ s/^.//; + $f =~ s/#.*//; + $f =~ s/^\s+//; + next if ($f =~ /^$/); + + # This only checks context lines in the patch + # and so hopefully shouldn't trigger false + # positives, even though some of these are + # common words in help texts + if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice| + if|endif|menu|endmenu|source)\b/x) { + $is_end = 1; + last; + } + $length++; + } + if ($is_start && $is_end && $length < $min_conf_desc_length) { + WARN("CONFIG_DESCRIPTION", + "please write a paragraph that describes the config symbol fully\n" . $herecurr); + } + #print "is_start<$is_start> is_end<$is_end> length<$length>\n"; + } + +# check for MAINTAINERS entries that don't have the right form + if ($realfile =~ /^MAINTAINERS$/ && + $rawline =~ /^\+[A-Z]:/ && + $rawline !~ /^\+[A-Z]:\t\S/) { + if (WARN("MAINTAINERS_STYLE", + "MAINTAINERS entries use one tab after TYPE:\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/^(\+[A-Z]):\s*/$1:\t/; + } + } + +# discourage the use of boolean for type definition attributes of Kconfig options + if ($realfile =~ /Kconfig/ && + $line =~ /^\+\s*\bboolean\b/) { + WARN("CONFIG_TYPE_BOOLEAN", + "Use of boolean is deprecated, please use bool instead.\n" . $herecurr); + } + + if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) && + ($line =~ /\+(EXTRA_[A-Z]+FLAGS).*/)) { + my $flag = $1; + my $replacement = { + 'EXTRA_AFLAGS' => 'asflags-y', + 'EXTRA_CFLAGS' => 'ccflags-y', + 'EXTRA_CPPFLAGS' => 'cppflags-y', + 'EXTRA_LDFLAGS' => 'ldflags-y', + }; + + WARN("DEPRECATED_VARIABLE", + "Use of $flag is deprecated, please use \`$replacement->{$flag} instead.\n" . $herecurr) if ($replacement->{$flag}); + } + +# check for DT compatible documentation + if (defined $root && + (($realfile =~ /\.dtsi?$/ && $line =~ /^\+\s*compatible\s*=\s*\"/) || + ($realfile =~ /\.[ch]$/ && $line =~ /^\+.*\.compatible\s*=\s*\"/))) { + + my @compats = $rawline =~ /\"([a-zA-Z0-9\-\,\.\+_]+)\"/g; + + my $dt_path = $root . "/Documentation/devicetree/bindings/"; + my $vp_file = $dt_path . "vendor-prefixes.yaml"; + + foreach my $compat (@compats) { + my $compat2 = $compat; + $compat2 =~ s/\,[a-zA-Z0-9]*\-/\,<\.\*>\-/; + my $compat3 = $compat; + $compat3 =~ s/\,([a-z]*)[0-9]*\-/\,$1<\.\*>\-/; + `grep -Erq "$compat|$compat2|$compat3" $dt_path`; + if ( $? >> 8 ) { + WARN("UNDOCUMENTED_DT_STRING", + "DT compatible string \"$compat\" appears un-documented -- check $dt_path\n" . $herecurr); + } + + next if $compat !~ /^([a-zA-Z0-9\-]+)\,/; + my $vendor = $1; + `grep -Eq "\\"\\^\Q$vendor\E,\\.\\*\\":" $vp_file`; + if ( $? >> 8 ) { + WARN("UNDOCUMENTED_DT_STRING", + "DT compatible string vendor \"$vendor\" appears un-documented -- check $vp_file\n" . $herecurr); + } + } + } + +# check for using SPDX license tag at beginning of files + if ($realline == $checklicenseline) { + if ($rawline =~ /^[ \+]\s*\#\!\s*\//) { + $checklicenseline = 2; + } elsif ($rawline =~ /^\+/) { + my $comment = ""; + if ($realfile =~ /\.(h|s|S)$/) { + $comment = '/*'; + } elsif ($realfile =~ /\.(c|dts|dtsi)$/) { + $comment = '//'; + } elsif (($checklicenseline == 2) || $realfile =~ /\.(sh|pl|py|awk|tc)$/) { + $comment = '#'; + } elsif ($realfile =~ /\.rst$/) { + $comment = '..'; + } + +# check SPDX comment style for .[chsS] files + if ($realfile =~ /\.[chsS]$/ && + $rawline =~ /SPDX-License-Identifier:/ && + $rawline !~ m@^\+\s*\Q$comment\E\s*@) { + WARN("SPDX_LICENSE_TAG", + "Improper SPDX comment style for '$realfile', please use '$comment' instead\n" . $herecurr); + } + + if ($comment !~ /^$/ && + $rawline !~ m@^\+\Q$comment\E SPDX-License-Identifier: @) { + WARN("SPDX_LICENSE_TAG", + "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr); + } elsif ($rawline =~ /(SPDX-License-Identifier: .*)/) { + my $spdx_license = $1; + if (!is_SPDX_License_valid($spdx_license)) { + WARN("SPDX_LICENSE_TAG", + "'$spdx_license' is not supported in LICENSES/...\n" . $herecurr); + } + } + } + } + +# check we are in a valid source file if not then ignore this hunk + next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/); + +# check for using SPDX-License-Identifier on the wrong line number + if ($realline != $checklicenseline && + $rawline =~ /\bSPDX-License-Identifier:/ && + substr($line, @-, @+ - @-) eq "$;" x (@+ - @-)) { + WARN("SPDX_LICENSE_TAG", + "Misplaced SPDX-License-Identifier tag - use line $checklicenseline instead\n" . $herecurr); + } + +# line length limit (with some exclusions) +# +# There are a few types of lines that may extend beyond $max_line_length: +# logging functions like pr_info that end in a string +# lines with a single string +# #defines that are a single string +# lines with an RFC3986 like URL +# +# There are 3 different line length message types: +# LONG_LINE_COMMENT a comment starts before but extends beyond $max_line_length +# LONG_LINE_STRING a string starts before but extends beyond $max_line_length +# LONG_LINE all other lines longer than $max_line_length +# +# if LONG_LINE is ignored, the other 2 types are also ignored +# + + if ($line =~ /^\+/ && $length > $max_line_length) { + my $msg_type = "LONG_LINE"; + + # Check the allowed long line types first + + # logging functions that end in a string that starts + # before $max_line_length + if ($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(?:KERN_\S+\s*|[^"]*))?($String\s*(?:|,|\)\s*;)\s*)$/ && + length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { + $msg_type = ""; + + # lines with only strings (w/ possible termination) + # #defines with only strings + } elsif ($line =~ /^\+\s*$String\s*(?:\s*|,|\)\s*;)\s*$/ || + $line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) { + $msg_type = ""; + + # More special cases + } elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/ || + $line =~ /^\+\s*(?:\w+)?\s*DEFINE_PER_CPU/) { + $msg_type = ""; + + # URL ($rawline is used in case the URL is in a comment) + } elsif ($rawline =~ /^\+.*\b[a-z][\w\.\+\-]*:\/\/\S+/i) { + $msg_type = ""; + + # Otherwise set the alternate message types + + # a comment starts before $max_line_length + } elsif ($line =~ /($;[\s$;]*)$/ && + length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { + $msg_type = "LONG_LINE_COMMENT" + + # a quoted string starts before $max_line_length + } elsif ($sline =~ /\s*($String(?:\s*(?:\\|,\s*|\)\s*;\s*))?)$/ && + length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { + $msg_type = "LONG_LINE_STRING" + } + + if ($msg_type ne "" && + (show_type("LONG_LINE") || show_type($msg_type))) { + my $msg_level = \&WARN; + $msg_level = \&CHK if ($file); + &{$msg_level}($msg_type, + "line length of $length exceeds $max_line_length columns\n" . $herecurr); + } + } + +# check for adding lines without a newline. + if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) { + WARN("MISSING_EOF_NEWLINE", + "adding a line without newline at end of file\n" . $herecurr); + } + +# check we are in a valid source file C or perl if not then ignore this hunk + next if ($realfile !~ /\.(h|c|pl|dtsi|dts)$/); + +# at the beginning of a line any tabs must come first and anything +# more than 8 must use tabs. + if ($rawline =~ /^\+\s* \t\s*\S/ || + $rawline =~ /^\+\s* \s*/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + $rpt_cleaners = 1; + if (ERROR("CODE_INDENT", + "code indent should use tabs where possible\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e; + } + } + +# check for space before tabs. + if ($rawline =~ /^\+/ && $rawline =~ / \t/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + if (WARN("SPACE_BEFORE_TAB", + "please, no space before tabs\n" . $herevet) && + $fix) { + while ($fixed[$fixlinenr] =~ + s/(^\+.*) {8,8}\t/$1\t\t/) {} + while ($fixed[$fixlinenr] =~ + s/(^\+.*) +\t/$1\t/) {} + } + } + +# check for assignments on the start of a line + if ($sline =~ /^\+\s+($Assignment)[^=]/) { + CHK("ASSIGNMENT_CONTINUATIONS", + "Assignment operator '$1' should be on the previous line\n" . $hereprev); + } + +# check for && or || at the start of a line + if ($rawline =~ /^\+\s*(&&|\|\|)/) { + CHK("LOGICAL_CONTINUATIONS", + "Logical continuations should be on the previous line\n" . $hereprev); + } + +# check indentation starts on a tab stop + if ($perl_version_ok && + $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$)|$Declare\s*$Ident\s*[;=])/) { + my $indent = length($1); + if ($indent % 8) { + if (WARN("TABSTOP", + "Statements should start on a tabstop\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/8)@e; + } + } + } + +# check multi-line statement indentation matches previous line + if ($perl_version_ok && + $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|(?:\*\s*)*$Lval\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) { + $prevline =~ /^\+(\t*)(.*)$/; + my $oldindent = $1; + my $rest = $2; + + my $pos = pos_last_openparen($rest); + if ($pos >= 0) { + $line =~ /^(\+| )([ \t]*)/; + my $newindent = $2; + + my $goodtabindent = $oldindent . + "\t" x ($pos / 8) . + " " x ($pos % 8); + my $goodspaceindent = $oldindent . " " x $pos; + + if ($newindent ne $goodtabindent && + $newindent ne $goodspaceindent) { + + if (CHK("PARENTHESIS_ALIGNMENT", + "Alignment should match open parenthesis\n" . $hereprev) && + $fix && $line =~ /^\+/) { + $fixed[$fixlinenr] =~ + s/^\+[ \t]*/\+$goodtabindent/; + } + } + } + } + +# check for space after cast like "(int) foo" or "(struct foo) bar" +# avoid checking a few false positives: +# "sizeof(<type>)" or "__alignof__(<type>)" +# function pointer declarations like "(*foo)(int) = bar;" +# structure definitions like "(struct foo) { 0 };" +# multiline macros that define functions +# known attributes or the __attribute__ keyword + if ($line =~ /^\+(.*)\(\s*$Type\s*\)([ \t]++)((?![={]|\\$|$Attribute|__attribute__))/ && + (!defined($1) || $1 !~ /\b(?:sizeof|__alignof__)\s*$/)) { + if (CHK("SPACING", + "No space is necessary after a cast\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/(\(\s*$Type\s*\))[ \t]+/$1/; + } + } + +# Block comment styles +# Networking with an initial /* + if ($realfile =~ m@^(drivers/net/|net/)@ && + $prevrawline =~ /^\+[ \t]*\/\*[ \t]*$/ && + $rawline =~ /^\+[ \t]*\*/ && + $realline > 2) { + WARN("NETWORKING_BLOCK_COMMENT_STYLE", + "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev); + } + +# UAPI ABI version + if ($SOF && $realfile ne $last_abi_file && + $realfile =~ m@^(src/include/ipc/|src/include/kernel/|src/include/user/)@ && + $rawline =~ /^\+/ && + !$reported_abi_update) { + $last_abi_file = $realfile; + WARN("ABI update ??", + "Please update ABI in accordance with http://semver.org\n" . $hereprev); + } + +# Block comments use * on subsequent lines + if ($prevline =~ /$;[ \t]*$/ && #ends in comment + $prevrawline =~ /^\+.*?\/\*/ && #starting /* + $prevrawline !~ /\*\/[ \t]*$/ && #no trailing */ + $rawline =~ /^\+/ && #line is new + $rawline !~ /^\+[ \t]*\*/) { #no leading * + WARN("BLOCK_COMMENT_STYLE", + "Block comments use * on subsequent lines\n" . $hereprev); + } + +# Block comments use */ on trailing lines + if ($rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */ + $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/ + $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/ + $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */ + WARN("BLOCK_COMMENT_STYLE", + "Block comments use a trailing */ on a separate line\n" . $herecurr); + } + +# Block comment * alignment + if ($prevline =~ /$;[ \t]*$/ && #ends in comment + $line =~ /^\+[ \t]*$;/ && #leading comment + $rawline =~ /^\+[ \t]*\*/ && #leading * + (($prevrawline =~ /^\+.*?\/\*/ && #leading /* + $prevrawline !~ /\*\/[ \t]*$/) || #no trailing */ + $prevrawline =~ /^\+[ \t]*\*/)) { #leading * + my $oldindent; + $prevrawline =~ m@^\+([ \t]*/?)\*@; + if (defined($1)) { + $oldindent = expand_tabs($1); + } else { + $prevrawline =~ m@^\+(.*/?)\*@; + $oldindent = expand_tabs($1); + } + $rawline =~ m@^\+([ \t]*)\*@; + my $newindent = $1; + $newindent = expand_tabs($newindent); + if (length($oldindent) ne length($newindent)) { + WARN("BLOCK_COMMENT_STYLE", + "Block comments should align the * on each line\n" . $hereprev); + } + } + +# check for missing blank lines after struct/union declarations +# with exceptions for various attributes and macros + if ($prevline =~ /^[\+ ]};?\s*$/ && + $line =~ /^\+/ && + !($line =~ /^\+\s*$/ || + $line =~ /^\+\s*EXPORT_SYMBOL/ || + $line =~ /^\+\s*MODULE_/i || + $line =~ /^\+\s*\#\s*(?:end|elif|else)/ || + $line =~ /^\+[a-z_]*init/ || + $line =~ /^\+\s*(?:static\s+)?[A-Z_]*ATTR/ || + $line =~ /^\+\s*DECLARE/ || + $line =~ /^\+\s*builtin_[\w_]*driver/ || + $line =~ /^\+\s*__setup/)) { + if (CHK("LINE_SPACING", + "Please use a blank line after function/struct/union/enum declarations\n" . $hereprev) && + $fix) { + fix_insert_line($fixlinenr, "\+"); + } + } + +# check for multiple consecutive blank lines + if ($prevline =~ /^[\+ ]\s*$/ && + $line =~ /^\+\s*$/ && + $last_blank_line != ($linenr - 1)) { + if (CHK("LINE_SPACING", + "Please don't use multiple blank lines\n" . $hereprev) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + } + + $last_blank_line = $linenr; + } + +# check for missing blank lines after declarations + if ($sline =~ /^\+\s+\S/ && #Not at char 1 + # actual declarations + ($prevline =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || + # function pointer declarations + $prevline =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ || + # foo bar; where foo is some local typedef or #define + $prevline =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || + # known declaration macros + $prevline =~ /^\+\s+$declaration_macros/) && + # for "else if" which can look like "$Ident $Ident" + !($prevline =~ /^\+\s+$c90_Keywords\b/ || + # other possible extensions of declaration lines + $prevline =~ /(?:$Compare|$Assignment|$Operators)\s*$/ || + # not starting a section or a macro "\" extended line + $prevline =~ /(?:\{\s*|\\)$/) && + # looks like a declaration + !($sline =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || + # function pointer declarations + $sline =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ || + # foo bar; where foo is some local typedef or #define + $sline =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || + # known declaration macros + $sline =~ /^\+\s+$declaration_macros/ || + # start of struct or union or enum + $sline =~ /^\+\s+(?:static\s+)?(?:const\s+)?(?:union|struct|enum|typedef)\b/ || + # start or end of block or continuation of declaration + $sline =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ || + # bitfield continuation + $sline =~ /^\+\s+$Ident\s*:\s*\d+\s*[,;]/ || + # other possible extensions of declaration lines + $sline =~ /^\+\s+\(?\s*(?:$Compare|$Assignment|$Operators)/) && + # indentation of previous and current line are the same + (($prevline =~ /\+(\s+)\S/) && $sline =~ /^\+$1\S/)) { + if (WARN("LINE_SPACING", + "Missing a blank line after declarations\n" . $hereprev) && + $fix) { + fix_insert_line($fixlinenr, "\+"); + } + } + +# check for spaces at the beginning of a line. +# Exceptions: +# 1) within comments +# 2) indented preprocessor commands +# 3) hanging labels + if ($rawline =~ /^\+ / && $line !~ /^\+ *(?:$;|#|$Ident:)/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + if (WARN("LEADING_SPACE", + "please, no spaces at the start of a line\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e; + } + } + +# check we are in a valid C source file if not then ignore this hunk + next if ($realfile !~ /\.(h|c)$/); + +# check for unusual line ending [ or ( + if ($line =~ /^\+.*([\[\(])\s*$/) { + CHK("OPEN_ENDED_LINE", + "Lines should not end with a '$1'\n" . $herecurr); + } + +# check if this appears to be the start function declaration, save the name + if ($sline =~ /^\+\{\s*$/ && + $prevline =~ /^\+(?:(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*)?($Ident)\(/) { + $context_function = $1; + } + +# check if this appears to be the end of function declaration + if ($sline =~ /^\+\}\s*$/) { + undef $context_function; + } + +# check indentation of any line with a bare else +# (but not if it is a multiple line "if (foo) return bar; else return baz;") +# if the previous line is a break or return and is indented 1 tab more... + if ($sline =~ /^\+([\t]+)(?:}[ \t]*)?else(?:[ \t]*{)?\s*$/) { + my $tabs = length($1) + 1; + if ($prevline =~ /^\+\t{$tabs,$tabs}break\b/ || + ($prevline =~ /^\+\t{$tabs,$tabs}return\b/ && + defined $lines[$linenr] && + $lines[$linenr] !~ /^[ \+]\t{$tabs,$tabs}return/)) { + WARN("UNNECESSARY_ELSE", + "else is not generally useful after a break or return\n" . $hereprev); + } + } + +# check indentation of a line with a break; +# if the previous line is a goto or return and is indented the same # of tabs + if ($sline =~ /^\+([\t]+)break\s*;\s*$/) { + my $tabs = $1; + if ($prevline =~ /^\+$tabs(?:goto|return)\b/) { + WARN("UNNECESSARY_BREAK", + "break is not useful after a goto or return\n" . $hereprev); + } + } + +# check for RCS/CVS revision markers + if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) { + WARN("CVS_KEYWORD", + "CVS style keyword markers, these will _not_ be updated\n". $herecurr); + } + +# check for old HOTPLUG __dev<foo> section markings + if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) { + WARN("HOTPLUG_SECTION", + "Using $1 is unnecessary\n" . $herecurr); + } + +# Check for potential 'bare' types + my ($stat, $cond, $line_nr_next, $remain_next, $off_next, + $realline_next); +#print "LINE<$line>\n"; + if ($linenr > $suppress_statement && + $realcnt && $sline =~ /.\s*\S/) { + ($stat, $cond, $line_nr_next, $remain_next, $off_next) = + ctx_statement_block($linenr, $realcnt, 0); + $stat =~ s/\n./\n /g; + $cond =~ s/\n./\n /g; + +#print "linenr<$linenr> <$stat>\n"; + # If this statement has no statement boundaries within + # it there is no point in retrying a statement scan + # until we hit end of it. + my $frag = $stat; $frag =~ s/;+\s*$//; + if ($frag !~ /(?:{|;)/) { +#print "skip<$line_nr_next>\n"; + $suppress_statement = $line_nr_next; + } + + # Find the real next line. + $realline_next = $line_nr_next; + if (defined $realline_next && + (!defined $lines[$realline_next - 1] || + substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) { + $realline_next++; + } + + my $s = $stat; + $s =~ s/{.*$//s; + + # Ignore goto labels. + if ($s =~ /$Ident:\*$/s) { + + # Ignore functions being called + } elsif ($s =~ /^.\s*$Ident\s*\(/s) { + + } elsif ($s =~ /^.\s*else\b/s) { + + # declarations always start with types + } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) { + my $type = $1; + $type =~ s/\s+/ /g; + possible($type, "A:" . $s); + + # definitions in global scope can only start with types + } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) { + possible($1, "B:" . $s); + } + + # any (foo ... *) is a pointer cast, and foo is a type + while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) { + possible($1, "C:" . $s); + } + + # Check for any sort of function declaration. + # int foo(something bar, other baz); + # void (*store_gdt)(x86_descr_ptr *); + if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) { + my ($name_len) = length($1); + + my $ctx = $s; + substr($ctx, 0, $name_len + 1, ''); + $ctx =~ s/\)[^\)]*$//; + + for my $arg (split(/\s*,\s*/, $ctx)) { + if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) { + + possible($1, "D:" . $s); + } + } + } + + } + +# +# Checks which may be anchored in the context. +# + +# Check for switch () and associated case and default +# statements should be at the same indent. + if ($line=~/\bswitch\s*\(.*\)/) { + my $err = ''; + my $sep = ''; + my @ctx = ctx_block_outer($linenr, $realcnt); + shift(@ctx); + for my $ctx (@ctx) { + my ($clen, $cindent) = line_stats($ctx); + if ($ctx =~ /^\+\s*(case\s+|default:)/ && + $indent != $cindent) { + $err .= "$sep$ctx\n"; + $sep = ''; + } else { + $sep = "[...]\n"; + } + } + if ($err ne '') { + ERROR("SWITCH_CASE_INDENT_LEVEL", + "switch and case should be at the same indent\n$hereline$err"); + } + } + +# if/while/etc brace do not go on next line, unless defining a do while loop, +# or if that brace on the next line is for something else + if ($line =~ /(.*)\b((?:if|while|for|switch|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { + my $pre_ctx = "$1$2"; + + my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); + + if ($line =~ /^\+\t{6,}/) { + WARN("DEEP_INDENTATION", + "Too many leading tabs - consider code refactoring\n" . $herecurr); + } + + my $ctx_cnt = $realcnt - $#ctx - 1; + my $ctx = join("\n", @ctx); + + my $ctx_ln = $linenr; + my $ctx_skip = $realcnt; + + while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt && + defined $lines[$ctx_ln - 1] && + $lines[$ctx_ln - 1] =~ /^-/)) { + ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n"; + $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/); + $ctx_ln++; + } + + #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n"; + #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n"; + + if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln - 1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) { + ERROR("OPEN_BRACE", + "that open brace { should be on the previous line\n" . + "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); + } + if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ && + $ctx =~ /\)\s*\;\s*$/ && + defined $lines[$ctx_ln - 1]) + { + my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]); + if ($nindent > $indent) { + WARN("TRAILING_SEMICOLON", + "trailing semicolon indicates no statements, indent implies otherwise\n" . + "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); + } + } + } + +# Check relative indent for conditionals and blocks. + if ($line =~ /\b(?:(?:if|while|for|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|(?:do|else)\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { + ($stat, $cond, $line_nr_next, $remain_next, $off_next) = + ctx_statement_block($linenr, $realcnt, 0) + if (!defined $stat); + my ($s, $c) = ($stat, $cond); + + substr($s, 0, length($c), ''); + + # remove inline comments + $s =~ s/$;/ /g; + $c =~ s/$;/ /g; + + # Find out how long the conditional actually is. + my @newlines = ($c =~ /\n/gs); + my $cond_lines = 1 + $#newlines; + + # Make sure we remove the line prefixes as we have + # none on the first line, and are going to readd them + # where necessary. + $s =~ s/\n./\n/gs; + while ($s =~ /\n\s+\\\n/) { + $cond_lines += $s =~ s/\n\s+\\\n/\n/g; + } + + # We want to check the first line inside the block + # starting at the end of the conditional, so remove: + # 1) any blank line termination + # 2) any opening brace { on end of the line + # 3) any do (...) { + my $continuation = 0; + my $check = 0; + $s =~ s/^.*\bdo\b//; + $s =~ s/^\s*{//; + if ($s =~ s/^\s*\\//) { + $continuation = 1; + } + if ($s =~ s/^\s*?\n//) { + $check = 1; + $cond_lines++; + } + + # Also ignore a loop construct at the end of a + # preprocessor statement. + if (($prevline =~ /^.\s*#\s*define\s/ || + $prevline =~ /\\\s*$/) && $continuation == 0) { + $check = 0; + } + + my $cond_ptr = -1; + $continuation = 0; + while ($cond_ptr != $cond_lines) { + $cond_ptr = $cond_lines; + + # If we see an #else/#elif then the code + # is not linear. + if ($s =~ /^\s*\#\s*(?:else|elif)/) { + $check = 0; + } + + # Ignore: + # 1) blank lines, they should be at 0, + # 2) preprocessor lines, and + # 3) labels. + if ($continuation || + $s =~ /^\s*?\n/ || + $s =~ /^\s*#\s*?/ || + $s =~ /^\s*$Ident\s*:/) { + $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0; + if ($s =~ s/^.*?\n//) { + $cond_lines++; + } + } + } + + my (undef, $sindent) = line_stats("+" . $s); + my $stat_real = raw_line($linenr, $cond_lines); + + # Check if either of these lines are modified, else + # this is not this patch's fault. + if (!defined($stat_real) || + $stat !~ /^\+/ && $stat_real !~ /^\+/) { + $check = 0; + } + if (defined($stat_real) && $cond_lines > 1) { + $stat_real = "[...]\n$stat_real"; + } + + #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; + + if ($check && $s ne '' && + (($sindent % 8) != 0 || + ($sindent < $indent) || + ($sindent == $indent && + ($s !~ /^\s*(?:\}|\{|else\b)/)) || + ($sindent > $indent + 8))) { + WARN("SUSPECT_CODE_INDENT", + "suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); + } + } + + # Track the 'values' across context and added lines. + my $opline = $line; $opline =~ s/^./ /; + my ($curr_values, $curr_vars) = + annotate_values($opline . "\n", $prev_values); + $curr_values = $prev_values . $curr_values; + if ($dbg_values) { + my $outline = $opline; $outline =~ s/\t/ /g; + print "$linenr > .$outline\n"; + print "$linenr > $curr_values\n"; + print "$linenr > $curr_vars\n"; + } + $prev_values = substr($curr_values, -1); + +#ignore lines not being added + next if ($line =~ /^[^\+]/); + +# check for dereferences that span multiple lines + if ($prevline =~ /^\+.*$Lval\s*(?:\.|->)\s*$/ && + $line =~ /^\+\s*(?!\#\s*(?!define\s+|if))\s*$Lval/) { + $prevline =~ /($Lval\s*(?:\.|->))\s*$/; + my $ref = $1; + $line =~ /^.\s*($Lval)/; + $ref .= $1; + $ref =~ s/\s//g; + WARN("MULTILINE_DEREFERENCE", + "Avoid multiple line dereference - prefer '$ref'\n" . $hereprev); + } + +# check for declarations of signed or unsigned without int + while ($line =~ m{\b($Declare)\s*(?!char\b|short\b|int\b|long\b)\s*($Ident)?\s*[=,;\[\)\(]}g) { + my $type = $1; + my $var = $2; + $var = "" if (!defined $var); + if ($type =~ /^(?:(?:$Storage|$Inline|$Attribute)\s+)*((?:un)?signed)((?:\s*\*)*)\s*$/) { + my $sign = $1; + my $pointer = $2; + + $pointer = "" if (!defined $pointer); + + if (WARN("UNSPECIFIED_INT", + "Prefer '" . trim($sign) . " int" . rtrim($pointer) . "' to bare use of '$sign" . rtrim($pointer) . "'\n" . $herecurr) && + $fix) { + my $decl = trim($sign) . " int "; + my $comp_pointer = $pointer; + $comp_pointer =~ s/\s//g; + $decl .= $comp_pointer; + $decl = rtrim($decl) if ($var eq ""); + $fixed[$fixlinenr] =~ s@\b$sign\s*\Q$pointer\E\s*$var\b@$decl$var@; + } + } + } + +# TEST: allow direct testing of the type matcher. + if ($dbg_type) { + if ($line =~ /^.\s*$Declare\s*$/) { + ERROR("TEST_TYPE", + "TEST: is type\n" . $herecurr); + } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) { + ERROR("TEST_NOT_TYPE", + "TEST: is not type ($1 is)\n". $herecurr); + } + next; + } +# TEST: allow direct testing of the attribute matcher. + if ($dbg_attr) { + if ($line =~ /^.\s*$Modifier\s*$/) { + ERROR("TEST_ATTR", + "TEST: is attr\n" . $herecurr); + } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) { + ERROR("TEST_NOT_ATTR", + "TEST: is not attr ($1 is)\n". $herecurr); + } + next; + } + +# check for initialisation to aggregates open brace on the next line + if ($line =~ /^.\s*{/ && + $prevline =~ /(?:^|[^=])=\s*$/) { + if (ERROR("OPEN_BRACE", + "that open brace { should be on the previous line\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + $fixedline =~ s/\s*=\s*$/ = {/; + fix_insert_line($fixlinenr, $fixedline); + $fixedline = $line; + $fixedline =~ s/^(.\s*)\{\s*/$1/; + fix_insert_line($fixlinenr, $fixedline); + } + } + +# +# Checks which are anchored on the added line. +# + +# check for malformed paths in #include statements (uses RAW line) + if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) { + my $path = $1; + if ($path =~ m{//}) { + ERROR("MALFORMED_INCLUDE", + "malformed #include filename\n" . $herecurr); + } + if ($path =~ "^uapi/" && $realfile =~ m@\binclude/uapi/@) { + ERROR("UAPI_INCLUDE", + "No #include in ...include/uapi/... should use a uapi/ path prefix\n" . $herecurr); + } + } + +# no C99 // comments + if ($line =~ m{//}) { + if (ERROR("C99_COMMENTS", + "do not use C99 // comments\n" . $herecurr) && + $fix) { + my $line = $fixed[$fixlinenr]; + if ($line =~ /\/\/(.*)$/) { + my $comment = trim($1); + $fixed[$fixlinenr] =~ s@\/\/(.*)$@/\* $comment \*/@; + } + } + } + # Remove C99 comments. + $line =~ s@//.*@@; + $opline =~ s@//.*@@; + +# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider +# the whole statement. +#print "APW <$lines[$realline_next - 1]>\n"; + if (defined $realline_next && + exists $lines[$realline_next - 1] && + !defined $suppress_export{$realline_next} && + ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ || + $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { + # Handle definitions which produce identifiers with + # a prefix: + # XXX(foo); + # EXPORT_SYMBOL(something_foo); + my $name = $1; + if ($stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ && + $name =~ /^${Ident}_$2/) { +#print "FOO C name<$name>\n"; + $suppress_export{$realline_next} = 1; + + } elsif ($stat !~ /(?: + \n.}\s*$| + ^.DEFINE_$Ident\(\Q$name\E\)| + ^.DECLARE_$Ident\(\Q$name\E\)| + ^.LIST_HEAD\(\Q$name\E\)| + ^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(| + \b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\() + )/x) { +#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n"; + $suppress_export{$realline_next} = 2; + } else { + $suppress_export{$realline_next} = 1; + } + } + if (!defined $suppress_export{$linenr} && + $prevline =~ /^.\s*$/ && + ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ || + $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { +#print "FOO B <$lines[$linenr - 1]>\n"; + $suppress_export{$linenr} = 2; + } + if (defined $suppress_export{$linenr} && + $suppress_export{$linenr} == 2) { + WARN("EXPORT_SYMBOL", + "EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr); + } + +# check for global initialisers. + if ($line =~ /^\+$Type\s*$Ident(?:\s+$Modifier)*\s*=\s*($zero_initializer)\s*;/) { + if (ERROR("GLOBAL_INITIALISERS", + "do not initialise globals to $1\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(^.$Type\s*$Ident(?:\s+$Modifier)*)\s*=\s*$zero_initializer\s*;/$1;/; + } + } +# check for static initialisers. + if ($line =~ /^\+.*\bstatic\s.*=\s*($zero_initializer)\s*;/) { + if (ERROR("INITIALISED_STATIC", + "do not initialise statics to $1\n" . + $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(\bstatic\s.*?)\s*=\s*$zero_initializer\s*;/$1;/; + } + } + +# check for misordered declarations of char/short/int/long with signed/unsigned + while ($sline =~ m{(\b$TypeMisordered\b)}g) { + my $tmp = trim($1); + WARN("MISORDERED_TYPE", + "type '$tmp' should be specified in [[un]signed] [short|int|long|long long] order\n" . $herecurr); + } + +# check for unnecessary <signed> int declarations of short/long/long long + while ($sline =~ m{\b($TypeMisordered(\s*\*)*|$C90_int_types)\b}g) { + my $type = trim($1); + next if ($type !~ /\bint\b/); + next if ($type !~ /\b(?:short|long\s+long|long)\b/); + my $new_type = $type; + $new_type =~ s/\b\s*int\s*\b/ /; + $new_type =~ s/\b\s*(?:un)?signed\b\s*/ /; + $new_type =~ s/^const\s+//; + $new_type = "unsigned $new_type" if ($type =~ /\bunsigned\b/); + $new_type = "const $new_type" if ($type =~ /^const\b/); + $new_type =~ s/\s+/ /g; + $new_type = trim($new_type); + if (WARN("UNNECESSARY_INT", + "Prefer '$new_type' over '$type' as the int is unnecessary\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b\Q$type\E\b/$new_type/; + } + } + +# check for static const char * arrays. + if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) { + WARN("STATIC_CONST_CHAR_ARRAY", + "static const char * array should probably be static const char * const\n" . + $herecurr); + } + +# check for initialized const char arrays that should be static const + if ($line =~ /^\+\s*const\s+(char|unsigned\s+char|_*u8|(?:[us]_)?int8_t)\s+\w+\s*\[\s*(?:\w+\s*)?\]\s*=\s*"/) { + if (WARN("STATIC_CONST_CHAR_ARRAY", + "const array should probably be static const\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(^.\s*)const\b/${1}static const/; + } + } + +# check for static char foo[] = "bar" declarations. + if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) { + WARN("STATIC_CONST_CHAR_ARRAY", + "static char array declaration should probably be static const char\n" . + $herecurr); + } + +# check for const <foo> const where <foo> is not a pointer or array type + if ($sline =~ /\bconst\s+($BasicType)\s+const\b/) { + my $found = $1; + if ($sline =~ /\bconst\s+\Q$found\E\s+const\b\s*\*/) { + WARN("CONST_CONST", + "'const $found const *' should probably be 'const $found * const'\n" . $herecurr); + } elsif ($sline !~ /\bconst\s+\Q$found\E\s+const\s+\w+\s*\[/) { + WARN("CONST_CONST", + "'const $found const' should probably be 'const $found'\n" . $herecurr); + } + } + +# check for non-global char *foo[] = {"bar", ...} declarations. + if ($line =~ /^.\s+(?:static\s+|const\s+)?char\s+\*\s*\w+\s*\[\s*\]\s*=\s*\{/) { + WARN("STATIC_CONST_CHAR_ARRAY", + "char * array declaration might be better as static const\n" . + $herecurr); + } + +# check for sizeof(foo)/sizeof(foo[0]) that could be ARRAY_SIZE(foo) + if ($line =~ m@\bsizeof\s*\(\s*($Lval)\s*\)@) { + my $array = $1; + if ($line =~ m@\b(sizeof\s*\(\s*\Q$array\E\s*\)\s*/\s*sizeof\s*\(\s*\Q$array\E\s*\[\s*0\s*\]\s*\))@) { + my $array_div = $1; + if (WARN("ARRAY_SIZE", + "Prefer ARRAY_SIZE($array)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$array_div\E/ARRAY_SIZE($array)/; + } + } + } + +# check for function declarations without arguments like "int foo()" + if ($line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/) { + if (ERROR("FUNCTION_WITHOUT_ARGS", + "Bad function definition - $1() should probably be $1(void)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(\b($Type)\s+($Ident))\s*\(\s*\)/$2 $3(void)/; + } + } + +# check for new typedefs, only function parameters and sparse annotations +# make sense. + if ($line =~ /\btypedef\s/ && + $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && + $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && + $line !~ /\b$typeTypedefs\b/ && + $line !~ /\b__bitwise\b/) { + WARN("NEW_TYPEDEFS", + "do not add new typedefs\n" . $herecurr); + } + +# * goes on variable not on type + # (char*[ const]) + while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) { + #print "AA<$1>\n"; + my ($ident, $from, $to) = ($1, $2, $2); + + # Should start with a space. + $to =~ s/^(\S)/ $1/; + # Should not end with a space. + $to =~ s/\s+$//; + # '*'s should not have spaces between. + while ($to =~ s/\*\s+\*/\*\*/) { + } + +## print "1: from<$from> to<$to> ident<$ident>\n"; + if ($from ne $to) { + if (ERROR("POINTER_LOCATION", + "\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr) && + $fix) { + my $sub_from = $ident; + my $sub_to = $ident; + $sub_to =~ s/\Q$from\E/$to/; + $fixed[$fixlinenr] =~ + s@\Q$sub_from\E@$sub_to@; + } + } + } + while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) { + #print "BB<$1>\n"; + my ($match, $from, $to, $ident) = ($1, $2, $2, $3); + + # Should start with a space. + $to =~ s/^(\S)/ $1/; + # Should not end with a space. + $to =~ s/\s+$//; + # '*'s should not have spaces between. + while ($to =~ s/\*\s+\*/\*\*/) { + } + # Modifiers should have spaces. + $to =~ s/(\b$Modifier$)/$1 /; + +## print "2: from<$from> to<$to> ident<$ident>\n"; + if ($from ne $to && $ident !~ /^$Modifier$/) { + if (ERROR("POINTER_LOCATION", + "\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr) && + $fix) { + + my $sub_from = $match; + my $sub_to = $match; + $sub_to =~ s/\Q$from\E/$to/; + $fixed[$fixlinenr] =~ + s@\Q$sub_from\E@$sub_to@; + } + } + } + +# avoid BUG() or BUG_ON() + if ($line =~ /\b(?:BUG|BUG_ON)\b/) { + my $msg_level = \&WARN; + $msg_level = \&CHK if ($file); + &{$msg_level}("AVOID_BUG", + "Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr); + } + +# avoid LINUX_VERSION_CODE + if ($line =~ /\bLINUX_VERSION_CODE\b/) { + WARN("LINUX_VERSION_CODE", + "LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr); + } + +# check for uses of printk_ratelimit + if ($line =~ /\bprintk_ratelimit\s*\(/) { + WARN("PRINTK_RATELIMITED", + "Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr); + } + +# printk should use KERN_* levels + if ($line =~ /\bprintk\s*\(\s*(?!KERN_[A-Z]+\b)/) { + WARN("PRINTK_WITHOUT_KERN_LEVEL", + "printk() should include KERN_<LEVEL> facility level\n" . $herecurr); + } + + if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) { + my $orig = $1; + my $level = lc($orig); + $level = "warn" if ($level eq "warning"); + my $level2 = $level; + $level2 = "dbg" if ($level eq "debug"); + WARN("PREFER_PR_LEVEL", + "Prefer [subsystem eg: netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then pr_$level(... to printk(KERN_$orig ...\n" . $herecurr); + } + + if ($line =~ /\bpr_warning\s*\(/) { + if (WARN("PREFER_PR_LEVEL", + "Prefer pr_warn(... to pr_warning(...\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\bpr_warning\b/pr_warn/; + } + } + + if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) { + my $orig = $1; + my $level = lc($orig); + $level = "warn" if ($level eq "warning"); + $level = "dbg" if ($level eq "debug"); + WARN("PREFER_DEV_LEVEL", + "Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr); + } + +# ENOSYS means "bad syscall nr" and nothing else. This will have a small +# number of false positives, but assembly files are not checked, so at +# least the arch entry code will not trigger this warning. + if ($line =~ /\bENOSYS\b/) { + WARN("ENOSYS", + "ENOSYS means 'invalid syscall nr' and nothing else\n" . $herecurr); + } + +# function brace can't be on same line, except for #defines of do while, +# or if closed on same line + if ($perl_version_ok && + $sline =~ /$Type\s*$Ident\s*$balanced_parens\s*\{/ && + $sline !~ /\#\s*define\b.*do\s*\{/ && + $sline !~ /}/) { + if (ERROR("OPEN_BRACE", + "open brace '{' following function definitions go on the next line\n" . $herecurr) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + my $fixed_line = $rawline; + $fixed_line =~ /(^..*$Type\s*$Ident\(.*\)\s*){(.*)$/; + my $line1 = $1; + my $line2 = $2; + fix_insert_line($fixlinenr, ltrim($line1)); + fix_insert_line($fixlinenr, "\+{"); + if ($line2 !~ /^\s*$/) { + fix_insert_line($fixlinenr, "\+\t" . trim($line2)); + } + } + } + +# open braces for enum, union and struct go on the same line. + if ($line =~ /^.\s*{/ && + $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { + if (ERROR("OPEN_BRACE", + "open brace '{' following $1 go on the same line\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = rtrim($prevrawline) . " {"; + fix_insert_line($fixlinenr, $fixedline); + $fixedline = $rawline; + $fixedline =~ s/^(.\s*)\{\s*/$1\t/; + if ($fixedline !~ /^\+\s*$/) { + fix_insert_line($fixlinenr, $fixedline); + } + } + } + +# missing space after union, struct or enum definition + if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident){1,2}[=\{]/) { + if (WARN("SPACING", + "missing space after $1 definition\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(.\s*(?:typedef\s+)?(?:enum|union|struct)(?:\s+$Ident){1,2})([=\{])/$1 $2/; + } + } + +# Function pointer declarations +# check spacing between type, funcptr, and args +# canonical declaration is "type (*funcptr)(args...)" + if ($line =~ /^.\s*($Declare)\((\s*)\*(\s*)($Ident)(\s*)\)(\s*)\(/) { + my $declare = $1; + my $pre_pointer_space = $2; + my $post_pointer_space = $3; + my $funcname = $4; + my $post_funcname_space = $5; + my $pre_args_space = $6; + +# the $Declare variable will capture all spaces after the type +# so check it for a missing trailing missing space but pointer return types +# don't need a space so don't warn for those. + my $post_declare_space = ""; + if ($declare =~ /(\s+)$/) { + $post_declare_space = $1; + $declare = rtrim($declare); + } + if ($declare !~ /\*$/ && $post_declare_space =~ /^$/) { + WARN("SPACING", + "missing space after return type\n" . $herecurr); + $post_declare_space = " "; + } + +# unnecessary space "type (*funcptr)(args...)" +# This test is not currently implemented because these declarations are +# equivalent to +# int foo(int bar, ...) +# and this is form shouldn't/doesn't generate a checkpatch warning. +# +# elsif ($declare =~ /\s{2,}$/) { +# WARN("SPACING", +# "Multiple spaces after return type\n" . $herecurr); +# } + +# unnecessary space "type ( *funcptr)(args...)" + if (defined $pre_pointer_space && + $pre_pointer_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space after function pointer open parenthesis\n" . $herecurr); + } + +# unnecessary space "type (* funcptr)(args...)" + if (defined $post_pointer_space && + $post_pointer_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space before function pointer name\n" . $herecurr); + } + +# unnecessary space "type (*funcptr )(args...)" + if (defined $post_funcname_space && + $post_funcname_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space after function pointer name\n" . $herecurr); + } + +# unnecessary space "type (*funcptr) (args...)" + if (defined $pre_args_space && + $pre_args_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space before function pointer arguments\n" . $herecurr); + } + + if (show_type("SPACING") && $fix) { + $fixed[$fixlinenr] =~ + s/^(.\s*)$Declare\s*\(\s*\*\s*$Ident\s*\)\s*\(/$1 . $declare . $post_declare_space . '(*' . $funcname . ')('/ex; + } + } + +# check for spacing round square brackets; allowed: +# 1. with a type on the left -- int [] a; +# 2. at the beginning of a line for slice initialisers -- [0...10] = 5, +# 3. inside a curly brace -- = { [0...10] = 5 } + while ($line =~ /(.*?\s)\[/g) { + my ($where, $prefix) = ($-[1], $1); + if ($prefix !~ /$Type\s+$/ && + ($where != 0 || $prefix !~ /^.\s+$/) && + $prefix !~ /[{,:]\s+$/) { + if (ERROR("BRACKET_SPACE", + "space prohibited before open square bracket '['\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(\+.*?)\s+\[/$1\[/; + } + } + } + +# check for spaces between functions and their parentheses. + while ($line =~ /($Ident)\s+\(/g) { + my $name = $1; + my $ctx_before = substr($line, 0, $-[1]); + my $ctx = "$ctx_before$name"; + + # Ignore those directives where spaces _are_ permitted. + if ($name =~ /^(?: + if|for|while|switch|return|case| + volatile|__volatile__| + __attribute__|format|__extension__| + asm|__asm__)$/x) + { + # cpp #define statements have non-optional spaces, ie + # if there is a space between the name and the open + # parenthesis it is simply not a parameter group. + } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) { + + # cpp #elif statement condition may start with a ( + } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) { + + # If this whole things ends with a type its most + # likely a typedef for a function. + } elsif ($ctx =~ /$Type$/) { + + } else { + if (WARN("SPACING", + "space prohibited between function name and open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\b$name\s+\(/$name\(/; + } + } + } + +# Check operator spacing. + if (!($line=~/\#\s*include/)) { + my $fixed_line = ""; + my $line_fixed = 0; + + my $ops = qr{ + <<=|>>=|<=|>=|==|!=| + \+=|-=|\*=|\/=|%=|\^=|\|=|&=| + =>|->|<<|>>|<|>|=|!|~| + &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| + \?:|\?|: + }x; + my @elements = split(/($ops|;)/, $opline); + +## print("element count: <" . $#elements . ">\n"); +## foreach my $el (@elements) { +## print("el: <$el>\n"); +## } + + my @fix_elements = (); + my $off = 0; + + foreach my $el (@elements) { + push(@fix_elements, substr($rawline, $off, length($el))); + $off += length($el); + } + + $off = 0; + + my $blank = copy_spacing($opline); + my $last_after = -1; + + for (my $n = 0; $n < $#elements; $n += 2) { + + my $good = $fix_elements[$n] . $fix_elements[$n + 1]; + +## print("n: <$n> good: <$good>\n"); + + $off += length($elements[$n]); + + # Pick up the preceding and succeeding characters. + my $ca = substr($opline, 0, $off); + my $cc = ''; + if (length($opline) >= ($off + length($elements[$n + 1]))) { + $cc = substr($opline, $off + length($elements[$n + 1])); + } + my $cb = "$ca$;$cc"; + + my $a = ''; + $a = 'V' if ($elements[$n] ne ''); + $a = 'W' if ($elements[$n] =~ /\s$/); + $a = 'C' if ($elements[$n] =~ /$;$/); + $a = 'B' if ($elements[$n] =~ /(\[|\()$/); + $a = 'O' if ($elements[$n] eq ''); + $a = 'E' if ($ca =~ /^\s*$/); + + my $op = $elements[$n + 1]; + + my $c = ''; + if (defined $elements[$n + 2]) { + $c = 'V' if ($elements[$n + 2] ne ''); + $c = 'W' if ($elements[$n + 2] =~ /^\s/); + $c = 'C' if ($elements[$n + 2] =~ /^$;/); + $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/); + $c = 'O' if ($elements[$n + 2] eq ''); + $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/); + } else { + $c = 'E'; + } + + my $ctx = "${a}x${c}"; + + my $at = "(ctx:$ctx)"; + + my $ptr = substr($blank, 0, $off) . "^"; + my $hereptr = "$hereline$ptr\n"; + + # Pull out the value of this operator. + my $op_type = substr($curr_values, $off + 1, 1); + + # Get the full operator variant. + my $opv = $op . substr($curr_vars, $off, 1); + + # Ignore operators passed as parameters. + if ($op_type ne 'V' && + $ca =~ /\s$/ && $cc =~ /^\s*[,\)]/) { + +# # Ignore comments +# } elsif ($op =~ /^$;+$/) { + + # ; should have either the end of line or a space or \ after it + } elsif ($op eq ';') { + if ($ctx !~ /.x[WEBC]/ && + $cc !~ /^\\/ && $cc !~ /^;/) { + if (ERROR("SPACING", + "space required after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " "; + $line_fixed = 1; + } + } + + # // is a comment + } elsif ($op eq '//') { + + # : when part of a bitfield + } elsif ($opv eq ':B') { + # skip the bitfield test for now + + # No spaces for: + # -> + } elsif ($op eq '->') { + if ($ctx =~ /Wx.|.xW/) { + if (ERROR("SPACING", + "spaces prohibited around that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } + } + + # , must not have a space before and must have a space on the right. + } elsif ($op eq ',') { + my $rtrim_before = 0; + my $space_after = 0; + if ($ctx =~ /Wx./) { + if (ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr)) { + $line_fixed = 1; + $rtrim_before = 1; + } + } + if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) { + if (ERROR("SPACING", + "space required after that '$op' $at\n" . $hereptr)) { + $line_fixed = 1; + $last_after = $n; + $space_after = 1; + } + } + if ($rtrim_before || $space_after) { + if ($rtrim_before) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + } else { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]); + } + if ($space_after) { + $good .= " "; + } + } + + # '*' as part of a type definition -- reported already. + } elsif ($opv eq '*_') { + #warn "'*' is part of type\n"; + + # unary operators should have a space before and + # none after. May be left adjacent to another + # unary operator, or a cast + } elsif ($op eq '!' || $op eq '~' || + $opv eq '*U' || $opv eq '-U' || + $opv eq '&U' || $opv eq '&&U') { + if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { + if (ERROR("SPACING", + "space required before that '$op' $at\n" . $hereptr)) { + if ($n != $last_after + 2) { + $good = $fix_elements[$n] . " " . ltrim($fix_elements[$n + 1]); + $line_fixed = 1; + } + } + } + if ($op eq '*' && $cc =~/\s*$Modifier\b/) { + # A unary '*' may be const + + } elsif ($ctx =~ /.xW/) { + if (ERROR("SPACING", + "space prohibited after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . rtrim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } + } + + # unary ++ and unary -- are allowed no space on one side. + } elsif ($op eq '++' or $op eq '--') { + if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) { + if (ERROR("SPACING", + "space required one side of that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " "; + $line_fixed = 1; + } + } + if ($ctx =~ /Wx[BE]/ || + ($ctx =~ /Wx./ && $cc =~ /^;/)) { + if (ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + $line_fixed = 1; + } + } + if ($ctx =~ /ExW/) { + if (ERROR("SPACING", + "space prohibited after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } + } + + # << and >> may either have or not have spaces both sides + } elsif ($op eq '<<' or $op eq '>>' or + $op eq '&' or $op eq '^' or $op eq '|' or + $op eq '+' or $op eq '-' or + $op eq '*' or $op eq '/' or + $op eq '%') + { + if ($check) { + if (defined $fix_elements[$n + 2] && $ctx !~ /[EW]x[EW]/) { + if (CHK("SPACING", + "spaces preferred around that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; + $fix_elements[$n + 2] =~ s/^\s+//; + $line_fixed = 1; + } + } elsif (!defined $fix_elements[$n + 2] && $ctx !~ /Wx[OE]/) { + if (CHK("SPACING", + "space preferred before that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]); + $line_fixed = 1; + } + } + } elsif ($ctx =~ /Wx[^WCE]|[^WCE]xW/) { + if (ERROR("SPACING", + "need consistent spacing around '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } + } + + # A colon needs no spaces before when it is + # terminating a case value or a label. + } elsif ($opv eq ':C' || $opv eq ':L') { + if ($ctx =~ /Wx./) { + if (ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + $line_fixed = 1; + } + } + + # All the others need spaces both sides. + } elsif ($ctx !~ /[EWC]x[CWE]/) { + my $ok = 0; + + # Ignore email addresses <foo@bar> + if (($op eq '<' && + $cc =~ /^\S+\@\S+>/) || + ($op eq '>' && + $ca =~ /<\S+\@\S+$/)) + { + $ok = 1; + } + + # for asm volatile statements + # ignore a colon with another + # colon immediately before or after + if (($op eq ':') && + ($ca =~ /:$/ || $cc =~ /^:/)) { + $ok = 1; + } + + # messages are ERROR, but ?: are CHK + if ($ok == 0) { + my $msg_level = \&ERROR; + $msg_level = \&CHK if (($op eq '?:' || $op eq '?' || $op eq ':') && $ctx =~ /VxV/); + + if (&{$msg_level}("SPACING", + "spaces required around that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } + } + } + $off += length($elements[$n + 1]); + +## print("n: <$n> GOOD: <$good>\n"); + + $fixed_line = $fixed_line . $good; + } + + if (($#elements % 2) == 0) { + $fixed_line = $fixed_line . $fix_elements[$#elements]; + } + + if ($fix && $line_fixed && $fixed_line ne $fixed[$fixlinenr]) { + $fixed[$fixlinenr] = $fixed_line; + } + + + } + +# check for whitespace before a non-naked semicolon + if ($line =~ /^\+.*\S\s+;\s*$/) { + if (WARN("SPACING", + "space prohibited before semicolon\n" . $herecurr) && + $fix) { + 1 while $fixed[$fixlinenr] =~ + s/^(\+.*\S)\s+;/$1;/; + } + } + +# check for multiple assignments + if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) { + CHK("MULTIPLE_ASSIGNMENTS", + "multiple assignments should be avoided\n" . $herecurr); + } + +## # check for multiple declarations, allowing for a function declaration +## # continuation. +## if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ && +## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) { +## +## # Remove any bracketed sections to ensure we do not +## # falsly report the parameters of functions. +## my $ln = $line; +## while ($ln =~ s/\([^\(\)]*\)//g) { +## } +## if ($ln =~ /,/) { +## WARN("MULTIPLE_DECLARATION", +## "declaring multiple variables together should be avoided\n" . $herecurr); +## } +## } + +#need space before brace following if, while, etc + if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) || + $line =~ /\b(?:else|do)\{/) { + if (ERROR("SPACING", + "space required before the open brace '{'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/^(\+.*(?:do|else|\)))\{/$1 {/; + } + } + +## # check for blank lines before declarations +## if ($line =~ /^.\t+$Type\s+$Ident(?:\s*=.*)?;/ && +## $prevrawline =~ /^.\s*$/) { +## WARN("SPACING", +## "No blank lines before declarations\n" . $hereprev); +## } +## + +# closing brace should have a space following it when it has anything +# on the line + if ($line =~ /}(?!(?:,|;|\)|\}))\S/) { + if (ERROR("SPACING", + "space required after that close brace '}'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/}((?!(?:,|;|\)))\S)/} $1/; + } + } + +# check spacing on square brackets + if ($line =~ /\[\s/ && $line !~ /\[\s*$/) { + if (ERROR("SPACING", + "space prohibited after that open square bracket '['\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\[\s+/\[/; + } + } + if ($line =~ /\s\]/) { + if (ERROR("SPACING", + "space prohibited before that close square bracket ']'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\s+\]/\]/; + } + } + +# check spacing on parentheses + if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ && + $line !~ /for\s*\(\s+;/) { + if (ERROR("SPACING", + "space prohibited after that open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\(\s+/\(/; + } + } + if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ && + $line !~ /for\s*\(.*;\s+\)/ && + $line !~ /:\s+\)/) { + if (ERROR("SPACING", + "space prohibited before that close parenthesis ')'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\s+\)/\)/; + } + } + +# check unnecessary parentheses around addressof/dereference single $Lvals +# ie: &(foo->bar) should be &foo->bar and *(foo->bar) should be *foo->bar + + while ($line =~ /(?:[^&]&\s*|\*)\(\s*($Ident\s*(?:$Member\s*)+)\s*\)/g) { + my $var = $1; + if (CHK("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses around $var\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\(\s*\Q$var\E\s*\)/$var/; + } + } + +# check for unnecessary parentheses around function pointer uses +# ie: (foo->bar)(); should be foo->bar(); +# but not "if (foo->bar) (" to avoid some false positives + if ($line =~ /(\bif\s*|)(\(\s*$Ident\s*(?:$Member\s*)+\))[ \t]*\(/ && $1 !~ /^if/) { + my $var = $2; + if (CHK("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses around function pointer $var\n" . $herecurr) && + $fix) { + my $var2 = deparenthesize($var); + $var2 =~ s/\s//g; + $fixed[$fixlinenr] =~ s/\Q$var\E/$var2/; + } + } + +# check for unnecessary parentheses around comparisons in if uses +# when !drivers/staging or command-line uses --strict + if (($realfile !~ m@^(?:drivers/staging/)@ || $check_orig) && + $perl_version_ok && defined($stat) && + $stat =~ /(^.\s*if\s*($balanced_parens))/) { + my $if_stat = $1; + my $test = substr($2, 1, -1); + my $herectx; + while ($test =~ /(?:^|[^\w\&\!\~])+\s*\(\s*([\&\!\~]?\s*$Lval\s*(?:$Compare\s*$FuncArg)?)\s*\)/g) { + my $match = $1; + # avoid parentheses around potential macro args + next if ($match =~ /^\s*\w+\s*$/); + if (!defined($herectx)) { + $herectx = $here . "\n"; + my $cnt = statement_rawlines($if_stat); + for (my $n = 0; $n < $cnt; $n++) { + my $rl = raw_line($linenr, $n); + $herectx .= $rl . "\n"; + last if $rl =~ /^[ \+].*\{/; + } + } + CHK("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses around '$match'\n" . $herectx); + } + } + +#goto labels aren't indented, allow a single space however + if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and + !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) { + if (WARN("INDENTED_LABEL", + "labels should not be indented\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(.)\s+/$1/; + } + } + +# return is not a function + if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) { + my $spacing = $1; + if ($perl_version_ok && + $stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/) { + my $value = $1; + $value = deparenthesize($value); + if ($value =~ m/^\s*$FuncArg\s*(?:\?|$)/) { + ERROR("RETURN_PARENTHESES", + "return is not a function, parentheses are not required\n" . $herecurr); + } + } elsif ($spacing !~ /\s+/) { + ERROR("SPACING", + "space required before the open parenthesis '('\n" . $herecurr); + } + } + +# unnecessary return in a void function +# at end-of-function, with the previous line a single leading tab, then return; +# and the line before that not a goto label target like "out:" + if ($sline =~ /^[ \+]}\s*$/ && + $prevline =~ /^\+\treturn\s*;\s*$/ && + $linenr >= 3 && + $lines[$linenr - 3] =~ /^[ +]/ && + $lines[$linenr - 3] !~ /^[ +]\s*$Ident\s*:/) { + WARN("RETURN_VOID", + "void function return statements are not generally useful\n" . $hereprev); + } + +# if statements using unnecessary parentheses - ie: if ((foo == bar)) + if ($perl_version_ok && + $line =~ /\bif\s*((?:\(\s*){2,})/) { + my $openparens = $1; + my $count = $openparens =~ tr@\(@\(@; + my $msg = ""; + if ($line =~ /\bif\s*(?:\(\s*){$count,$count}$LvalOrFunc\s*($Compare)\s*$LvalOrFunc(?:\s*\)){$count,$count}/) { + my $comp = $4; #Not $1 because of $LvalOrFunc + $msg = " - maybe == should be = ?" if ($comp eq "=="); + WARN("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses$msg\n" . $herecurr); + } + } + +# comparisons with a constant or upper case identifier on the left +# avoid cases like "foo + BAR < baz" +# only fix matches surrounded by parentheses to avoid incorrect +# conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5" + if ($perl_version_ok && + $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) { + my $lead = $1; + my $const = $2; + my $comp = $3; + my $to = $4; + my $newcomp = $comp; + if ($lead !~ /(?:$Operators|\.)\s*$/ && + $to !~ /^(?:Constant|[A-Z_][A-Z0-9_]*)$/ && + WARN("CONSTANT_COMPARISON", + "Comparisons should place the constant on the right side of the test\n" . $herecurr) && + $fix) { + if ($comp eq "<") { + $newcomp = ">"; + } elsif ($comp eq "<=") { + $newcomp = ">="; + } elsif ($comp eq ">") { + $newcomp = "<"; + } elsif ($comp eq ">=") { + $newcomp = "<="; + } + $fixed[$fixlinenr] =~ s/\(\s*\Q$const\E\s*$Compare\s*\Q$to\E\s*\)/($to $newcomp $const)/; + } + } + +# Return of what appears to be an errno should normally be negative + if ($sline =~ /\breturn(?:\s*\(+\s*|\s+)(E[A-Z]+)(?:\s*\)+\s*|\s*)[;:,]/) { + my $name = $1; + if ($name ne 'EOF' && $name ne 'ERROR') { + WARN("USE_NEGATIVE_ERRNO", + "return of an errno should typically be negative (ie: return -$1)\n" . $herecurr); + } + } + +# Need a space before open parenthesis after if, while etc + if ($line =~ /\b(if|while|for|switch)\(/) { + if (ERROR("SPACING", + "space required before the open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\b(if|while|for|switch)\(/$1 \(/; + } + } + +# Check for illegal assignment in if conditional -- and check for trailing +# statements after the conditional. + if ($line =~ /do\s*(?!{)/) { + ($stat, $cond, $line_nr_next, $remain_next, $off_next) = + ctx_statement_block($linenr, $realcnt, 0) + if (!defined $stat); + my ($stat_next) = ctx_statement_block($line_nr_next, + $remain_next, $off_next); + $stat_next =~ s/\n./\n /g; + ##print "stat<$stat> stat_next<$stat_next>\n"; + + if ($stat_next =~ /^\s*while\b/) { + # If the statement carries leading newlines, + # then count those as offsets. + my ($whitespace) = + ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s); + my $offset = + statement_rawlines($whitespace) - 1; + + $suppress_whiletrailers{$line_nr_next + + $offset} = 1; + } + } + if (!defined $suppress_whiletrailers{$linenr} && + defined($stat) && defined($cond) && + $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { + my ($s, $c) = ($stat, $cond); + + if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) { + ERROR("ASSIGN_IN_IF", + "do not use assignment in if condition\n" . $herecurr); + } + + # Find out what is on the end of the line after the + # conditional. + substr($s, 0, length($c), ''); + $s =~ s/\n.*//g; + $s =~ s/$;//g; # Remove any comments + if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && + $c !~ /}\s*while\s*/) + { + # Find out how long the conditional actually is. + my @newlines = ($c =~ /\n/gs); + my $cond_lines = 1 + $#newlines; + my $stat_real = ''; + + $stat_real = raw_line($linenr, $cond_lines) + . "\n" if ($cond_lines); + if (defined($stat_real) && $cond_lines > 1) { + $stat_real = "[...]\n$stat_real"; + } + + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . $herecurr . $stat_real); + } + } + +# Check for bitwise tests written as boolean + if ($line =~ / + (?: + (?:\[|\(|\&\&|\|\|) + \s*0[xX][0-9]+\s* + (?:\&\&|\|\|) + | + (?:\&\&|\|\|) + \s*0[xX][0-9]+\s* + (?:\&\&|\|\||\)|\]) + )/x) + { + WARN("HEXADECIMAL_BOOLEAN_TEST", + "boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr); + } + +# if and else should not have general statements after it + if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { + my $s = $1; + $s =~ s/$;//g; # Remove any comments + if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . $herecurr); + } + } +# if should not continue a brace + if ($line =~ /}\s*if\b/) { + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line (or did you mean 'else if'?)\n" . + $herecurr); + } +# case and default should not have general statements after them + if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g && + $line !~ /\G(?: + (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$| + \s*return\s+ + )/xg) + { + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . $herecurr); + } + + # Check for }<nl>else {, these must be at the same + # indent level to be relevant to each other. + if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ && + $previndent == $indent) { + if (ERROR("ELSE_AFTER_BRACE", + "else should follow close brace '}'\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + $fixedline =~ s/}\s*$//; + if ($fixedline !~ /^\+\s*$/) { + fix_insert_line($fixlinenr, $fixedline); + } + $fixedline = $rawline; + $fixedline =~ s/^(.\s*)else/$1} else/; + fix_insert_line($fixlinenr, $fixedline); + } + } + + if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ && + $previndent == $indent) { + my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0); + + # Find out what is on the end of the line after the + # conditional. + substr($s, 0, length($c), ''); + $s =~ s/\n.*//g; + + if ($s =~ /^\s*;/) { + if (ERROR("WHILE_AFTER_BRACE", + "while should follow close brace '}'\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + my $trailing = $rawline; + $trailing =~ s/^\+//; + $trailing = trim($trailing); + $fixedline =~ s/}\s*$/} $trailing/; + fix_insert_line($fixlinenr, $fixedline); + } + } + } + +#Specific variable tests + while ($line =~ m{($Constant|$Lval)}g) { + my $var = $1; + +#CamelCase + if ($var !~ /^$Constant$/ && + $var =~ /[A-Z][a-z]|[a-z][A-Z]/ && +#Ignore Page<foo> variants + $var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ && +#Ignore SI style variants like nS, mV and dB (ie: max_uV, regulator_min_uA_show) + $var !~ /^(?:[a-z_]*?)_?[a-z][A-Z](?:_[a-z_]+)?$/ && +#Ignore some three character SI units explicitly, like MiB and KHz + $var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) { + while ($var =~ m{($Ident)}g) { + my $word = $1; + next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/); + if ($check) { + seed_camelcase_includes(); + if (!$file && !$camelcase_file_seeded) { + seed_camelcase_file($realfile); + $camelcase_file_seeded = 1; + } + } + if (!defined $camelcase{$word}) { + $camelcase{$word} = 1; + CHK("CAMELCASE", + "Avoid CamelCase: <$word>\n" . $herecurr); + } + } + } + } + +#no spaces allowed after \ in define + if ($line =~ /\#\s*define.*\\\s+$/) { + if (WARN("WHITESPACE_AFTER_LINE_CONTINUATION", + "Whitespace after \\ makes next lines useless\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\s+$//; + } + } + +# warn if <asm/foo.h> is #included and <linux/foo.h> is available and includes +# itself <asm/foo.h> (uses RAW line) + if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) { + my $file = "$1.h"; + my $checkfile = "include/linux/$file"; + if (-f "$root/$checkfile" && + $realfile ne $checkfile && + $1 !~ /$allowed_asm_includes/) + { + my $asminclude = `grep -Ec "#include\\s+<asm/$file>" $root/$checkfile`; + if ($asminclude > 0) { + if ($realfile =~ m{^arch/}) { + CHK("ARCH_INCLUDE_LINUX", + "Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + } else { + WARN("INCLUDE_LINUX", + "Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + } + } + } + } + +# multi-statement macros should be enclosed in a do while loop, grab the +# first statement and ensure its the whole macro if its not enclosed +# in a known good container + if ($realfile !~ m@/vmlinux.lds.h$@ && + $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) { + my $ln = $linenr; + my $cnt = $realcnt; + my ($off, $dstat, $dcond, $rest); + my $ctx = ''; + my $has_flow_statement = 0; + my $has_arg_concat = 0; + ($dstat, $dcond, $ln, $cnt, $off) = + ctx_statement_block($linenr, $realcnt, 0); + $ctx = $dstat; + #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n"; + #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n"; + + $has_flow_statement = 1 if ($ctx =~ /\b(goto|return)\b/); + $has_arg_concat = 1 if ($ctx =~ /\#\#/ && $ctx !~ /\#\#\s*(?:__VA_ARGS__|args)\b/); + + $dstat =~ s/^.\s*\#\s*define\s+$Ident(\([^\)]*\))?\s*//; + my $define_args = $1; + my $define_stmt = $dstat; + my @def_args = (); + + if (defined $define_args && $define_args ne "") { + $define_args = substr($define_args, 1, length($define_args) - 2); + $define_args =~ s/\s*//g; + $define_args =~ s/\\\+?//g; + @def_args = split(",", $define_args); + } + + $dstat =~ s/$;//g; + $dstat =~ s/\\\n.//g; + $dstat =~ s/^\s*//s; + $dstat =~ s/\s*$//s; + + # Flatten any parentheses and braces + while ($dstat =~ s/\([^\(\)]*\)/1/ || + $dstat =~ s/\{[^\{\}]*\}/1/ || + $dstat =~ s/.\[[^\[\]]*\]/1/) + { + } + + # Flatten any obvious string concatentation. + while ($dstat =~ s/($String)\s*$Ident/$1/ || + $dstat =~ s/$Ident\s*($String)/$1/) + { + } + + # Make asm volatile uses seem like a generic function + $dstat =~ s/\b_*asm_*\s+_*volatile_*\b/asm_volatile/g; + + my $exceptions = qr{ + $Declare| + module_param_named| + MODULE_PARM_DESC| + DECLARE_PER_CPU| + DEFINE_PER_CPU| + __typeof__\(| + union| + struct| + \.$Ident\s*=\s*| + ^\"|\"$| + ^\[ + }x; + #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; + + $ctx =~ s/\n*$//; + my $stmt_cnt = statement_rawlines($ctx); + my $herectx = get_stat_here($linenr, $stmt_cnt, $here); + + if ($dstat ne '' && + $dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(), + $dstat !~ /^(?:$Ident|-?$Constant);$/ && # foo(); + $dstat !~ /^[!~-]?(?:$Lval|$Constant)$/ && # 10 // foo() // !foo // ~foo // -foo // foo->bar // foo.bar->baz + $dstat !~ /^'X'$/ && $dstat !~ /^'XX'$/ && # character constants + $dstat !~ /$exceptions/ && + $dstat !~ /^\.$Ident\s*=/ && # .foo = + $dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo + $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...) + $dstat !~ /^for\s*$Constant$/ && # for (...) + $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar() + $dstat !~ /^do\s*{/ && # do {... + $dstat !~ /^\(\{/ && # ({... + $ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/) + { + if ($dstat =~ /^\s*if\b/) { + ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE", + "Macros starting with if should be enclosed by a do - while loop to avoid possible if/else logic defects\n" . "$herectx"); + } elsif ($dstat =~ /;/) { + ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE", + "Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx"); + } else { + ERROR("COMPLEX_MACRO", + "Macros with complex values should be enclosed in parentheses\n" . "$herectx"); + } + + } + + # Make $define_stmt single line, comment-free, etc + my @stmt_array = split('\n', $define_stmt); + my $first = 1; + $define_stmt = ""; + foreach my $l (@stmt_array) { + $l =~ s/\\$//; + if ($first) { + $define_stmt = $l; + $first = 0; + } elsif ($l =~ /^[\+ ]/) { + $define_stmt .= substr($l, 1); + } + } + $define_stmt =~ s/$;//g; + $define_stmt =~ s/\s+/ /g; + $define_stmt = trim($define_stmt); + +# check if any macro arguments are reused (ignore '...' and 'type') + foreach my $arg (@def_args) { + next if ($arg =~ /\.\.\./); + next if ($arg =~ /^type$/i); + my $tmp_stmt = $define_stmt; + $tmp_stmt =~ s/\b(sizeof|typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g; + $tmp_stmt =~ s/\#+\s*$arg\b//g; + $tmp_stmt =~ s/\b$arg\s*\#\#//g; + my $use_cnt = () = $tmp_stmt =~ /\b$arg\b/g; + if ($use_cnt > 1) { + CHK("MACRO_ARG_REUSE", + "Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx"); + } +# check if any macro arguments may have other precedence issues + if ($tmp_stmt =~ m/($Operators)?\s*\b$arg\b\s*($Operators)?/m && + ((defined($1) && $1 ne ',') || + (defined($2) && $2 ne ','))) { + CHK("MACRO_ARG_PRECEDENCE", + "Macro argument '$arg' may be better as '($arg)' to avoid precedence issues\n" . "$herectx"); + } + } + +# check for macros with flow control, but without ## concatenation +# ## concatenation is commonly a macro that defines a function so ignore those + if ($has_flow_statement && !$has_arg_concat) { + my $cnt = statement_rawlines($ctx); + my $herectx = get_stat_here($linenr, $cnt, $here); + + WARN("MACRO_WITH_FLOW_CONTROL", + "Macros with flow control statements should be avoided\n" . "$herectx"); + } + +# check for line continuations outside of #defines, preprocessor #, and asm + + } else { + if ($prevline !~ /^..*\\$/ && + $line !~ /^\+\s*\#.*\\$/ && # preprocessor + $line !~ /^\+.*\b(__asm__|asm)\b.*\\$/ && # asm + $line =~ /^\+.*\\$/) { + WARN("LINE_CONTINUATIONS", + "Avoid unnecessary line continuations\n" . $herecurr); + } + } + +# do {} while (0) macro tests: +# single-statement macros do not need to be enclosed in do while (0) loop, +# macro should not end with a semicolon + if ($perl_version_ok && + $realfile !~ m@/vmlinux.lds.h$@ && + $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) { + my $ln = $linenr; + my $cnt = $realcnt; + my ($off, $dstat, $dcond, $rest); + my $ctx = ''; + ($dstat, $dcond, $ln, $cnt, $off) = + ctx_statement_block($linenr, $realcnt, 0); + $ctx = $dstat; + + $dstat =~ s/\\\n.//g; + $dstat =~ s/$;/ /g; + + if ($dstat =~ /^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/) { + my $stmts = $2; + my $semis = $3; + + $ctx =~ s/\n*$//; + my $cnt = statement_rawlines($ctx); + my $herectx = get_stat_here($linenr, $cnt, $here); + + if (($stmts =~ tr/;/;/) == 1 && + $stmts !~ /^\s*(if|while|for|switch)\b/) { + WARN("SINGLE_STATEMENT_DO_WHILE_MACRO", + "Single statement macros should not use a do {} while (0) loop\n" . "$herectx"); + } + if (defined $semis && $semis ne "") { + WARN("DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON", + "do {} while (0) macros should not be semicolon terminated\n" . "$herectx"); + } + } elsif ($dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/) { + $ctx =~ s/\n*$//; + my $cnt = statement_rawlines($ctx); + my $herectx = get_stat_here($linenr, $cnt, $here); + + WARN("TRAILING_SEMICOLON", + "macros should not use a trailing semicolon\n" . "$herectx"); + } + } + +# check for redundant bracing round if etc + if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) { + my ($level, $endln, @chunks) = + ctx_statement_full($linenr, $realcnt, 1); + #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; + #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"; + if ($#chunks > 0 && $level == 0) { + my @allowed = (); + my $allow = 0; + my $seen = 0; + my $herectx = $here . "\n"; + my $ln = $linenr - 1; + for my $chunk (@chunks) { + my ($cond, $block) = @{$chunk}; + + # If the condition carries leading newlines, then count those as offsets. + my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s); + my $offset = statement_rawlines($whitespace) - 1; + + $allowed[$allow] = 0; + #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n"; + + # We have looked at and allowed this specific line. + $suppress_ifbraces{$ln + $offset} = 1; + + $herectx .= "$rawlines[$ln + $offset]\n[...]\n"; + $ln += statement_rawlines($block) - 1; + + substr($block, 0, length($cond), ''); + + $seen++ if ($block =~ /^\s*{/); + + #print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n"; + if (statement_lines($cond) > 1) { + #print "APW: ALLOWED: cond<$cond>\n"; + $allowed[$allow] = 1; + } + if ($block =~/\b(?:if|for|while)\b/) { + #print "APW: ALLOWED: block<$block>\n"; + $allowed[$allow] = 1; + } + if (statement_block_size($block) > 1) { + #print "APW: ALLOWED: lines block<$block>\n"; + $allowed[$allow] = 1; + } + $allow++; + } + if ($seen) { + my $sum_allowed = 0; + foreach (@allowed) { + $sum_allowed += $_; + } + if ($sum_allowed == 0) { + WARN("BRACES", + "braces {} are not necessary for any arm of this statement\n" . $herectx); + } elsif ($sum_allowed != $allow && + $seen != $allow) { + CHK("BRACES", + "braces {} should be used on all arms of this statement\n" . $herectx); + } + } + } + } + if (!defined $suppress_ifbraces{$linenr - 1} && + $line =~ /\b(if|while|for|else)\b/) { + my $allowed = 0; + + # Check the pre-context. + if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { + #print "APW: ALLOWED: pre<$1>\n"; + $allowed = 1; + } + + my ($level, $endln, @chunks) = + ctx_statement_full($linenr, $realcnt, $-[0]); + + # Check the condition. + my ($cond, $block) = @{$chunks[0]}; + #print "CHECKING<$linenr> cond<$cond> block<$block>\n"; + if (defined $cond) { + substr($block, 0, length($cond), ''); + } + if (statement_lines($cond) > 1) { + #print "APW: ALLOWED: cond<$cond>\n"; + $allowed = 1; + } + if ($block =~/\b(?:if|for|while)\b/) { + #print "APW: ALLOWED: block<$block>\n"; + $allowed = 1; + } + if (statement_block_size($block) > 1) { + #print "APW: ALLOWED: lines block<$block>\n"; + $allowed = 1; + } + # Check the post-context. + if (defined $chunks[1]) { + my ($cond, $block) = @{$chunks[1]}; + if (defined $cond) { + substr($block, 0, length($cond), ''); + } + if ($block =~ /^\s*\{/) { + #print "APW: ALLOWED: chunk-1 block<$block>\n"; + $allowed = 1; + } + } + if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) { + my $cnt = statement_rawlines($block); + my $herectx = get_stat_here($linenr, $cnt, $here); + + WARN("BRACES", + "braces {} are not necessary for single statement blocks\n" . $herectx); + } + } + +# check for single line unbalanced braces + if ($sline =~ /^.\s*\}\s*else\s*$/ || + $sline =~ /^.\s*else\s*\{\s*$/) { + CHK("BRACES", "Unbalanced braces around else statement\n" . $herecurr); + } + +# check for unnecessary blank lines around braces + if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) { + if (CHK("BRACES", + "Blank lines aren't necessary before a close brace '}'\n" . $hereprev) && + $fix && $prevrawline =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + } + } + if (($rawline =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) { + if (CHK("BRACES", + "Blank lines aren't necessary after an open brace '{'\n" . $hereprev) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + } + } + +# no volatiles please + my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b}; + if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) { + WARN("VOLATILE", + "Use of volatile is usually wrong: see Documentation/process/volatile-considered-harmful.rst\n" . $herecurr); + } + +# Check for user-visible strings broken across lines, which breaks the ability +# to grep for the string. Make exceptions when the previous string ends in a +# newline (multiple lines in one string constant) or '\t', '\r', ';', or '{' +# (common in inline assembly) or is a octal \123 or hexadecimal \xaf value + if ($line =~ /^\+\s*$String/ && + $prevline =~ /"\s*$/ && + $prevrawline !~ /(?:\\(?:[ntr]|[0-7]{1,3}|x[0-9a-fA-F]{1,2})|;\s*|\{\s*)"\s*$/) { + if (WARN("SPLIT_STRING", + "quoted string split across lines\n" . $hereprev) && + $fix && + $prevrawline =~ /^\+.*"\s*$/ && + $last_coalesced_string_linenr != $linenr - 1) { + my $extracted_string = get_quoted_string($line, $rawline); + my $comma_close = ""; + if ($rawline =~ /\Q$extracted_string\E(\s*\)\s*;\s*$|\s*,\s*)/) { + $comma_close = $1; + } + + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + $fixedline =~ s/"\s*$//; + $fixedline .= substr($extracted_string, 1) . trim($comma_close); + fix_insert_line($fixlinenr - 1, $fixedline); + $fixedline = $rawline; + $fixedline =~ s/\Q$extracted_string\E\Q$comma_close\E//; + if ($fixedline !~ /\+\s*$/) { + fix_insert_line($fixlinenr, $fixedline); + } + $last_coalesced_string_linenr = $linenr; + } + } + +# check for missing a space in a string concatenation + if ($prevrawline =~ /[^\\]\w"$/ && $rawline =~ /^\+[\t ]+"\w/) { + WARN('MISSING_SPACE', + "break quoted strings at a space character\n" . $hereprev); + } + +# check for an embedded function name in a string when the function is known +# This does not work very well for -f --file checking as it depends on patch +# context providing the function name or a single line form for in-file +# function declarations + if (!$SOF && + $line =~ /^\+.*$String/ && + defined($context_function) && + get_quoted_string($line, $rawline) =~ /\b$context_function\b/ && + length(get_quoted_string($line, $rawline)) != (length($context_function) + 2)) { + WARN("EMBEDDED_FUNCTION_NAME", + "Prefer using '\"%s...\", __func__' to using '$context_function', this function's name, in a string\n" . $herecurr); + } + +# check for spaces before a quoted newline + if ($rawline =~ /^.*\".*\s\\n/) { + if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE", + "unnecessary whitespace before a quoted newline\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/^(\+.*\".*)\s+\\n/$1\\n/; + } + + } + +# concatenated string without spaces between elements + if ($line =~ /$String[A-Za-z0-9_]/ || $line =~ /[A-Za-z0-9_]$String/) { + if (CHK("CONCATENATED_STRING", + "Concatenated strings should use spaces between elements\n" . $herecurr) && + $fix) { + while ($line =~ /($String)/g) { + my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]); + $fixed[$fixlinenr] =~ s/\Q$extracted_string\E([A-Za-z0-9_])/$extracted_string $1/; + $fixed[$fixlinenr] =~ s/([A-Za-z0-9_])\Q$extracted_string\E/$1 $extracted_string/; + } + } + } + +# uncoalesced string fragments + if ($line =~ /$String\s*"/) { + if (WARN("STRING_FRAGMENTS", + "Consecutive strings are generally better as a single string\n" . $herecurr) && + $fix) { + while ($line =~ /($String)(?=\s*")/g) { + my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]); + $fixed[$fixlinenr] =~ s/\Q$extracted_string\E\s*"/substr($extracted_string, 0, -1)/e; + } + } + } + +# check for non-standard and hex prefixed decimal printf formats + my $show_L = 1; #don't show the same defect twice + my $show_Z = 1; + while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { + my $string = substr($rawline, $-[1], $+[1] - $-[1]); + $string =~ s/%%/__/g; + # check for %L + if ($show_L && $string =~ /%[\*\d\.\$]*L([diouxX])/) { + WARN("PRINTF_L", + "\%L$1 is non-standard C, use %ll$1\n" . $herecurr); + $show_L = 0; + } + # check for %Z + if ($show_Z && $string =~ /%[\*\d\.\$]*Z([diouxX])/) { + WARN("PRINTF_Z", + "%Z$1 is non-standard C, use %z$1\n" . $herecurr); + $show_Z = 0; + } + # check for 0x<decimal> + if ($string =~ /0x%[\*\d\.\$\Llzth]*[diou]/) { + ERROR("PRINTF_0XDECIMAL", + "Prefixing 0x with decimal output is defective\n" . $herecurr); + } + } + +# check for line continuations in quoted strings with odd counts of " + if ($rawline =~ /\\$/ && $sline =~ tr/"/"/ % 2) { + WARN("LINE_CONTINUATIONS", + "Avoid line continuations in quoted strings\n" . $herecurr); + } + +# warn about #if 0 + if ($line =~ /^.\s*\#\s*if\s+0\b/) { + WARN("IF_0", + "Consider removing the code enclosed by this #if 0 and its #endif\n" . $herecurr); + } + +# warn about #if 1 + if ($line =~ /^.\s*\#\s*if\s+1\b/) { + WARN("IF_1", + "Consider removing the #if 1 and its #endif\n" . $herecurr); + } + +# check for needless "if (<foo>) fn(<foo>)" uses + if ($prevline =~ /\bif\s*\(\s*($Lval)\s*\)/) { + my $tested = quotemeta($1); + my $expr = '\s*\(\s*' . $tested . '\s*\)\s*;'; + if ($line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?|(?:kmem_cache|mempool|dma_pool)_destroy)$expr/) { + my $func = $1; + if (WARN('NEEDLESS_IF', + "$func(NULL) is safe and this check is probably not required\n" . $hereprev) && + $fix) { + my $do_fix = 1; + my $leading_tabs = ""; + my $new_leading_tabs = ""; + if ($lines[$linenr - 2] =~ /^\+(\t*)if\s*\(\s*$tested\s*\)\s*$/) { + $leading_tabs = $1; + } else { + $do_fix = 0; + } + if ($lines[$linenr - 1] =~ /^\+(\t+)$func\s*\(\s*$tested\s*\)\s*;\s*$/) { + $new_leading_tabs = $1; + if (length($leading_tabs) + 1 ne length($new_leading_tabs)) { + $do_fix = 0; + } + } else { + $do_fix = 0; + } + if ($do_fix) { + fix_delete_line($fixlinenr - 1, $prevrawline); + $fixed[$fixlinenr] =~ s/^\+$new_leading_tabs/\+$leading_tabs/; + } + } + } + } + +# check for unnecessary "Out of Memory" messages + if ($line =~ /^\+.*\b$logFunctions\s*\(/ && + $prevline =~ /^[ \+]\s*if\s*\(\s*(\!\s*|NULL\s*==\s*)?($Lval)(\s*==\s*NULL\s*)?\s*\)/ && + (defined $1 || defined $3) && + $linenr > 3) { + my $testval = $2; + my $testline = $lines[$linenr - 3]; + + my ($s, $c) = ctx_statement_block($linenr - 3, $realcnt, 0); +# print("line: <$line>\nprevline: <$prevline>\ns: <$s>\nc: <$c>\n\n\n"); + + if ($s =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*$allocFunctions\s*\(/ && + $s !~ /\b__GFP_NOWARN\b/ ) { + WARN("OOM_MESSAGE", + "Possible unnecessary 'out of memory' message\n" . $hereprev); + } + } + +# check for logging functions with KERN_<LEVEL> + if ($line !~ /printk(?:_ratelimited|_once)?\s*\(/ && + $line =~ /\b$logFunctions\s*\(.*\b(KERN_[A-Z]+)\b/) { + my $level = $1; + if (WARN("UNNECESSARY_KERN_LEVEL", + "Possible unnecessary $level\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\s*$level\s*//; + } + } + +# check for logging continuations + if ($line =~ /\bprintk\s*\(\s*KERN_CONT\b|\bpr_cont\s*\(/) { + WARN("LOGGING_CONTINUATION", + "Avoid logging continuation uses where feasible\n" . $herecurr); + } + +# check for mask then right shift without a parentheses + if ($perl_version_ok && + $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ && + $4 !~ /^\&/) { # $LvalOrFunc may be &foo, ignore if so + WARN("MASK_THEN_SHIFT", + "Possible precedence defect with mask then right shift - may need parentheses\n" . $herecurr); + } + +# check for pointer comparisons to NULL + if ($perl_version_ok) { + while ($line =~ /\b$LvalOrFunc\s*(==|\!=)\s*NULL\b/g) { + my $val = $1; + my $equal = "!"; + $equal = "" if ($4 eq "!="); + if (CHK("COMPARISON_TO_NULL", + "Comparison to NULL could be written \"${equal}${val}\"\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b\Q$val\E\s*(?:==|\!=)\s*NULL\b/$equal$val/; + } + } + } + +# check for bad placement of section $InitAttribute (e.g.: __initdata) + if ($line =~ /(\b$InitAttribute\b)/) { + my $attr = $1; + if ($line =~ /^\+\s*static\s+(?:const\s+)?(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*[=;]/) { + my $ptr = $1; + my $var = $2; + if ((($ptr =~ /\b(union|struct)\s+$attr\b/ && + ERROR("MISPLACED_INIT", + "$attr should be placed after $var\n" . $herecurr)) || + ($ptr !~ /\b(union|struct)\s+$attr\b/ && + WARN("MISPLACED_INIT", + "$attr should be placed after $var\n" . $herecurr))) && + $fix) { + $fixed[$fixlinenr] =~ s/(\bstatic\s+(?:const\s+)?)(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*([=;])\s*/"$1" . trim(string_find_replace($2, "\\s*$attr\\s*", " ")) . " " . trim(string_find_replace($3, "\\s*$attr\\s*", "")) . " $attr" . ("$4" eq ";" ? ";" : " = ")/e; + } + } + } + +# check for $InitAttributeData (ie: __initdata) with const + if ($line =~ /\bconst\b/ && $line =~ /($InitAttributeData)/) { + my $attr = $1; + $attr =~ /($InitAttributePrefix)(.*)/; + my $attr_prefix = $1; + my $attr_type = $2; + if (ERROR("INIT_ATTRIBUTE", + "Use of const init definition must use ${attr_prefix}initconst\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/$InitAttributeData/${attr_prefix}initconst/; + } + } + +# check for $InitAttributeConst (ie: __initconst) without const + if ($line !~ /\bconst\b/ && $line =~ /($InitAttributeConst)/) { + my $attr = $1; + if (ERROR("INIT_ATTRIBUTE", + "Use of $attr requires a separate use of const\n" . $herecurr) && + $fix) { + my $lead = $fixed[$fixlinenr] =~ + /(^\+\s*(?:static\s+))/; + $lead = rtrim($1); + $lead = "$lead " if ($lead !~ /^\+$/); + $lead = "${lead}const "; + $fixed[$fixlinenr] =~ s/(^\+\s*(?:static\s+))/$lead/; + } + } + +# check for __read_mostly with const non-pointer (should just be const) + if ($line =~ /\b__read_mostly\b/ && + $line =~ /($Type)\s*$Ident/ && $1 !~ /\*\s*$/ && $1 =~ /\bconst\b/) { + if (ERROR("CONST_READ_MOSTLY", + "Invalid use of __read_mostly with const type\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\s+__read_mostly\b//; + } + } + +# don't use __constant_<foo> functions outside of include/uapi/ + if ($realfile !~ m@^include/uapi/@ && + $line =~ /(__constant_(?:htons|ntohs|[bl]e(?:16|32|64)_to_cpu|cpu_to_[bl]e(?:16|32|64)))\s*\(/) { + my $constant_func = $1; + my $func = $constant_func; + $func =~ s/^__constant_//; + if (WARN("CONSTANT_CONVERSION", + "$constant_func should be $func\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b$constant_func\b/$func/g; + } + } + +# prefer usleep_range over udelay + if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) { + my $delay = $1; + # ignore udelay's < 10, however + if (! ($delay < 10) ) { + CHK("USLEEP_RANGE", + "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst\n" . $herecurr); + } + if ($delay > 2000) { + WARN("LONG_UDELAY", + "long udelay - prefer mdelay; see arch/arm/include/asm/delay.h\n" . $herecurr); + } + } + +# warn about unexpectedly long msleep's + if ($line =~ /\bmsleep\s*\((\d+)\);/) { + if ($1 < 20) { + WARN("MSLEEP", + "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.rst\n" . $herecurr); + } + } + +# check for comparisons of jiffies + if ($line =~ /\bjiffies\s*$Compare|$Compare\s*jiffies\b/) { + WARN("JIFFIES_COMPARISON", + "Comparing jiffies is almost always wrong; prefer time_after, time_before and friends\n" . $herecurr); + } + +# check for comparisons of get_jiffies_64() + if ($line =~ /\bget_jiffies_64\s*\(\s*\)\s*$Compare|$Compare\s*get_jiffies_64\s*\(\s*\)/) { + WARN("JIFFIES_COMPARISON", + "Comparing get_jiffies_64() is almost always wrong; prefer time_after64, time_before64 and friends\n" . $herecurr); + } + +# warn about #ifdefs in C files +# if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) { +# print "#ifdef in C files should be avoided\n"; +# print "$herecurr"; +# $clean = 0; +# } + +# warn about spacing in #ifdefs + if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) { + if (ERROR("SPACING", + "exactly one space required after that #$1\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(.\s*\#\s*(ifdef|ifndef|elif))\s{2,}/$1 /; + } + + } + +# check for spinlock_t definitions without a comment. + if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ || + $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) { + my $which = $1; + if (!ctx_has_comment($first_line, $linenr)) { + CHK("UNCOMMENTED_DEFINITION", + "$1 definition without comment\n" . $herecurr); + } + } +# check for memory barriers without a comment. + + my $barriers = qr{ + mb| + rmb| + wmb| + read_barrier_depends + }x; + my $barrier_stems = qr{ + mb__before_atomic| + mb__after_atomic| + store_release| + load_acquire| + store_mb| + (?:$barriers) + }x; + my $all_barriers = qr{ + (?:$barriers)| + smp_(?:$barrier_stems)| + virt_(?:$barrier_stems) + }x; + + if ($line =~ /\b(?:$all_barriers)\s*\(/) { + if (!ctx_has_comment($first_line, $linenr)) { + WARN("MEMORY_BARRIER", + "memory barrier without comment\n" . $herecurr); + } + } + + my $underscore_smp_barriers = qr{__smp_(?:$barrier_stems)}x; + + if ($realfile !~ m@^include/asm-generic/@ && + $realfile !~ m@/barrier\.h$@ && + $line =~ m/\b(?:$underscore_smp_barriers)\s*\(/ && + $line !~ m/^.\s*\#\s*define\s+(?:$underscore_smp_barriers)\s*\(/) { + WARN("MEMORY_BARRIER", + "__smp memory barriers shouldn't be used outside barrier.h and asm-generic\n" . $herecurr); + } + +# check for waitqueue_active without a comment. + if ($line =~ /\bwaitqueue_active\s*\(/) { + if (!ctx_has_comment($first_line, $linenr)) { + WARN("WAITQUEUE_ACTIVE", + "waitqueue_active without comment\n" . $herecurr); + } + } + +# check for smp_read_barrier_depends and read_barrier_depends + if (!$file && $line =~ /\b(smp_|)read_barrier_depends\s*\(/) { + WARN("READ_BARRIER_DEPENDS", + "$1read_barrier_depends should only be used in READ_ONCE or DEC Alpha code\n" . $herecurr); + } + +# check of hardware specific defines + if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) { + CHK("ARCH_DEFINES", + "architecture specific defines should be avoided\n" . $herecurr); + } + +# check that the storage class is not after a type + if ($line =~ /\b($Type)\s+($Storage)\b/) { + WARN("STORAGE_CLASS", + "storage class '$2' should be located before type '$1'\n" . $herecurr); + } +# Check that the storage class is at the beginning of a declaration + if ($line =~ /\b$Storage\b/ && + $line !~ /^.\s*$Storage/ && + $line =~ /^.\s*(.+?)\$Storage\s/ && + $1 !~ /[\,\)]\s*$/) { + WARN("STORAGE_CLASS", + "storage class should be at the beginning of the declaration\n" . $herecurr); + } + +# check the location of the inline attribute, that it is between +# storage class and type. + if ($line =~ /\b$Type\s+$Inline\b/ || + $line =~ /\b$Inline\s+$Storage\b/) { + ERROR("INLINE_LOCATION", + "inline keyword should sit between storage class and type\n" . $herecurr); + } + +# Check for __inline__ and __inline, prefer inline + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b(__inline__|__inline)\b/) { + if (WARN("INLINE", + "plain inline is preferred over $1\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b(__inline__|__inline)\b/inline/; + + } + } + +# Check for __attribute__ packed, prefer __packed + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) { + WARN("PREFER_PACKED", + "__packed is preferred over __attribute__((packed))\n" . $herecurr); + } + +# Check for __attribute__ aligned, prefer __aligned + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(.*aligned/) { + WARN("PREFER_ALIGNED", + "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr); + } + +# Check for __attribute__ section, prefer __section + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(.*_*section_*\s*\(\s*("[^"]*")/) { + my $old = substr($rawline, $-[1], $+[1] - $-[1]); + my $new = substr($old, 1, -1); + if (WARN("PREFER_SECTION", + "__section($new) is preferred over __attribute__((section($old)))\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*_*section_*\s*\(\s*\Q$old\E\s*\)\s*\)\s*\)/__section($new)/; + } + } + +# Check for __attribute__ format(printf, prefer __printf + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) { + if (WARN("PREFER_PRINTF", + "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf\s*,\s*(.*)\)\s*\)\s*\)/"__printf(" . trim($1) . ")"/ex; + + } + } + +# Check for __attribute__ format(scanf, prefer __scanf + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) { + if (WARN("PREFER_SCANF", + "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\s*,\s*(.*)\)\s*\)\s*\)/"__scanf(" . trim($1) . ")"/ex; + } + } + +# Check for __attribute__ weak, or __weak declarations (may have link issues) + if ($perl_version_ok && + $line =~ /(?:$Declare|$DeclareMisordered)\s*$Ident\s*$balanced_parens\s*(?:$Attribute)?\s*;/ && + ($line =~ /\b__attribute__\s*\(\s*\(.*\bweak\b/ || + $line =~ /\b__weak\b/)) { + ERROR("WEAK_DECLARATION", + "Using weak declarations can have unintended link defects\n" . $herecurr); + } + +# check for c99 types like uint8_t used outside of uapi/ and tools/ + if (!$SOF && + $realfile !~ m@\binclude/uapi/@ && + $realfile !~ m@\btools/@ && + $line =~ /\b($Declare)\s*$Ident\s*[=;,\[]/) { + my $type = $1; + if ($type =~ /\b($typeC99Typedefs)\b/) { + $type = $1; + my $kernel_type = 'u'; + $kernel_type = 's' if ($type =~ /^_*[si]/); + $type =~ /(\d+)/; + $kernel_type .= $1; + if (CHK("PREFER_KERNEL_TYPES", + "Prefer kernel type '$kernel_type' over '$type'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b$type\b/$kernel_type/; + } + } + } + +# check for cast of C90 native int or longer types constants + if ($line =~ /(\(\s*$C90_int_types\s*\)\s*)($Constant)\b/) { + my $cast = $1; + my $const = $2; + if (WARN("TYPECAST_INT_CONSTANT", + "Unnecessary typecast of c90 int constant\n" . $herecurr) && + $fix) { + my $suffix = ""; + my $newconst = $const; + $newconst =~ s/${Int_type}$//; + $suffix .= 'U' if ($cast =~ /\bunsigned\b/); + if ($cast =~ /\blong\s+long\b/) { + $suffix .= 'LL'; + } elsif ($cast =~ /\blong\b/) { + $suffix .= 'L'; + } + $fixed[$fixlinenr] =~ s/\Q$cast\E$const\b/$newconst$suffix/; + } + } + +# check for sizeof(&) + if ($line =~ /\bsizeof\s*\(\s*\&/) { + WARN("SIZEOF_ADDRESS", + "sizeof(& should be avoided\n" . $herecurr); + } + +# check for sizeof without parenthesis + if ($line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/) { + if (WARN("SIZEOF_PARENTHESIS", + "sizeof $1 should be sizeof($1)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/"sizeof(" . trim($1) . ")"/ex; + } + } + +# check for struct spinlock declarations + if ($line =~ /^.\s*\bstruct\s+spinlock\s+\w+\s*;/) { + WARN("USE_SPINLOCK_T", + "struct spinlock should be spinlock_t\n" . $herecurr); + } + +# check for seq_printf uses that could be seq_puts + if ($sline =~ /\bseq_printf\s*\(.*"\s*\)\s*;\s*$/) { + my $fmt = get_quoted_string($line, $rawline); + $fmt =~ s/%%//g; + if ($fmt !~ /%/) { + if (WARN("PREFER_SEQ_PUTS", + "Prefer seq_puts to seq_printf\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bseq_printf\b/seq_puts/; + } + } + } + +# check for memcpy uses that should be memcpy_s + if ($SOF && ($line =~ /memcpy\s*\(.*/)) { + my $fmt = get_quoted_string($line, $rawline); + $fmt =~ s/%%//g; + if ($fmt !~ /%/) { + if (WARN("PREFER_MEMCPY_S", + "Use safe version of memcpy - memcpy_s whenever possible\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/memcpy\b/memcpy_s/; + } + } + } + +# check for vsprintf extension %p<foo> misuses + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s && + $1 !~ /^_*volatile_*$/) { + my $stat_real; + + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + for (my $count = $linenr; $count <= $lc; $count++) { + my $specifier; + my $extension; + my $bad_specifier = ""; + my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); + $fmt =~ s/%%//g; + + while ($fmt =~ /(\%[\*\d\.]*p(\w))/g) { + $specifier = $1; + $extension = $2; + if ($extension !~ /[SsBKRraEhMmIiUDdgVCbGNOxt]/) { + $bad_specifier = $specifier; + last; + } + if ($extension eq "x" && !defined($stat_real)) { + if (!defined($stat_real)) { + $stat_real = get_stat_real($linenr, $lc); + } + WARN("VSPRINTF_SPECIFIER_PX", + "Using vsprintf specifier '\%px' potentially exposes the kernel memory layout, if you don't really need the address please consider using '\%p'.\n" . "$here\n$stat_real\n"); + } + } + if ($bad_specifier ne "") { + my $stat_real = get_stat_real($linenr, $lc); + my $ext_type = "Invalid"; + my $use = ""; + if ($bad_specifier =~ /p[Ff]/) { + $ext_type = "Deprecated"; + $use = " - use %pS instead"; + $use =~ s/pS/ps/ if ($bad_specifier =~ /pf/); + } + + WARN("VSPRINTF_POINTER_EXTENSION", + "$ext_type vsprintf pointer extension '$bad_specifier'$use\n" . "$here\n$stat_real\n"); + } + } + } + +# Check for misused memsets + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/) { + + my $ms_addr = $2; + my $ms_val = $7; + my $ms_size = $12; + + if ($ms_size =~ /^(0x|)0$/i) { + ERROR("MEMSET", + "memset to 0's uses 0 as the 2nd argument, not the 3rd\n" . "$here\n$stat\n"); + } elsif ($ms_size =~ /^(0x|)1$/i) { + WARN("MEMSET", + "single byte memset is suspicious. Swapped 2nd/3rd argument?\n" . "$here\n$stat\n"); + } + } + +# Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar) +# if ($perl_version_ok && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { +# if (WARN("PREFER_ETHER_ADDR_COPY", +# "Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/; +# } +# } + +# Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar) +# if ($perl_version_ok && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { +# WARN("PREFER_ETHER_ADDR_EQUAL", +# "Prefer ether_addr_equal() or ether_addr_equal_unaligned() over memcmp()\n" . "$here\n$stat\n") +# } + +# check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr +# check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr +# if ($perl_version_ok && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { +# +# my $ms_val = $7; +# +# if ($ms_val =~ /^(?:0x|)0+$/i) { +# if (WARN("PREFER_ETH_ZERO_ADDR", +# "Prefer eth_zero_addr over memset()\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_zero_addr($2)/; +# } +# } elsif ($ms_val =~ /^(?:0xff|255)$/i) { +# if (WARN("PREFER_ETH_BROADCAST_ADDR", +# "Prefer eth_broadcast_addr() over memset()\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_broadcast_addr($2)/; +# } +# } +# } + +# typecasts on min/max could be min_t/max_t + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) { + if (defined $2 || defined $7) { + my $call = $1; + my $cast1 = deparenthesize($2); + my $arg1 = $3; + my $cast2 = deparenthesize($7); + my $arg2 = $8; + my $cast; + + if ($cast1 ne "" && $cast2 ne "" && $cast1 ne $cast2) { + $cast = "$cast1 or $cast2"; + } elsif ($cast1 ne "") { + $cast = $cast1; + } else { + $cast = $cast2; + } + WARN("MINMAX", + "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . "$here\n$stat\n"); + } + } + +# check usleep_range arguments + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) { + my $min = $1; + my $max = $7; + if ($min eq $max) { + WARN("USLEEP_RANGE", + "usleep_range should not use min == max args; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n"); + } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ && + $min > $max) { + WARN("USLEEP_RANGE", + "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n"); + } + } + +# check for naked sscanf + if ($perl_version_ok && + defined $stat && + $line =~ /\bsscanf\b/ && + ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ && + $stat !~ /\bsscanf\s*$balanced_parens\s*(?:$Compare)/ && + $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) { + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = get_stat_real($linenr, $lc); + WARN("NAKED_SSCANF", + "unchecked sscanf return value\n" . "$here\n$stat_real\n"); + } + +# check for simple sscanf that should be kstrto<foo> + if ($perl_version_ok && + defined $stat && + $line =~ /\bsscanf\b/) { + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = get_stat_real($linenr, $lc); + if ($stat_real =~ /\bsscanf\b\s*\(\s*$FuncArg\s*,\s*("[^"]+")/) { + my $format = $6; + my $count = $format =~ tr@%@%@; + if ($count == 1 && + $format =~ /^"\%(?i:ll[udxi]|[udxi]ll|ll|[hl]h?[udxi]|[udxi][hl]h?|[hl]h?|[udxi])"$/) { + WARN("SSCANF_TO_KSTRTO", + "Prefer kstrto<type> to single variable sscanf\n" . "$here\n$stat_real\n"); + } + } + } + +# check for new externs in .h files. + if ($realfile =~ /\.h$/ && + $line =~ /^\+\s*(extern\s+)$Type\s*$Ident\s*\(/s) { + if (CHK("AVOID_EXTERNS", + "extern prototypes should be avoided in .h files\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(.*)\bextern\b\s*(.*)/$1$2/; + } + } + +# check for new externs in .c files. + if ($realfile =~ /\.c$/ && defined $stat && + $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) + { + my $function_name = $1; + my $paren_space = $2; + + my $s = $stat; + if (defined $cond) { + substr($s, 0, length($cond), ''); + } + if ($s =~ /^\s*;/ && + $function_name ne 'uninitialized_var') + { + WARN("AVOID_EXTERNS", + "externs should be avoided in .c files\n" . $herecurr); + } + + if ($paren_space =~ /\n/) { + WARN("FUNCTION_ARGUMENTS", + "arguments for function declarations should follow identifier\n" . $herecurr); + } + + } elsif ($realfile =~ /\.c$/ && defined $stat && + $stat =~ /^.\s*extern\s+/) + { + WARN("AVOID_EXTERNS", + "externs should be avoided in .c files\n" . $herecurr); + } + +# check for function declarations that have arguments without identifier names + if (defined $stat && + $stat =~ /^.\s*(?:extern\s+)?$Type\s*(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*\(\s*([^{]+)\s*\)\s*;/s && + $1 ne "void") { + my $args = trim($1); + while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) { + my $arg = trim($1); + if ($arg =~ /^$Type$/ && $arg !~ /enum\s+$Ident$/) { + WARN("FUNCTION_ARGUMENTS", + "function definition argument '$arg' should also have an identifier name\n" . $herecurr); + } + } + } + +# check for function definitions + if ($perl_version_ok && + defined $stat && + $stat =~ /^.\s*(?:$Storage\s+)?$Type\s*($Ident)\s*$balanced_parens\s*{/s) { + $context_function = $1; + +# check for multiline function definition with misplaced open brace + my $ok = 0; + my $cnt = statement_rawlines($stat); + my $herectx = $here . "\n"; + for (my $n = 0; $n < $cnt; $n++) { + my $rl = raw_line($linenr, $n); + $herectx .= $rl . "\n"; + $ok = 1 if ($rl =~ /^[ \+]\{/); + $ok = 1 if ($rl =~ /\{/ && $n == 0); + last if $rl =~ /^[ \+].*\{/; + } + if (!$ok) { + ERROR("OPEN_BRACE", + "open brace '{' following function definitions go on the next line\n" . $herectx); + } + } + +# checks for new __setup's + if ($rawline =~ /\b__setup\("([^"]*)"/) { + my $name = $1; + + if (!grep(/$name/, @setup_docs)) { + CHK("UNDOCUMENTED_SETUP", + "__setup appears un-documented -- check Documentation/admin-guide/kernel-parameters.rst\n" . $herecurr); + } + } + +# check for pointless casting of alloc functions + if ($line =~ /\*\s*\)\s*$allocFunctions\b/) { + WARN("UNNECESSARY_CASTS", + "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); + } + +# alloc style +# p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...) + if ($perl_version_ok && + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k|v)[mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) { + CHK("ALLOC_SIZEOF_STRUCT", + "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr); + } + +# check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) { + my $oldfunc = $3; + my $a1 = $4; + my $a2 = $10; + my $newfunc = "kmalloc_array"; + $newfunc = "kcalloc" if ($oldfunc eq "kzalloc"); + my $r1 = $a1; + my $r2 = $a2; + if ($a1 =~ /^sizeof\s*\S/) { + $r1 = $a2; + $r2 = $a1; + } + if ($r1 !~ /^sizeof\b/ && $r2 =~ /^sizeof\s*\S/ && + !($r1 =~ /^$Constant$/ || $r1 =~ /^[A-Z_][A-Z0-9_]*$/)) { + my $cnt = statement_rawlines($stat); + my $herectx = get_stat_here($linenr, $cnt, $here); + + if (WARN("ALLOC_WITH_MULTIPLY", + "Prefer $newfunc over $oldfunc with multiply\n" . $herectx) && + $cnt == 1 && + $fix) { + $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e; + } + } + } + +# check for krealloc arg reuse + if ($perl_version_ok && + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*($Lval)\s*,/ && + $1 eq $3) { + WARN("KREALLOC_ARG_REUSE", + "Reusing the krealloc arg is almost always a bug\n" . $herecurr); + } + +# check for alloc argument mismatch + if ($line =~ /\b(kcalloc|kmalloc_array)\s*\(\s*sizeof\b/) { + WARN("ALLOC_ARRAY_ARGS", + "$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr); + } + +# check for multiple semicolons + if ($line =~ /;\s*;\s*$/) { + if (WARN("ONE_SEMICOLON", + "Statements terminations use 1 semicolon\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(\s*;\s*){2,}$/;/g; + } + } + +# check for #defines like: 1 << <digit> that could be BIT(digit), it is not exported to uapi + if ($realfile !~ m@^include/uapi/@ && + $line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) { + my $ull = ""; + $ull = "_ULL" if (defined($1) && $1 =~ /ll/i); + if (CHK("BIT_MACRO", + "Prefer using the BIT$ull macro\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\(?\s*1\s*[ulUL]*\s*<<\s*(\d+|$Ident)\s*\)?/BIT${ull}($1)/; + } + } + +# check for #if defined CONFIG_<FOO> || defined CONFIG_<FOO>_MODULE + if ($line =~ /^\+\s*#\s*if\s+defined(?:\s*\(?\s*|\s+)(CONFIG_[A-Z_]+)\s*\)?\s*\|\|\s*defined(?:\s*\(?\s*|\s+)\1_MODULE\s*\)?\s*$/) { + my $config = $1; + if (WARN("PREFER_IS_ENABLED", + "Prefer IS_ENABLED(<FOO>) to CONFIG_<FOO> || CONFIG_<FOO>_MODULE\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = "\+#if IS_ENABLED($config)"; + } + } + +# check for case / default statements not preceded by break/fallthrough/switch + if ($line =~ /^.\s*(?:case\s+(?:$Ident|$Constant)\s*|default):/) { + my $has_break = 0; + my $has_statement = 0; + my $count = 0; + my $prevline = $linenr; + while ($prevline > 1 && ($file || $count < 3) && !$has_break) { + $prevline--; + my $rline = $rawlines[$prevline - 1]; + my $fline = $lines[$prevline - 1]; + last if ($fline =~ /^\@\@/); + next if ($fline =~ /^\-/); + next if ($fline =~ /^.(?:\s*(?:case\s+(?:$Ident|$Constant)[\s$;]*|default):[\s$;]*)*$/); + $has_break = 1 if ($rline =~ /fall[\s_-]*(through|thru)/i); + next if ($fline =~ /^.[\s$;]*$/); + $has_statement = 1; + $count++; + $has_break = 1 if ($fline =~ /\bswitch\b|\b(?:break\s*;[\s$;]*$|exit\s*\(\b|return\b|goto\b|continue\b)/); + } + if (!$has_break && $has_statement) { + WARN("MISSING_BREAK", + "Possible switch case/default not preceded by break or fallthrough comment\n" . $herecurr); + } + } + +# check for switch/default statements without a break; + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) { + my $cnt = statement_rawlines($stat); + my $herectx = get_stat_here($linenr, $cnt, $here); + + WARN("DEFAULT_NO_BREAK", + "switch default: should use break\n" . $herectx); + } + +# check for gcc specific __FUNCTION__ + if ($line =~ /\b__FUNCTION__\b/) { + if (WARN("USE_FUNC", + "__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b__FUNCTION__\b/__func__/g; + } + } + +# check for uses of __DATE__, __TIME__, __TIMESTAMP__ + while ($line =~ /\b(__(?:DATE|TIME|TIMESTAMP)__)\b/g) { + ERROR("DATE_TIME", + "Use of the '$1' macro makes the build non-deterministic\n" . $herecurr); + } + +# check for use of yield() + if ($line =~ /\byield\s*\(\s*\)/) { + WARN("YIELD", + "Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n" . $herecurr); + } + +# check for comparisons against true and false + if ($line =~ /\+\s*(.*?)\b(true|false|$Lval)\s*(==|\!=)\s*(true|false|$Lval)\b(.*)$/i) { + my $lead = $1; + my $arg = $2; + my $test = $3; + my $otype = $4; + my $trail = $5; + my $op = "!"; + + ($arg, $otype) = ($otype, $arg) if ($arg =~ /^(?:true|false)$/i); + + my $type = lc($otype); + if ($type =~ /^(?:true|false)$/) { + if (("$test" eq "==" && "$type" eq "true") || + ("$test" eq "!=" && "$type" eq "false")) { + $op = ""; + } + + CHK("BOOL_COMPARISON", + "Using comparison to $otype is error prone\n" . $herecurr); + +## maybe suggesting a correct construct would better +## "Using comparison to $otype is error prone. Perhaps use '${lead}${op}${arg}${trail}'\n" . $herecurr); + + } + } + +# check for semaphores initialized locked + if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) { + WARN("CONSIDER_COMPLETION", + "consider using a completion\n" . $herecurr); + } + +# recommend kstrto* over simple_strto* and strict_strto* + if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) { + WARN("CONSIDER_KSTRTO", + "$1 is obsolete, use k$3 instead\n" . $herecurr); + } + +# check for __initcall(), use device_initcall() explicitly or more appropriate function please + if ($line =~ /^.\s*__initcall\s*\(/) { + WARN("USE_DEVICE_INITCALL", + "please use device_initcall() or more appropriate function instead of __initcall() (see include/linux/init.h)\n" . $herecurr); + } + +# check for spin_is_locked(), suggest lockdep instead + if ($line =~ /\bspin_is_locked\(/) { + WARN("USE_LOCKDEP", + "Where possible, use lockdep_assert_held instead of assertions based on spin_is_locked\n" . $herecurr); + } + +# check for deprecated apis + if ($line =~ /\b($deprecated_apis_search)\b\s*\(/) { + my $deprecated_api = $1; + my $new_api = $deprecated_apis{$deprecated_api}; + WARN("DEPRECATED_API", + "Deprecated use of '$deprecated_api', prefer '$new_api' instead\n" . $herecurr); + } + +# check for various structs that are normally const (ops, kgdb, device_tree) +# and avoid what seem like struct definitions 'struct foo {' + if ($line !~ /\bconst\b/ && + $line =~ /\bstruct\s+($const_structs)\b(?!\s*\{)/) { + WARN("CONST_STRUCT", + "struct $1 should normally be const\n" . $herecurr); + } + +# use of NR_CPUS is usually wrong +# ignore definitions of NR_CPUS and usage to define arrays as likely right + if ($line =~ /\bNR_CPUS\b/ && + $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ && + $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ && + $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ && + $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ && + $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/) + { + WARN("NR_CPUS", + "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); + } + +# Use of __ARCH_HAS_<FOO> or ARCH_HAVE_<BAR> is wrong. + if ($line =~ /\+\s*#\s*define\s+((?:__)?ARCH_(?:HAS|HAVE)\w*)\b/) { + ERROR("DEFINE_ARCH_HAS", + "#define of '$1' is wrong - use Kconfig variables or standard guards instead\n" . $herecurr); + } + +# likely/unlikely comparisons similar to "(likely(foo) > 0)" + if ($perl_version_ok && + $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) { + WARN("LIKELY_MISUSE", + "Using $1 should generally have parentheses around the comparison\n" . $herecurr); + } + +# nested likely/unlikely calls + if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) { + WARN("LIKELY_MISUSE", + "nested (un)?likely() calls, $1 already uses unlikely() internally\n" . $herecurr); + } + +# whine mightly about in_atomic + if ($line =~ /\bin_atomic\s*\(/) { + if ($realfile =~ m@^drivers/@) { + ERROR("IN_ATOMIC", + "do not use in_atomic in drivers\n" . $herecurr); + } elsif ($realfile !~ m@^kernel/@) { + WARN("IN_ATOMIC", + "use of in_atomic() is incorrect outside core kernel code\n" . $herecurr); + } + } + +# check for mutex_trylock_recursive usage + if ($line =~ /mutex_trylock_recursive/) { + ERROR("LOCKING", + "recursive locking is bad, do not use this ever.\n" . $herecurr); + } + +# check for lockdep_set_novalidate_class + if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ || + $line =~ /__lockdep_no_validate__\s*\)/ ) { + if ($realfile !~ m@^kernel/lockdep@ && + $realfile !~ m@^include/linux/lockdep@ && + $realfile !~ m@^drivers/base/core@) { + ERROR("LOCKDEP", + "lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr); + } + } + + if ($line =~ /debugfs_create_\w+.*\b$mode_perms_world_writable\b/ || + $line =~ /DEVICE_ATTR.*\b$mode_perms_world_writable\b/) { + WARN("EXPORTED_WORLD_WRITABLE", + "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr); + } + +# check for DEVICE_ATTR uses that could be DEVICE_ATTR_<FOO> +# and whether or not function naming is typical and if +# DEVICE_ATTR permissions uses are unusual too + if ($perl_version_ok && + defined $stat && + $stat =~ /\bDEVICE_ATTR\s*\(\s*(\w+)\s*,\s*\(?\s*(\s*(?:${multi_mode_perms_string_search}|0[0-7]{3,3})\s*)\s*\)?\s*,\s*(\w+)\s*,\s*(\w+)\s*\)/) { + my $var = $1; + my $perms = $2; + my $show = $3; + my $store = $4; + my $octal_perms = perms_to_octal($perms); + if ($show =~ /^${var}_show$/ && + $store =~ /^${var}_store$/ && + $octal_perms eq "0644") { + if (WARN("DEVICE_ATTR_RW", + "Use DEVICE_ATTR_RW\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*$store\s*\)/DEVICE_ATTR_RW(${var})/; + } + } elsif ($show =~ /^${var}_show$/ && + $store =~ /^NULL$/ && + $octal_perms eq "0444") { + if (WARN("DEVICE_ATTR_RO", + "Use DEVICE_ATTR_RO\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*NULL\s*\)/DEVICE_ATTR_RO(${var})/; + } + } elsif ($show =~ /^NULL$/ && + $store =~ /^${var}_store$/ && + $octal_perms eq "0200") { + if (WARN("DEVICE_ATTR_WO", + "Use DEVICE_ATTR_WO\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*NULL\s*,\s*$store\s*\)/DEVICE_ATTR_WO(${var})/; + } + } elsif ($octal_perms eq "0644" || + $octal_perms eq "0444" || + $octal_perms eq "0200") { + my $newshow = "$show"; + $newshow = "${var}_show" if ($show ne "NULL" && $show ne "${var}_show"); + my $newstore = $store; + $newstore = "${var}_store" if ($store ne "NULL" && $store ne "${var}_store"); + my $rename = ""; + if ($show ne $newshow) { + $rename .= " '$show' to '$newshow'"; + } + if ($store ne $newstore) { + $rename .= " '$store' to '$newstore'"; + } + WARN("DEVICE_ATTR_FUNCTIONS", + "Consider renaming function(s)$rename\n" . $herecurr); + } else { + WARN("DEVICE_ATTR_PERMS", + "DEVICE_ATTR unusual permissions '$perms' used\n" . $herecurr); + } + } + +# Mode permission misuses where it seems decimal should be octal +# This uses a shortcut match to avoid unnecessary uses of a slow foreach loop +# o Ignore module_param*(...) uses with a decimal 0 permission as that has a +# specific definition of not visible in sysfs. +# o Ignore proc_create*(...) uses with a decimal 0 permission as that means +# use the default permissions + if ($perl_version_ok && + defined $stat && + $line =~ /$mode_perms_search/) { + foreach my $entry (@mode_permission_funcs) { + my $func = $entry->[0]; + my $arg_pos = $entry->[1]; + + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = get_stat_real($linenr, $lc); + + my $skip_args = ""; + if ($arg_pos > 1) { + $arg_pos--; + $skip_args = "(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}"; + } + my $test = "\\b$func\\s*\\(${skip_args}($FuncArg(?:\\|\\s*$FuncArg)*)\\s*[,\\)]"; + if ($stat =~ /$test/) { + my $val = $1; + $val = $6 if ($skip_args ne ""); + if (!($func =~ /^(?:module_param|proc_create)/ && $val eq "0") && + (($val =~ /^$Int$/ && $val !~ /^$Octal$/) || + ($val =~ /^$Octal$/ && length($val) ne 4))) { + ERROR("NON_OCTAL_PERMISSIONS", + "Use 4 digit octal (0777) not decimal permissions\n" . "$here\n" . $stat_real); + } + if ($val =~ /^$Octal$/ && (oct($val) & 02)) { + ERROR("EXPORTED_WORLD_WRITABLE", + "Exporting writable files is usually an error. Consider more restrictive permissions.\n" . "$here\n" . $stat_real); + } + } + } + } + +# check for uses of S_<PERMS> that could be octal for readability + while ($line =~ m{\b($multi_mode_perms_string_search)\b}g) { + my $oval = $1; + my $octal = perms_to_octal($oval); + if (WARN("SYMBOLIC_PERMS", + "Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$oval\E/$octal/; + } + } + +# validate content of MODULE_LICENSE against list from include/linux/module.h + if ($line =~ /\bMODULE_LICENSE\s*\(\s*($String)\s*\)/) { + my $extracted_string = get_quoted_string($line, $rawline); + my $valid_licenses = qr{ + GPL| + GPL\ v2| + GPL\ and\ additional\ rights| + Dual\ BSD/GPL| + Dual\ MIT/GPL| + Dual\ MPL/GPL| + Proprietary + }x; + if ($extracted_string !~ /^"(?:$valid_licenses)"$/x) { + WARN("MODULE_LICENSE", + "unknown module license " . $extracted_string . "\n" . $herecurr); + } + } + +# check for sysctl duplicate constants + if ($line =~ /\.extra[12]\s*=\s*&(zero|one|int_max)\b/) { + WARN("DUPLICATED_SYSCTL_CONST", + "duplicated sysctl range checking value '$1', consider using the shared one in include/linux/sysctl.h\n" . $herecurr); + } + } + + # If we have no input at all, then there is nothing to report on + # so just keep quiet. + if ($#rawlines == -1) { + exit(0); + } + + # In mailback mode only produce a report in the negative, for + # things that appear to be patches. + if ($mailback && ($clean == 1 || !$is_patch)) { + exit(0); + } + + # This is not a patch, and we are are in 'no-patch' mode so + # just keep quiet. + if (!$chk_patch && !$is_patch) { + exit(0); + } + + if (!$is_patch && $filename !~ /cover-letter\.patch$/) { + ERROR("NOT_UNIFIED_DIFF", + "Does not appear to be a unified-diff format patch\n"); + } + if ($is_patch && $has_commit_log && $chk_signoff) { + if ($signoff == 0) { + ERROR("MISSING_SIGN_OFF", + "Missing Signed-off-by: line(s)\n"); + } elsif (!$authorsignoff) { + WARN("NO_AUTHOR_SIGN_OFF", + "Missing Signed-off-by: line by nominal patch author '$author'\n"); + } + } + + print report_dump(); + if ($summary && !($clean == 1 && $quiet == 1)) { + print "$filename " if ($summary_file); + print "total: $cnt_error errors, $cnt_warn warnings, " . + (($check)? "$cnt_chk checks, " : "") . + "$cnt_lines lines checked\n"; + } + + if ($quiet == 0) { + # If there were any defects found and not already fixing them + if (!$clean and !$fix) { + print << "EOM" + +NOTE: For some of the reported defects, checkpatch may be able to + mechanically convert to the typical style using --fix or --fix-inplace. +EOM + } + # If there were whitespace errors which cleanpatch can fix + # then suggest that. + if ($rpt_cleaners) { + $rpt_cleaners = 0; + print << "EOM" + +NOTE: Whitespace errors detected. + You may wish to use scripts/cleanpatch or scripts/cleanfile +EOM + } + } + + if ($clean == 0 && $fix && + ("@rawlines" ne "@fixed" || + $#fixed_inserted >= 0 || $#fixed_deleted >= 0)) { + my $newfile = $filename; + $newfile .= ".EXPERIMENTAL-checkpatch-fixes" if (!$fix_inplace); + my $linecount = 0; + my $f; + + @fixed = fix_inserted_deleted_lines(\@fixed, \@fixed_inserted, \@fixed_deleted); + + open($f, '>', $newfile) + or die "$P: Can't open $newfile for write\n"; + foreach my $fixed_line (@fixed) { + $linecount++; + if ($file) { + if ($linecount > 3) { + $fixed_line =~ s/^\+//; + print $f $fixed_line . "\n"; + } + } else { + print $f $fixed_line . "\n"; + } + } + close($f); + + if (!$quiet) { + print << "EOM"; + +Wrote EXPERIMENTAL --fix correction(s) to '$newfile' + +Do _NOT_ trust the results written to this file. +Do _NOT_ submit these changes without inspecting them for correctness. + +This EXPERIMENTAL file is simply a convenience to help rewrite patches. +No warranties, expressed or implied... +EOM + } + } + + if ($quiet == 0) { + print "\n"; + if ($clean == 1) { + print "$vname has no obvious style problems and is ready for submission.\n"; + } else { + print "$vname has style problems, please review.\n"; + } + } + return $clean; +} diff --git a/tools/rimage/scripts/const_structs.checkpatch b/tools/rimage/scripts/const_structs.checkpatch new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tools/rimage/scripts/spelling.txt b/tools/rimage/scripts/spelling.txt new file mode 100644 index 000000000000..9a058cff49d4 --- /dev/null +++ b/tools/rimage/scripts/spelling.txt @@ -0,0 +1,1254 @@ +# Originally from Debian's Lintian tool. Various false positives have been +# removed, and various additions have been made as they've been discovered +# in the kernel source. +# +# License: GPLv2 +# +# The format of each line is: +# mistake||correction +# +abandonning||abandoning +abigious||ambiguous +abitrate||arbitrate +abov||above +abreviated||abbreviated +absense||absence +absolut||absolute +absoulte||absolute +acccess||access +acceess||access +acceleratoin||acceleration +accelleration||acceleration +accesing||accessing +accesnt||accent +accessable||accessible +accesss||access +accidentaly||accidentally +accidentually||accidentally +accoding||according +accomodate||accommodate +accomodates||accommodates +accordign||according +accoring||according +accout||account +accquire||acquire +accquired||acquired +accross||across +acessable||accessible +acess||access +achitecture||architecture +acient||ancient +acitions||actions +acitve||active +acknowldegement||acknowledgment +acknowledgement||acknowledgment +ackowledge||acknowledge +ackowledged||acknowledged +acording||according +activete||activate +actived||activated +actualy||actually +acumulating||accumulating +acumulator||accumulator +adapater||adapter +addional||additional +additionaly||additionally +additonal||additional +addres||address +adddress||address +addreses||addresses +addresss||address +aditional||additional +aditionally||additionally +aditionaly||additionally +adminstrative||administrative +adress||address +adresses||addresses +adviced||advised +afecting||affecting +againt||against +agaist||against +aggreataon||aggregation +aggreation||aggregation +albumns||albums +alegorical||allegorical +algined||aligned +algorith||algorithm +algorithmical||algorithmically +algoritm||algorithm +algoritms||algorithms +algorrithm||algorithm +algorritm||algorithm +aligment||alignment +alignement||alignment +allign||align +alligned||aligned +alllocate||allocate +alloated||allocated +allocatote||allocate +allocatrd||allocated +allocte||allocate +allpication||application +alocate||allocate +alogirhtms||algorithms +alogrithm||algorithm +alot||a lot +alow||allow +alows||allows +altough||although +alue||value +ambigious||ambiguous +amoung||among +amout||amount +an union||a union +an user||a user +an userspace||a userspace +an one||a one +analysator||analyzer +ang||and +anniversery||anniversary +annoucement||announcement +anomolies||anomalies +anomoly||anomaly +anway||anyway +aplication||application +appearence||appearance +applicaion||application +appliction||application +applictions||applications +applys||applies +appplications||applications +appropiate||appropriate +appropriatly||appropriately +approriate||appropriate +approriately||appropriately +apropriate||appropriate +aquainted||acquainted +aquired||acquired +aquisition||acquisition +arbitary||arbitrary +architechture||architecture +arguement||argument +arguements||arguments +aritmetic||arithmetic +arne't||aren't +arraival||arrival +artifical||artificial +artillary||artillery +asign||assign +asser||assert +assertation||assertion +assiged||assigned +assigment||assignment +assigments||assignments +assistent||assistant +assocation||association +associcated||associated +assotiated||associated +assum||assume +assumtpion||assumption +asuming||assuming +asycronous||asynchronous +asynchnous||asynchronous +atomatically||automatically +atomicly||atomically +atempt||attempt +attachement||attachment +attched||attached +attemps||attempts +attemping||attempting +attruibutes||attributes +authentification||authentication +automaticaly||automatically +automaticly||automatically +automatize||automate +automatized||automated +automatizes||automates +autonymous||autonomous +auxillary||auxiliary +auxilliary||auxiliary +avaiable||available +avaible||available +availabe||available +availabled||available +availablity||availability +availale||available +availavility||availability +availble||available +availiable||available +availible||available +avalable||available +avaliable||available +aysnc||async +backgroud||background +backword||backward +backwords||backwards +bahavior||behavior +bakup||backup +baloon||balloon +baloons||balloons +bandwith||bandwidth +banlance||balance +batery||battery +beacuse||because +becasue||because +becomming||becoming +becuase||because +beeing||being +befor||before +begining||beginning +beter||better +betweeen||between +bianries||binaries +bitmast||bitmask +boardcast||broadcast +borad||board +boundry||boundary +brievely||briefly +broadcat||broadcast +cacluated||calculated +caculation||calculation +calender||calendar +calescing||coalescing +calle||called +callibration||calibration +calucate||calculate +calulate||calculate +cancelation||cancellation +cancle||cancel +capabilites||capabilities +capabilty||capability +capabitilies||capabilities +capatibilities||capabilities +capapbilities||capabilities +carefuly||carefully +cariage||carriage +catagory||category +cehck||check +challange||challenge +challanges||challenges +chanell||channel +changable||changeable +chanined||chained +channle||channel +channnel||channel +charachter||character +charachters||characters +charactor||character +charater||character +charaters||characters +charcter||character +chcek||check +chck||check +checksuming||checksumming +childern||children +childs||children +chiled||child +chked||checked +chnage||change +chnages||changes +chnnel||channel +choosen||chosen +chouse||chose +circumvernt||circumvent +claread||cleared +clared||cleared +closeing||closing +clustred||clustered +coexistance||coexistence +collapsable||collapsible +colorfull||colorful +comand||command +comit||commit +commerical||commercial +comming||coming +comminucation||communication +commited||committed +commiting||committing +committ||commit +commoditiy||commodity +comsume||consume +comsumer||consumer +comsuming||consuming +compability||compatibility +compaibility||compatibility +compatability||compatibility +compatable||compatible +compatibiliy||compatibility +compatibilty||compatibility +compatiblity||compatibility +competion||completion +compilant||compliant +compleatly||completely +completition||completion +completly||completely +complient||compliant +componnents||components +compoment||component +compres||compress +compresion||compression +comression||compression +comunication||communication +conbination||combination +conditionaly||conditionally +conected||connected +connecetd||connected +configuartion||configuration +configuratoin||configuration +configuraton||configuration +configuretion||configuration +configutation||configuration +conider||consider +conjuction||conjunction +connectinos||connections +connnection||connection +connnections||connections +consistancy||consistency +consistant||consistent +containes||contains +containts||contains +contaisn||contains +contant||contact +contence||contents +continious||continuous +continous||continuous +continously||continuously +continueing||continuing +contraints||constraints +contol||control +contoller||controller +controled||controlled +controler||controller +controll||control +contruction||construction +contry||country +conuntry||country +convertion||conversion +convertor||converter +convienient||convenient +convinient||convenient +corected||corrected +correponding||corresponding +correponds||corresponds +correspoding||corresponding +cotrol||control +cound||could +couter||counter +coutner||counter +cryptocraphic||cryptographic +cunter||counter +curently||currently +cylic||cyclic +dafault||default +deafult||default +deamon||daemon +decompres||decompress +decription||description +dectected||detected +defailt||default +defferred||deferred +definate||definite +definately||definitely +defintion||definition +defintions||definitions +defualt||default +defult||default +deintializing||deinitializing +deintialize||deinitialize +deintialized||deinitialized +deivce||device +delared||declared +delare||declare +delares||declares +delaring||declaring +delemiter||delimiter +demodualtor||demodulator +demension||dimension +dependancies||dependencies +dependancy||dependency +dependant||dependent +depreacted||deprecated +depreacte||deprecate +desactivate||deactivate +desciptor||descriptor +desciptors||descriptors +descripton||description +descrition||description +descritptor||descriptor +desctiptor||descriptor +desriptor||descriptor +desriptors||descriptors +destionation||destination +destory||destroy +destoryed||destroyed +destorys||destroys +destroied||destroyed +detabase||database +deteced||detected +develope||develop +developement||development +developped||developed +developpement||development +developper||developer +developpment||development +deveolpment||development +devided||divided +deviece||device +diable||disable +dictionnary||dictionary +didnt||didn't +diferent||different +differrence||difference +diffrent||different +diffrentiate||differentiate +difinition||definition +dimesions||dimensions +diplay||display +direectly||directly +disassocation||disassociation +disapear||disappear +disapeared||disappeared +disappared||disappeared +disble||disable +disbled||disabled +disconnet||disconnect +discontinous||discontinuous +dispertion||dispersion +dissapears||disappears +distiction||distinction +docuentation||documentation +documantation||documentation +documentaion||documentation +documment||document +doesnt||doesn't +dorp||drop +dosen||doesn +downlad||download +downlads||downloads +druing||during +dynmaic||dynamic +easilly||easily +ecspecially||especially +edditable||editable +editting||editing +efective||effective +efficently||efficiently +ehther||ether +eigth||eight +elementry||elementary +eletronic||electronic +embeded||embedded +enabledi||enabled +enchanced||enhanced +encorporating||incorporating +encrupted||encrypted +encrypiton||encryption +encryptio||encryption +endianess||endianness +enhaced||enhanced +enlightnment||enlightenment +entrys||entries +enocded||encoded +enterily||entirely +enviroiment||environment +enviroment||environment +environement||environment +environent||environment +eqivalent||equivalent +equiped||equipped +equivelant||equivalent +equivilant||equivalent +eror||error +errorr||error +estbalishment||establishment +etsablishment||establishment +etsbalishment||establishment +excecutable||executable +exceded||exceeded +excellant||excellent +exeed||exceed +existance||existence +existant||existent +exixt||exist +exlcude||exclude +exlcusive||exclusive +exmaple||example +expecially||especially +explicite||explicit +explicitely||explicitly +explict||explicit +explictely||explicitly +explictly||explicitly +expresion||expression +exprimental||experimental +extened||extended +extensability||extensibility +extention||extension +extracter||extractor +falied||failed +faild||failed +faill||fail +failied||failed +faillure||failure +failue||failure +failuer||failure +failng||failing +faireness||fairness +falied||failed +faliure||failure +fallbck||fallback +familar||familiar +fatser||faster +feauture||feature +feautures||features +fetaure||feature +fetaures||features +fileystem||filesystem +fimware||firmware +firware||firmware +finanize||finalize +findn||find +finilizes||finalizes +finsih||finish +flusing||flushing +folloing||following +followign||following +followings||following +follwing||following +fonud||found +forseeable||foreseeable +forse||force +fortan||fortran +forwardig||forwarding +framming||framing +framwork||framework +frequncy||frequency +frome||from +fucntion||function +fuction||function +fuctions||functions +funcion||function +functionallity||functionality +functionaly||functionally +functionnality||functionality +functonality||functionality +funtion||function +funtions||functions +furthur||further +futhermore||furthermore +futrue||future +gaurenteed||guaranteed +generiously||generously +genereate||generate +genric||generic +globel||global +grabing||grabbing +grahical||graphical +grahpical||graphical +grapic||graphic +grranted||granted +guage||gauge +guarenteed||guaranteed +guarentee||guarantee +halfs||halves +hander||handler +handfull||handful +hanled||handled +happend||happened +harware||hardware +heirarchically||hierarchically +helpfull||helpful +hybernate||hibernate +hierachy||hierarchy +hierarchie||hierarchy +howver||however +hsould||should +hypervior||hypervisor +hypter||hyper +identidier||identifier +iligal||illegal +illigal||illegal +imblance||imbalance +immeadiately||immediately +immedaite||immediate +immediatelly||immediately +immediatly||immediately +immidiate||immediate +impelentation||implementation +impementated||implemented +implemantation||implementation +implemenation||implementation +implementaiton||implementation +implementated||implemented +implemention||implementation +implementd||implemented +implemetation||implementation +implemntation||implementation +implentation||implementation +implmentation||implementation +implmenting||implementing +incative||inactive +incomming||incoming +incompatabilities||incompatibilities +incompatable||incompatible +inconsistant||inconsistent +increas||increase +incremeted||incremented +incrment||increment +indendation||indentation +indended||intended +independant||independent +independantly||independently +independed||independent +indiate||indicate +indicat||indicate +inexpect||inexpected +infomation||information +informatiom||information +informations||information +informtion||information +infromation||information +ingore||ignore +inital||initial +initalized||initialized +initalised||initialized +initalise||initialize +initalize||initialize +initation||initiation +initators||initiators +initialiazation||initialization +initializiation||initialization +initialzed||initialized +initilization||initialization +initilize||initialize +inofficial||unofficial +insititute||institute +instal||install +instanciated||instantiated +inteface||interface +integreated||integrated +integrety||integrity +integrey||integrity +intendet||intended +intented||intended +interanl||internal +interchangable||interchangeable +interferring||interfering +interger||integer +intermittant||intermittent +internel||internal +interoprability||interoperability +interuupt||interrupt +interrface||interface +interrrupt||interrupt +interrup||interrupt +interrups||interrupts +interruptted||interrupted +interupted||interrupted +interupt||interrupt +intial||initial +intialisation||initialisation +intialised||initialised +intialise||initialise +intialization||initialization +intialized||initialized +intialize||initialize +intregral||integral +intrrupt||interrupt +intterrupt||interrupt +intuative||intuitive +invaid||invalid +invald||invalid +invalde||invalid +invalide||invalid +invalidiate||invalidate +invalud||invalid +invididual||individual +invokation||invocation +invokations||invocations +irrelevent||irrelevant +isnt||isn't +isssue||issue +iternations||iterations +itertation||iteration +itslef||itself +jave||java +jeffies||jiffies +juse||just +jus||just +kown||known +langage||language +langauage||language +langauge||language +langugage||language +lauch||launch +layed||laid +leightweight||lightweight +lengh||length +lenght||length +lenth||length +lesstiff||lesstif +libaries||libraries +libary||library +librairies||libraries +libraris||libraries +licenceing||licencing +loggging||logging +loggin||login +logile||logfile +loosing||losing +losted||lost +machinary||machinery +maintainance||maintenance +maintainence||maintenance +maintan||maintain +makeing||making +malplaced||misplaced +malplace||misplace +managable||manageable +managment||management +mangement||management +manoeuvering||maneuvering +mappping||mapping +mathimatical||mathematical +mathimatic||mathematic +mathimatics||mathematics +maxium||maximum +mechamism||mechanism +meetign||meeting +ment||meant +mergable||mergeable +mesage||message +messags||messages +messgaes||messages +messsage||message +messsages||messages +micropone||microphone +microprocesspr||microprocessor +milliseonds||milliseconds +minium||minimum +minimam||minimum +minumum||minimum +misalinged||misaligned +miscelleneous||miscellaneous +misformed||malformed +mispelled||misspelled +mispelt||misspelt +mising||missing +mismactch||mismatch +missmanaged||mismanaged +missmatch||mismatch +miximum||maximum +mmnemonic||mnemonic +mnay||many +modulues||modules +momery||memory +memomry||memory +monochorome||monochrome +monochromo||monochrome +monocrome||monochrome +mopdule||module +mroe||more +mulitplied||multiplied +multidimensionnal||multidimensional +multple||multiple +mumber||number +muticast||multicast +mutilcast||multicast +mutiple||multiple +mutli||multi +nams||names +navagating||navigating +nead||need +neccecary||necessary +neccesary||necessary +neccessary||necessary +necesary||necessary +neded||needed +negaive||negative +negoitation||negotiation +negotation||negotiation +nerver||never +nescessary||necessary +nessessary||necessary +noticable||noticeable +notications||notifications +notifed||notified +numebr||number +numner||number +obtaion||obtain +occassionally||occasionally +occationally||occasionally +occurance||occurrence +occurances||occurrences +occured||occurred +occurence||occurrence +occure||occurred +occured||occurred +occuring||occurring +offet||offset +omited||omitted +omiting||omitting +omitt||omit +ommiting||omitting +ommitted||omitted +onself||oneself +ony||only +operatione||operation +opertaions||operations +optionnal||optional +optmizations||optimizations +orientatied||orientated +orientied||oriented +orignal||original +otherise||otherwise +ouput||output +oustanding||outstanding +overaall||overall +overhread||overhead +overlaping||overlapping +overide||override +overrided||overridden +overriden||overridden +overun||overrun +overwritting||overwriting +overwriten||overwritten +pacakge||package +pachage||package +packacge||package +packege||package +packge||package +packtes||packets +pakage||package +pallette||palette +paln||plan +paramameters||parameters +paramaters||parameters +paramater||parameter +parametes||parameters +parametised||parametrised +paramter||parameter +paramters||parameters +particuarly||particularly +particularily||particularly +partiton||partition +pased||passed +passin||passing +pathes||paths +pecularities||peculiarities +peformance||performance +peice||piece +pendantic||pedantic +peprocessor||preprocessor +perfoming||performing +permissons||permissions +peroid||period +persistance||persistence +persistant||persistent +plalform||platform +platfrom||platform +plattform||platform +pleaes||please +ploting||plotting +plugable||pluggable +poinnter||pointer +pointeur||pointer +poiter||pointer +posible||possible +positon||position +possibilites||possibilities +powerfull||powerful +preample||preamble +preapre||prepare +preceeded||preceded +preceeding||preceding +preceed||precede +precendence||precedence +precission||precision +preemptable||preemptible +prefered||preferred +prefferably||preferably +premption||preemption +prepaired||prepared +pressre||pressure +primative||primitive +princliple||principle +priorty||priority +privilaged||privileged +privilage||privilege +priviledge||privilege +priviledges||privileges +probaly||probably +procceed||proceed +proccesors||processors +procesed||processed +proces||process +procesing||processing +processessing||processing +processess||processes +processpr||processor +processsed||processed +processsing||processing +procteted||protected +prodecure||procedure +progams||programs +progess||progress +programers||programmers +programm||program +programms||programs +progresss||progress +promiscous||promiscuous +promps||prompts +pronnounced||pronounced +prononciation||pronunciation +pronouce||pronounce +pronunce||pronounce +propery||property +propigate||propagate +propigation||propagation +propogate||propagate +prosess||process +protable||portable +protcol||protocol +protecion||protection +protocoll||protocol +promixity||proximity +psudo||pseudo +psuedo||pseudo +psychadelic||psychedelic +pwoer||power +quering||querying +randomally||randomly +raoming||roaming +reasearcher||researcher +reasearchers||researchers +reasearch||research +recepient||recipient +receving||receiving +recieved||received +recieve||receive +reciever||receiver +recieves||receives +recogniced||recognised +recognizeable||recognizable +recommanded||recommended +recyle||recycle +redircet||redirect +redirectrion||redirection +reename||rename +refcounf||refcount +refence||reference +refered||referred +referenace||reference +refering||referring +refernces||references +refernnce||reference +refrence||reference +registerd||registered +registeresd||registered +registerred||registered +registes||registers +registraration||registration +regsiter||register +regster||register +regualar||regular +reguator||regulator +regulamentations||regulations +reigstration||registration +releated||related +relevent||relevant +remoote||remote +remore||remote +removeable||removable +repectively||respectively +replacable||replaceable +replacments||replacements +replys||replies +reponse||response +representaion||representation +reqeust||request +requestied||requested +requiere||require +requirment||requirement +requred||required +requried||required +requst||request +reseting||resetting +resizeable||resizable +resouce||resource +resouces||resources +resoures||resources +responce||response +ressizes||resizes +ressource||resource +ressources||resources +retransmited||retransmitted +retreived||retrieved +retreive||retrieve +retrive||retrieve +retuned||returned +reudce||reduce +reuest||request +reuqest||request +reutnred||returned +revsion||revision +rmeoved||removed +rmeove||remove +rmeoves||removes +rountine||routine +routins||routines +rquest||request +runing||running +runned||ran +runnning||running +runtine||runtime +sacrifying||sacrificing +safly||safely +safty||safety +savable||saveable +scaned||scanned +scaning||scanning +scarch||search +seach||search +searchs||searches +secquence||sequence +secund||second +segement||segment +senarios||scenarios +sentivite||sensitive +separatly||separately +sepcify||specify +sepc||spec +seperated||separated +seperately||separately +seperate||separate +seperatly||separately +seperator||separator +sepperate||separate +sequece||sequence +sequencial||sequential +serveral||several +setts||sets +settting||setting +shotdown||shutdown +shoud||should +shouldnt||shouldn't +shoule||should +shrinked||shrunk +siginificantly||significantly +signabl||signal +similary||similarly +similiar||similar +simlar||similar +simliar||similar +simpified||simplified +singaled||signaled +singal||signal +singed||signed +sleeped||slept +softwares||software +speach||speech +specfic||specific +speciefied||specified +specifc||specific +specifed||specified +specificatin||specification +specificaton||specification +specifing||specifying +specifiying||specifying +speficied||specified +speicify||specify +speling||spelling +spinlcok||spinlock +spinock||spinlock +splitted||split +spreaded||spread +spurrious||spurious +sructure||structure +stablilization||stabilization +staically||statically +staion||station +standardss||standards +standartization||standardization +standart||standard +staticly||statically +stoped||stopped +stoppped||stopped +straming||streaming +struc||struct +structres||structures +stuct||struct +strucuture||structure +stucture||structure +sturcture||structure +subdirectoires||subdirectories +suble||subtle +substract||subtract +submition||submission +succesfully||successfully +succesful||successful +successed||succeeded +successfull||successful +successfuly||successfully +sucessfully||successfully +sucess||success +superflous||superfluous +superseeded||superseded +suplied||supplied +suported||supported +suport||support +supportet||supported +suppored||supported +supportin||supporting +suppoted||supported +suppported||supported +suppport||support +supress||suppress +surpressed||suppressed +surpresses||suppresses +susbsystem||subsystem +suspeneded||suspended +suspicously||suspiciously +swaping||swapping +switchs||switches +swith||switch +swithable||switchable +swithc||switch +swithced||switched +swithcing||switching +swithed||switched +swithing||switching +swtich||switch +symetric||symmetric +synax||syntax +synchonized||synchronized +syncronize||synchronize +syncronized||synchronized +syncronizing||synchronizing +syncronus||synchronous +syste||system +sytem||system +sythesis||synthesis +taht||that +targetted||targeted +targetting||targeting +teh||the +temorary||temporary +temproarily||temporarily +therfore||therefore +thier||their +threds||threads +threshhold||threshold +thresold||threshold +throught||through +troughput||throughput +thses||these +tiggered||triggered +tipically||typically +timout||timeout +tmis||this +torerable||tolerable +tramsmitted||transmitted +tramsmit||transmit +tranasction||transaction +tranfer||transfer +transciever||transceiver +transferd||transferred +transfered||transferred +transfering||transferring +transision||transition +transmittd||transmitted +transormed||transformed +trasfer||transfer +trasmission||transmission +treshold||threshold +trigerring||triggering +trun||turn +tunning||tuning +ture||true +tyep||type +udpate||update +uesd||used +uncommited||uncommitted +unconditionaly||unconditionally +underun||underrun +unecessary||unnecessary +unexecpted||unexpected +unexepected||unexpected +unexpcted||unexpected +unexpectd||unexpected +unexpeted||unexpected +unexpexted||unexpected +unfortunatelly||unfortunately +unifiy||unify +unintialized||uninitialized +unkmown||unknown +unknonw||unknown +unknow||unknown +unkown||unknown +unneded||unneeded +unneccecary||unnecessary +unneccesary||unnecessary +unneccessary||unnecessary +unnecesary||unnecessary +unneedingly||unnecessarily +unnsupported||unsupported +unmached||unmatched +unregester||unregister +unresgister||unregister +unrgesiter||unregister +unsinged||unsigned +unstabel||unstable +unsolicitied||unsolicited +unsuccessfull||unsuccessful +unsuported||unsupported +untill||until +unuseful||useless +upate||update +usefule||useful +usefull||useful +usege||usage +usera||users +usualy||usually +utilites||utilities +utillities||utilities +utilties||utilities +utiltity||utility +utitity||utility +utitlty||utility +vaid||valid +vaild||valid +valide||valid +variantions||variations +varible||variable +varient||variant +vaule||value +verbse||verbose +verisons||versions +verison||version +verson||version +vicefersa||vice-versa +virtal||virtual +virtaul||virtual +virtiual||virtual +visiters||visitors +vitual||virtual +wakeus||wakeups +wating||waiting +wiat||wait +wether||whether +whataver||whatever +whcih||which +whenver||whenever +wheter||whether +whe||when +wierd||weird +wiil||will +wirte||write +withing||within +wnat||want +workarould||workaround +writeing||writing +writting||writing +zombe||zombie +zomebie||zombie diff --git a/tools/rimage/src/adsp_config.c b/tools/rimage/src/adsp_config.c new file mode 100644 index 000000000000..ac196075a2b0 --- /dev/null +++ b/tools/rimage/src/adsp_config.c @@ -0,0 +1,2380 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski <karolx.trzcinski@linux.intel.com> + */ + +#include "rimage/sof/user/manifest.h" +#include "rimage/sof/user/manifest.h" +#include "rimage/adsp_config.h" +#include "rimage/ext_manifest_gen.h" +#include "rimage/plat_auth.h" +#include "rimage/manifest.h" +#include "rimage/rimage.h" +#include "rimage/cse.h" +#include "rimage/css.h" +#include "rimage/toml_utils.h" +#include "rimage/file_utils.h" +#include "toml.h" +#include <stdbool.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> + +/* map memory zone string name to enum value */ +static enum snd_sof_fw_blk_type zone_name_to_idx(const char *name) +{ + static const struct { + const char name[32]; + enum snd_sof_fw_blk_type type; + } mem_zone_name_dict[] = { + {"START", SOF_FW_BLK_TYPE_START}, + {"IRAM", SOF_FW_BLK_TYPE_IRAM}, + {"DRAM", SOF_FW_BLK_TYPE_DRAM}, + {"SRAM", SOF_FW_BLK_TYPE_SRAM}, + {"ROM", SOF_FW_BLK_TYPE_ROM}, + {"IMR", SOF_FW_BLK_TYPE_IMR}, + {"RSRVD0", SOF_FW_BLK_TYPE_RSRVD0}, + {"HP-SRAM", SOF_FW_BLK_TYPE_HPSRAM}, + {"LP-SRAM", SOF_FW_BLK_TYPE_LPSRAM}, + {"RSRVD8", SOF_FW_BLK_TYPE_RSRVD8}, + {"RSRVD9", SOF_FW_BLK_TYPE_RSRVD9}, + {"RSRVD10", SOF_FW_BLK_TYPE_RSRVD10}, + {"RSRVD11", SOF_FW_BLK_TYPE_RSRVD11}, + {"RSRVD12", SOF_FW_BLK_TYPE_RSRVD12}, + {"RSRVD13", SOF_FW_BLK_TYPE_RSRVD13}, + {"RSRVD14", SOF_FW_BLK_TYPE_RSRVD14}, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(mem_zone_name_dict); ++i) { + if (!strcmp(name, mem_zone_name_dict[i].name)) + return mem_zone_name_dict[i].type; + } + return SOF_FW_BLK_TYPE_INVALID; +} + +static void dump_adsp(const struct adsp *adsp) +{ + int i; + + DUMP("\nadsp"); + DUMP_KEY("name", "'%s'", adsp->name); + DUMP_KEY("image_size", "0x%x", adsp->image_size); + DUMP_KEY("exec_boot_ldr", "%d", adsp->exec_boot_ldr); + for (i = 0; i < ARRAY_SIZE(adsp->mem.zones); ++i) { + DUMP_KEY("mem_zone.idx", "%d", i); + DUMP_KEY("mem_zone.size", "0x%x", adsp->mem.zones[i].size); + DUMP_KEY("mem_zone.base", "0x%x", adsp->mem.zones[i].base); + DUMP_KEY("mem_zone.host_offset", "0x%x", adsp->mem.zones[i].host_offset); + } +} + +static int parse_adsp(const toml_table_t *toml, struct parse_ctx *pctx, struct adsp *out, + bool verbose) +{ + toml_array_t *mem_zone_array, *alias_array; + struct memory_zone *zone; + struct parse_ctx ctx; + toml_table_t *adsp; + toml_raw_t raw; + int zone_idx; + char a_kind; + int a_size; + bool alias_found; + int ret; + int i; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + adsp = toml_table_in(toml, "adsp"); + if (!adsp) + return err_key_not_found("adsp"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non-configurable fields */ + + /* configurable fields */ + raw = toml_raw_in(adsp, "name"); + if (!raw) + return err_key_not_found("name"); + ++ctx.key_cnt; + + /* free(out->name) is called in adsp_free() */ + ret = toml_rtos(raw, (char **)&out->name); + if (ret < 0) + return err_key_parse("name", NULL); + + out->image_size = parse_uint32_hex_key(adsp, &ctx, "image_size", 0, &ret); + if (ret < 0) + return ret; + + out->exec_boot_ldr = parse_uint32_key(adsp, &ctx, "exec_boot_ldr", 0, &ret); + if (ret < 0) + return ret; + + memset(&out->mem, 0, sizeof(out->mem)); + out->mem.alias.mask = parse_uint32_hex_key(adsp, &ctx, "alias_mask", -ENODATA, &ret); + alias_found = !ret; + + /* check everything parsed, 1 or 2 tables should be present */ + ctx.array_cnt += 1 + alias_found; + ret = assert_everything_parsed(adsp, &ctx); + if (ret < 0) + return ret; + + if (alias_found) { + alias_array = toml_array_in(adsp, "mem_alias"); + if (!alias_array) + return err_key_not_found("mem_alias"); + a_kind = toml_array_kind(alias_array); + a_size = toml_array_nelem(alias_array); + if (a_kind != 't' || a_size != 2) + return err_key_parse("mem_alias", "wrong array type %c or length %d", + a_kind, a_size); + + /* retrieve "cached" and "uncached" alias base addresses */ + for (i = 0; i < a_size; ++i) { + toml_table_t *alias = toml_table_at(alias_array, i); + char alias_name[16]; + uint32_t base; + + if (!alias) + return err_key_parse("mem_alias", NULL); + + parse_str_key(alias, &ctx, "type", alias_name, sizeof(alias_name), &ret); + if (ret < 0) + return err_key_parse("mem_alias", NULL); + + base = parse_uint32_hex_key(alias, &ctx, "base", -1, &ret); + + if (!strncmp("cached", alias_name, sizeof("cached"))) + out->mem.alias.cached = base & out->mem.alias.mask; + else if (!strncmp("uncached", alias_name, sizeof("uncached"))) + out->mem.alias.uncached = base & out->mem.alias.mask; + } + } else { + /* Make uncache_to_cache() an identity transform */ + out->mem.alias.uncached = 0; + out->mem.alias.cached = 0; + out->mem.alias.mask = 0; + } + + /* look for entry array */ + mem_zone_array = toml_array_in(adsp, "mem_zone"); + if (!mem_zone_array) + return err_key_not_found("mem_zone"); + a_kind = toml_array_kind(mem_zone_array); + a_size = toml_array_nelem(mem_zone_array); + if (a_kind != 't' || a_size > SOF_FW_BLK_TYPE_NUM) + return err_key_parse("mem_zone", "wrong array type %c or length %d", + a_kind, a_size); + + /* parse entry array elements */ + for (i = 0; i < a_size; ++i) { + toml_table_t *mem_zone = toml_table_at(mem_zone_array, i); + char zone_name[32]; + + if (!mem_zone) + return err_key_parse("mem_zone", NULL); + + /* initialize parse context for each array element */ + parse_ctx_init(&ctx); + + /* non-configurable fields */ + + /* configurable fields */ + parse_str_key(mem_zone, &ctx, "type", zone_name, sizeof(zone_name), &ret); + if (ret < 0) + return err_key_parse("mem_zone", NULL); + + zone_idx = zone_name_to_idx(zone_name); + if (zone_idx < 0) + return err_key_parse("mem_zone.name", "unknown zone '%s'", zone_name); + + zone = &out->mem.zones[zone_idx]; + zone->base = parse_uint32_hex_key(mem_zone, &ctx, "base", -1, &ret); + if (ret < 0) + return err_key_parse("mem_zone", NULL); + + zone->host_offset = parse_uint32_hex_key(mem_zone, &ctx, "host_offset", 0, + &ret); + if (ret < 0) + return err_key_parse("mem_zone", NULL); + + zone->size = parse_uint32_hex_key(mem_zone, &ctx, "size", -1, &ret); + if (ret < 0) + return err_key_parse("mem_zone", NULL); + + /* check everything parsed */ + ret = assert_everything_parsed(mem_zone, &ctx); + if (ret < 0) + return ret; + } + + if (verbose) + dump_adsp(out); + + /* + * values set in other places in code: + * - write_firmware + * - write_firmware_meu + * - man_vX_Y + */ + + return 0; +} + +static void dump_cse(const struct CsePartitionDirHeader *cse_header, + const struct CsePartitionDirEntry *cse_entry) +{ + int i; + + DUMP("\ncse"); + DUMP_PRINTABLE_BYTES("partition_name", cse_header->partition_name); + DUMP_KEY("header_version", "%d", cse_header->header_version); + DUMP_KEY("entry_version", "%d", cse_header->entry_version); + DUMP_KEY("nb_entries", "%d", cse_header->nb_entries); + for (i = 0; i < cse_header->nb_entries; ++i) { + DUMP_PRINTABLE_BYTES("entry.name", cse_entry[i].entry_name); + DUMP_KEY("entry.offset", "0x%x", cse_entry[i].offset); + DUMP_KEY("entry.length", "0x%x", cse_entry[i].length); + } +} + +static int parse_cse(const toml_table_t *toml, struct parse_ctx *pctx, + struct CsePartitionDirHeader *hdr, struct CsePartitionDirEntry *out, + int entry_capacity, bool verbose) +{ + toml_array_t *cse_entry_array; + toml_table_t *cse_entry; + struct parse_ctx ctx; + toml_table_t *cse; + int ret; + int i; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + cse = toml_table_in(toml, "cse"); + if (!cse) + return err_key_not_found("cse"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non-configurable fields */ + hdr->header_marker = CSE_HEADER_MAKER; + hdr->header_length = sizeof(struct CsePartitionDirHeader); + + /* configurable fields */ + hdr->header_version = parse_uint32_key(cse, &ctx, "header_version", 1, &ret); + if (ret < 0) + return ret; + + hdr->entry_version = parse_uint32_key(cse, &ctx, "entry_version", 1, &ret); + if (ret < 0) + return ret; + + parse_printable_key(cse, &ctx, "partition_name", hdr->partition_name, + sizeof(hdr->partition_name), &ret); + if (ret < 0) + return ret; + + /* check everything parsed, expect 1 table */ + ctx.array_cnt += 1; + ret = assert_everything_parsed(cse, &ctx); + if (ret < 0) + return ret; + + /* entry array */ + cse_entry_array = toml_array_in(cse, "entry"); + if (!cse_entry_array) + return err_key_not_found("entry"); + if (toml_array_kind(cse_entry_array) != 't' || + toml_array_nelem(cse_entry_array) != entry_capacity) + return err_key_parse("entry", "wrong array type or length != %d", entry_capacity); + + /* parse entry array elements */ + for (i = 0; i < toml_array_nelem(cse_entry_array); ++i) { + cse_entry = toml_table_at(cse_entry_array, i); + if (!cse_entry) + return err_key_parse("entry", NULL); + + /* initialize parse context for each array element */ + parse_ctx_init(&ctx); + + /* non-configurable fields */ + + /* configurable fields */ + parse_printable_key(cse_entry, &ctx, "name", out[i].entry_name, + sizeof(out[i].entry_name), &ret); + if (ret < 0) + return err_key_parse("entry", NULL); + + out[i].offset = parse_uint32_hex_key(cse_entry, &ctx, "offset", -1, &ret); + if (ret < 0) + return err_key_parse("entry", NULL); + + out[i].length = parse_uint32_hex_key(cse_entry, &ctx, "length", -1, &ret); + if (ret < 0) + return err_key_parse("entry", NULL); + + /* check everything parsed */ + ret = assert_everything_parsed(cse_entry, &ctx); + if (ret < 0) + return ret; + } + + hdr->nb_entries = toml_array_nelem(cse_entry_array); + + if (verbose) + dump_cse(hdr, out); + + /* + * values set in other places in code: + * - checksum + */ + + return 0; +} + +static void dump_cse_v2_5(const struct CsePartitionDirHeader_v2_5 *cse_header, + const struct CsePartitionDirEntry *cse_entry) +{ + int i; + + DUMP("\ncse"); + DUMP_PRINTABLE_BYTES("partition_name", cse_header->partition_name); + DUMP_KEY("header_version", "%d", cse_header->header_version); + DUMP_KEY("entry_version", "%d", cse_header->entry_version); + DUMP_KEY("nb_entries", "%d", cse_header->nb_entries); + for (i = 0; i < cse_header->nb_entries; ++i) { + DUMP_PRINTABLE_BYTES("entry.name", cse_entry[i].entry_name); + DUMP_KEY("entry.offset", "0x%x", cse_entry[i].offset); + DUMP_KEY("entry.length", "0x%x", cse_entry[i].length); + } +} + +/* TODO: fix up constants in headers for v2.5 */ +static int parse_cse_v2_5(const toml_table_t *toml, struct parse_ctx *pctx, + struct CsePartitionDirHeader_v2_5 *hdr, struct CsePartitionDirEntry *out, + int entry_capacity, bool verbose) +{ + toml_array_t *cse_entry_array; + toml_table_t *cse_entry; + struct parse_ctx ctx; + toml_table_t *cse; + int ret; + int i; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + cse = toml_table_in(toml, "cse"); + if (!cse) + return err_key_not_found("cse"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non-configurable fields */ + hdr->header_marker = CSE_HEADER_MAKER; + hdr->header_length = sizeof(struct CsePartitionDirHeader_v2_5); + + /* configurable fields */ + hdr->header_version = parse_uint32_key(cse, &ctx, "header_version", 2, &ret); + if (ret < 0) + return ret; + + hdr->entry_version = parse_uint32_key(cse, &ctx, "entry_version", 1, &ret); + if (ret < 0) + return ret; + + parse_printable_key(cse, &ctx, "partition_name", hdr->partition_name, + sizeof(hdr->partition_name), &ret); + if (ret < 0) + return ret; + + /* check everything parsed, expect 1 table */ + ctx.array_cnt += 1; + ret = assert_everything_parsed(cse, &ctx); + if (ret < 0) + return ret; + + /* entry array */ + cse_entry_array = toml_array_in(cse, "entry"); + if (!cse_entry_array) + return err_key_not_found("entry"); + if (toml_array_kind(cse_entry_array) != 't' || + toml_array_nelem(cse_entry_array) != entry_capacity) + return err_key_parse("entry", "wrong array type or length != %d", entry_capacity); + + /* parse entry array elements */ + for (i = 0; i < toml_array_nelem(cse_entry_array); ++i) { + cse_entry = toml_table_at(cse_entry_array, i); + if (!cse_entry) + return err_key_parse("entry", NULL); + + /* initialize parse context for each array element */ + parse_ctx_init(&ctx); + + /* non-configurable fields */ + + /* configurable fields */ + parse_printable_key(cse_entry, &ctx, "name", out[i].entry_name, + sizeof(out[i].entry_name), &ret); + if (ret < 0) + return err_key_parse("entry", NULL); + + out[i].offset = parse_uint32_hex_key(cse_entry, &ctx, "offset", -1, &ret); + if (ret < 0) + return err_key_parse("offset", NULL); + + out[i].length = parse_uint32_hex_key(cse_entry, &ctx, "length", -1, &ret); + if (ret < 0) + return err_key_parse("length", NULL); + + /* check everything parsed */ + ret = assert_everything_parsed(cse_entry, &ctx); + if (ret < 0) + return ret; + } + + hdr->nb_entries = toml_array_nelem(cse_entry_array); + + if (verbose) + dump_cse_v2_5(hdr, out); + + /* + * values set in other places in code: + * - checksum + */ + + return 0; +} + +static void dump_css_v1_5(const struct css_header_v1_5 *css) +{ + DUMP("\ncss 1.5"); + DUMP_KEY("module_type", "%d", css->module_type); + DUMP_KEY("header_len", "%d", css->header_len); + DUMP_KEY("header_version", "0x%x", css->header_version); + DUMP_KEY("module_vendor", "0x%x", css->module_vendor); + DUMP_KEY("size", "%d", css->size); + DUMP_KEY("key_size", "%d", css->key_size); + DUMP_KEY("modulus_size", "%d", css->modulus_size); + DUMP_KEY("exponent_size", "%d", css->exponent_size); +} + +static int parse_css_v1_5(const toml_table_t *toml, struct parse_ctx *pctx, + struct css_header_v1_5 *out, bool verbose) +{ + struct parse_ctx ctx; + toml_table_t *css; + int ret; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + css = toml_table_in(toml, "css"); + if (!css) + return err_key_not_found("css"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non-configurable fields */ + + /* configurable fields */ + out->module_type = parse_uint32_key(css, &ctx, "module_type", MAN_CSS_LT_MODULE_TYPE, &ret); + if (ret < 0) + return ret; + + out->header_len = parse_uint32_key(css, &ctx, "header_len", MAN_CSS_HDR_SIZE, &ret); + if (ret < 0) + return ret; + + out->header_version = parse_uint32_hex_key(css, &ctx, "header_version", MAN_CSS_HDR_VERSION, + &ret); + if (ret < 0) + return ret; + out->module_vendor = parse_uint32_hex_key(css, &ctx, "module_vendor", MAN_CSS_MOD_VENDOR, + &ret); + if (ret < 0) + return ret; + + out->size = parse_uint32_key(css, &ctx, "size", 0x800, &ret); + if (ret < 0) + return ret; + + out->key_size = parse_uint32_key(css, &ctx, "key_size", MAN_CSS_KEY_SIZE, &ret); + if (ret < 0) + return ret; + + out->modulus_size = parse_uint32_key(css, &ctx, "modulus_size", MAN_CSS_MOD_SIZE, &ret); + if (ret < 0) + return ret; + + out->exponent_size = parse_uint32_key(css, &ctx, "exponent_size", MAN_CSS_EXP_SIZE, &ret); + if (ret < 0) + return ret; + + /* check everything parsed */ + ret = assert_everything_parsed(css, &ctx); + if (ret < 0) + return ret; + + if (verbose) + dump_css_v1_5(out); + + /* + * values set in other places in code: + * - date + * - version + * - modulus + * - exponent + * - signature + */ + + return 0; +} + +static void dump_css_v1_8(const struct css_header_v1_8 *css) +{ + DUMP("\ncss 1.8"); + DUMP_KEY("header_type", "%d", css->header_type); + DUMP_KEY("header_len", "%d", css->header_len); + DUMP_KEY("header_version", "0x%x", css->header_version); + DUMP_KEY("module_vendor", "0x%x", css->module_vendor); + DUMP_KEY("size", "%d", css->size); + DUMP_KEY("svn", "%d", css->svn); + DUMP_KEY("modulus_size", "%d", css->modulus_size); + DUMP_KEY("exponent_size", "%d", css->exponent_size); +} + +static int parse_css_v1_8(const toml_table_t *toml, struct parse_ctx *pctx, + struct css_header_v1_8 *out, bool verbose) +{ + static const uint8_t hdr_id[4] = MAN_CSS_HDR_ID; + struct parse_ctx ctx; + toml_table_t *css; + int ret; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + css = toml_table_in(toml, "css"); + if (!css) + return err_key_not_found("css"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non-configurable fields */ + memcpy(out->header_id, hdr_id, sizeof(out->header_id)); + + /* configurable fields */ + out->header_type = parse_uint32_key(css, &ctx, "header_type", MAN_CSS_MOD_TYPE, &ret); + if (ret < 0) + return ret; + + out->header_len = parse_uint32_key(css, &ctx, "header_len", MAN_CSS_HDR_SIZE, &ret); + if (ret < 0) + return ret; + + out->header_version = parse_uint32_hex_key(css, &ctx, "header_version", MAN_CSS_HDR_VERSION, + &ret); + if (ret < 0) + return ret; + out->module_vendor = parse_uint32_hex_key(css, &ctx, "module_vendor", MAN_CSS_MOD_VENDOR, + &ret); + if (ret < 0) + return ret; + + out->size = parse_uint32_key(css, &ctx, "size", 222, &ret); + if (ret < 0) + return ret; + + out->svn = parse_uint32_key(css, &ctx, "svn", 0, &ret); + if (ret < 0) + return ret; + + out->modulus_size = parse_uint32_key(css, &ctx, "modulus_size", MAN_CSS_MOD_SIZE, &ret); + if (ret < 0) + return ret; + + out->exponent_size = parse_uint32_key(css, &ctx, "exponent_size", MAN_CSS_EXP_SIZE, &ret); + if (ret < 0) + return ret; + + /* check everything parsed */ + ret = assert_everything_parsed(css, &ctx); + if (ret < 0) + return ret; + + if (verbose) + dump_css_v1_8(out); + + /* + * values set in other places in code: + * - date + * - version + * - modulus + * - exponent + * - signature + */ + + return 0; +} + +static void dump_css_v2_5(const struct css_header_v2_5 *css) +{ + DUMP("\ncss 2.5"); + DUMP_KEY("header_type", "%d", css->header_type); + DUMP_KEY("header_len", "%d", css->header_len); + DUMP_KEY("header_version", "0x%x", css->header_version); + DUMP_KEY("module_vendor", "0x%x", css->module_vendor); + DUMP_KEY("size", "%d", css->size); + DUMP_KEY("svn", "%d", css->svn); + DUMP_KEY("modulus_size", "%d", css->modulus_size); + DUMP_KEY("exponent_size", "%d", css->exponent_size); +} + +static int parse_css_v2_5(const toml_table_t *toml, struct parse_ctx *pctx, + struct css_header_v2_5 *out, bool verbose) +{ + static const uint8_t hdr_id[4] = MAN_CSS_HDR_ID; + struct parse_ctx ctx; + toml_table_t *css; + int ret; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + css = toml_table_in(toml, "css"); + if (!css) + return err_key_not_found("css"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non-configurable fields */ + memcpy(out->header_id, hdr_id, sizeof(out->header_id)); + + /* configurable fields */ + out->header_type = parse_uint32_key(css, &ctx, "header_type", MAN_CSS_MOD_TYPE, &ret); + if (ret < 0) + return ret; + + out->header_len = parse_uint32_key(css, &ctx, "header_len", MAN_CSS_HDR_SIZE_2_5, &ret); + if (ret < 0) + return ret; + + out->header_version = parse_uint32_hex_key(css, &ctx, "header_version", MAN_CSS_HDR_VERSION_2_5, + &ret); + if (ret < 0) + return ret; + out->module_vendor = parse_uint32_hex_key(css, &ctx, "module_vendor", MAN_CSS_MOD_VENDOR, + &ret); + if (ret < 0) + return ret; + + out->size = parse_uint32_key(css, &ctx, "size", 281, &ret); + if (ret < 0) + return ret; + + out->svn = parse_uint32_key(css, &ctx, "svn", 0, &ret); + if (ret < 0) + return ret; + + out->modulus_size = parse_uint32_key(css, &ctx, "modulus_size", MAN_CSS_MOD_SIZE_2_5, &ret); + if (ret < 0) + return ret; + + out->exponent_size = parse_uint32_key(css, &ctx, "exponent_size", MAN_CSS_EXP_SIZE, &ret); + if (ret < 0) + return ret; + + /* hardcoded to align with meu */ + out->reserved1[0] = 0xf; + out->reserved1[1] = 0x048e0000; // TODO: what is this ? + + /* check everything parsed */ + ret = assert_everything_parsed(css, &ctx); + if (ret < 0) + return ret; + + if (verbose) + dump_css_v2_5(out); + + /* + * values set in other places in code: + * - date + * - version + * - modulus + * - exponent + * - signature + */ + + return 0; +} + +static void dump_signed_pkg(const struct signed_pkg_info_ext *signed_pkg) +{ + int i; + + DUMP("\nsigned_pkg"); + DUMP_PRINTABLE_BYTES("name", signed_pkg->name); + DUMP_KEY("vcn", "%d", signed_pkg->vcn); + DUMP_KEY("svn", "%d", signed_pkg->svn); + DUMP_KEY("fw_type", "%d", signed_pkg->fw_type); + DUMP_KEY("fw_sub_type", "%d", signed_pkg->fw_sub_type); + for (i = 0; i < ARRAY_SIZE(signed_pkg->bitmap); ++i) + DUMP_KEY("bitmap", "%d", signed_pkg->bitmap[i]); + for (i = 0; i < ARRAY_SIZE(signed_pkg->module); ++i) { + DUMP_PRINTABLE_BYTES("meta.name", signed_pkg->module[i].name); + DUMP_KEY("meta.type", "0x%x", signed_pkg->module[i].type); + DUMP_KEY("meta.hash_algo", "0x%x", signed_pkg->module[i].hash_algo); + DUMP_KEY("meta.hash_size", "0x%x", signed_pkg->module[i].hash_size); + DUMP_KEY("meta.meta_size", "%d", signed_pkg->module[i].meta_size); + } +} + +static int parse_signed_pkg(const toml_table_t *toml, struct parse_ctx *pctx, + struct image *image, bool verbose) +{ + struct adsp *adsp = image->adsp; + struct signed_pkg_info_ext *out = &adsp->man_v1_8->signed_pkg; + struct signed_pkg_info_module *mod; + toml_array_t *bitmap_array; + toml_array_t *module_array; + toml_table_t *signed_pkg; + struct parse_ctx ctx; + toml_table_t *module; + toml_raw_t raw; + int64_t temp_i; + int ret; + int i; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + signed_pkg = toml_table_in(toml, "signed_pkg"); + if (!signed_pkg) + return err_key_not_found("signed_pkg"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non-configurable fields */ + out->ext_type = SIGN_PKG_EXT_TYPE; + out->ext_len = sizeof(struct signed_pkg_info_ext); + + /* configurable fields */ + parse_printable_key(signed_pkg, &ctx, "name", out->name, sizeof(out->name), &ret); + if (ret < 0) + return ret; + + out->vcn = parse_uint32_key(signed_pkg, &ctx, "vcn", 0, &ret); + if (ret < 0) + return ret; + + out->svn = parse_uint32_key(signed_pkg, &ctx, "svn", 0, &ret); + if (ret < 0) + return ret; + + out->fw_type = parse_uint32_hex_key(signed_pkg, &ctx, "fw_type", 0, &ret); + if (ret < 0) + return ret; + + out->fw_sub_type = parse_uint32_hex_key(signed_pkg, &ctx, "fw_sub_type", 0, &ret); + if (ret < 0) + return ret; + + /* bitmap array */ + bitmap_array = toml_array_in(signed_pkg, "bitmap"); + if (!bitmap_array) { + /* default value, depending on the IMR type */ + out->bitmap[4] = image->imr_type == 4 ? 0x10 : 0x8; + } else { + ++ctx.array_cnt; + if (toml_array_kind(bitmap_array) != 'v' || toml_array_type(bitmap_array) != 'i' || + toml_array_nelem(bitmap_array) > ARRAY_SIZE(out->bitmap)) + return err_key_parse("bitmap", "wrong array type or length > %d", + ARRAY_SIZE(out->bitmap)); + + for (i = 0; i < toml_array_nelem(bitmap_array); ++i) { + raw = toml_raw_at(bitmap_array, i); + if (!raw) + return err_key_parse("bitmap", NULL); + + ret = toml_rtoi(raw, &temp_i); + if (ret < 0 || temp_i < 0) + return err_key_parse("bitmap", "values can't be negative"); + out->bitmap[i] = temp_i; + } + } + + /* check everything parsed, expect 1 more array */ + ctx.array_cnt += 1; + ret = assert_everything_parsed(signed_pkg, &ctx); + if (ret < 0) + return ret; + + /* modules array */ + module_array = toml_array_in(signed_pkg, "module"); + if (!module_array) + return err_key_not_found("module"); + if (toml_array_kind(module_array) != 't' || + toml_array_nelem(module_array) != ARRAY_SIZE(out->module)) + return err_key_parse("module", "wrong array type or length != %d", + ARRAY_SIZE(out->module)); + + /* parse modules array elements */ + for (i = 0; i < toml_array_nelem(module_array); ++i) { + module = toml_table_at(module_array, i); + if (!module) + return err_key_parse("module", NULL); + mod = &out->module[i]; + + /* initialize parse context for each array element */ + parse_ctx_init(&ctx); + + /* non-configurable fields */ + + /* configurable fields */ + parse_printable_key(module, &ctx, "name", mod->name, sizeof(mod->name), &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->type = parse_uint32_hex_key(module, &ctx, "type", 0x03, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->hash_algo = parse_uint32_hex_key(module, &ctx, "hash_algo", 0x02, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->hash_size = parse_uint32_hex_key(module, &ctx, "hash_size", 0x20, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->meta_size = parse_uint32_key(module, &ctx, "meta_size", 96, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + /* check everything parsed */ + ret = assert_everything_parsed(module, &ctx); + if (ret < 0) + return ret; + } + + if (verbose) + dump_signed_pkg(out); + + /* + * values set in other places in code: + * - module.hash + */ + + return 0; +} + +static void dump_signed_pkg_v2_5(const struct signed_pkg_info_ext_v2_5 *signed_pkg) +{ + int i; + + DUMP("\nsigned_pkg"); + DUMP_PRINTABLE_BYTES("name", signed_pkg->name); + DUMP_KEY("vcn", "%d", signed_pkg->vcn); + DUMP_KEY("svn", "%d", signed_pkg->svn); + DUMP_KEY("fw_type", "%d", signed_pkg->fw_type); + DUMP_KEY("fw_sub_type", "%d", signed_pkg->fw_sub_type); + for (i = 0; i < ARRAY_SIZE(signed_pkg->bitmap); ++i) + DUMP_KEY("bitmap", "%d", signed_pkg->bitmap[i]); + for (i = 0; i < ARRAY_SIZE(signed_pkg->module); ++i) { + DUMP_PRINTABLE_BYTES("meta.name", signed_pkg->module[i].name); + DUMP_KEY("meta.type", "0x%x", signed_pkg->module[i].type); + DUMP_KEY("meta.hash_algo", "0x%x", signed_pkg->module[i].hash_algo); + DUMP_KEY("meta.hash_size", "0x%x", signed_pkg->module[i].hash_size); + DUMP_KEY("meta.meta_size", "%d", signed_pkg->module[i].meta_size); + } +} + +static int parse_signed_pkg_v2_5(const toml_table_t *toml, struct parse_ctx *pctx, + struct image *image, bool verbose) +{ + struct adsp *adsp = image->adsp; + struct signed_pkg_info_ext_v2_5 *out = &adsp->man_v2_5->signed_pkg; + struct signed_pkg_info_module_v2_5 *mod; + toml_array_t *bitmap_array; + toml_array_t *module_array; + toml_table_t *signed_pkg; + struct parse_ctx ctx; + toml_table_t *module; + toml_raw_t raw; + int64_t temp_i; + int ret; + int i; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + signed_pkg = toml_table_in(toml, "signed_pkg"); + if (!signed_pkg) + return err_key_not_found("signed_pkg"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non-configurable fields */ + out->ext_type = SIGN_PKG_EXT_TYPE; + out->ext_len = sizeof(struct signed_pkg_info_ext_v2_5); + + /* configurable fields */ + parse_printable_key(signed_pkg, &ctx, "name", out->name, sizeof(out->name), &ret); + if (ret < 0) + return ret; + + out->vcn = parse_uint32_key(signed_pkg, &ctx, "vcn", 0, &ret); + if (ret < 0) + return ret; + + out->svn = parse_uint32_key(signed_pkg, &ctx, "svn", 0, &ret); + if (ret < 0) + return ret; + + out->fw_type = parse_uint32_hex_key(signed_pkg, &ctx, "fw_type", 0, &ret); + if (ret < 0) + return ret; + + out->fw_sub_type = parse_uint32_hex_key(signed_pkg, &ctx, "fw_sub_type", 0, &ret); + if (ret < 0) + return ret; + + /* bitmap array */ + bitmap_array = toml_array_in(signed_pkg, "bitmap"); + if (!bitmap_array) { + /* default value, depending on the IMR type */ + out->bitmap[4] = image->imr_type == 4 ? 0x10 : 0x8; + } else { + ++ctx.array_cnt; + if (toml_array_kind(bitmap_array) != 'v' || toml_array_type(bitmap_array) != 'i' || + toml_array_nelem(bitmap_array) > ARRAY_SIZE(out->bitmap)) + return err_key_parse("bitmap", "wrong array type or length > %d", + ARRAY_SIZE(out->bitmap)); + + for (i = 0; i < toml_array_nelem(bitmap_array); ++i) { + raw = toml_raw_at(bitmap_array, i); + if (!raw) + return err_key_parse("bitmap", NULL); + + ret = toml_rtoi(raw, &temp_i); + if (ret < 0 || temp_i < 0) + return err_key_parse("bitmap", "values can't be negative"); + out->bitmap[i] = temp_i; + } + } + + /* check everything parsed, expect 1 more array */ + ctx.array_cnt += 1; + ret = assert_everything_parsed(signed_pkg, &ctx); + if (ret < 0) + return ret; + + /* modules array */ + module_array = toml_array_in(signed_pkg, "module"); + if (!module_array) + return err_key_not_found("module"); + if (toml_array_kind(module_array) != 't' || + toml_array_nelem(module_array) != ARRAY_SIZE(out->module)) + return err_key_parse("module", "wrong array type or length != %d", + ARRAY_SIZE(out->module)); + + /* parse modules array elements */ + for (i = 0; i < toml_array_nelem(module_array); ++i) { + module = toml_table_at(module_array, i); + if (!module) + return err_key_parse("module", NULL); + mod = &out->module[i]; + + /* initialize parse context for each array element */ + parse_ctx_init(&ctx); + + /* non-configurable fields */ + + /* configurable fields */ + parse_printable_key(module, &ctx, "name", mod->name, sizeof(mod->name), &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->type = parse_uint32_hex_key(module, &ctx, "type", 0x03, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->hash_algo = parse_uint32_hex_key(module, &ctx, "hash_algo", 0x00, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->hash_size = parse_uint32_hex_key(module, &ctx, "hash_size", 0x30, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->meta_size = parse_uint32_key(module, &ctx, "meta_size", 112, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + /* check everything parsed */ + ret = assert_everything_parsed(module, &ctx); + if (ret < 0) + return ret; + } + + if (verbose) + dump_signed_pkg_v2_5(out); + + /* + * values set in other places in code: + * - module.hash + */ + + return 0; +} + +static void dump_signed_pkg_ace_v1_5(const struct signed_pkg_info_ext_ace_v1_5 *signed_pkg) +{ + int i; + + DUMP("\nsigned_pkg"); + DUMP_KEY("name", "'%s'", signed_pkg->name); + DUMP_KEY("vcn", "%d", signed_pkg->vcn); + DUMP_KEY("svn", "%d", signed_pkg->svn); + DUMP_KEY("fw_type", "%d", signed_pkg->fw_type); + DUMP_KEY("fw_sub_type", "%d", signed_pkg->fw_sub_type); + for (i = 0; i < ARRAY_SIZE(signed_pkg->module); ++i) { + DUMP_KEY("meta.name", "'%s'", signed_pkg->module[i].name); + DUMP_KEY("meta.type", "0x%x", signed_pkg->module[i].type); + } +} + +static int parse_signed_pkg_ace_v1_5(const toml_table_t *toml, struct parse_ctx *pctx, + struct image *image, bool verbose) +{ + struct adsp *adsp = image->adsp; + struct signed_pkg_info_ext_ace_v1_5 *out = &adsp->man_ace_v1_5->signed_pkg; + struct signed_pkg_info_module_ace_v1_5 *mod; + toml_array_t *module_array; + toml_table_t *signed_pkg; + struct parse_ctx ctx; + toml_table_t *module; + int ret; + int i; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + signed_pkg = toml_table_in(toml, "signed_pkg"); + if (!signed_pkg) + return err_key_not_found("signed_pkg"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non-configurable fields */ + out->ext_type = SIGN_PKG_EXT_TYPE_ACE_V1_5; + out->ext_len = sizeof(struct signed_pkg_info_ext_ace_v1_5); + + /* configurable fields */ + parse_printable_key(signed_pkg, &ctx, "name", out->name, sizeof(out->name), &ret); + if (ret < 0) + return ret; + + out->vcn = parse_uint32_key(signed_pkg, &ctx, "vcn", 0, &ret); + if (ret < 0) + return ret; + + out->svn = parse_uint32_key(signed_pkg, &ctx, "svn", 0, &ret); + if (ret < 0) + return ret; + + out->fw_type = parse_uint32_hex_key(signed_pkg, &ctx, "fw_type", 0, &ret); + if (ret < 0) + return ret; + + out->fw_sub_type = parse_uint32_hex_key(signed_pkg, &ctx, "fw_sub_type", 0, &ret); + if (ret < 0) + return ret; + + out->partition_usage = parse_uint32_hex_key(signed_pkg, &ctx, "partition_usage", 0, &ret); + if (ret < 0) + return ret; + + /* check everything parsed, expect 1 more array */ + ctx.array_cnt += 1; + ret = assert_everything_parsed(signed_pkg, &ctx); + if (ret < 0) + return ret; + + /* modules array */ + module_array = toml_array_in(signed_pkg, "module"); + if (!module_array) + return err_key_not_found("module"); + if (toml_array_kind(module_array) != 't' || + toml_array_nelem(module_array) != ARRAY_SIZE(out->module)) + return err_key_parse("module", "wrong array type or length != %d", + ARRAY_SIZE(out->module)); + + /* parse modules array elements */ + for (i = 0; i < toml_array_nelem(module_array); ++i) { + module = toml_table_at(module_array, i); + if (!module) + return err_key_parse("module", NULL); + mod = &out->module[i]; + + /* initialize parse context for each array element */ + parse_ctx_init(&ctx); + + /* non-configurable fields */ + + /* configurable fields */ + parse_printable_key(module, &ctx, "name", mod->name, sizeof(mod->name), &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->type = parse_uint32_hex_key(module, &ctx, "type", 0x03, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->hash_algo = parse_uint32_hex_key(module, &ctx, "hash_algo", 0x00, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->meta_size = parse_uint32_key(module, &ctx, "meta_size", 112, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + /* check everything parsed */ + ret = assert_everything_parsed(module, &ctx); + if (ret < 0) + return ret; + } + + if (verbose) + dump_signed_pkg_ace_v1_5(out); + + /* + * values set in other places in code: + * - module.hash + */ + + return 0; +} + +static void dump_partition_info_ext(const struct partition_info_ext *part_info) +{ + int i; + + DUMP("\npartition_info"); + DUMP_PRINTABLE_BYTES("name", part_info->name); + DUMP_KEY("part_version", "0x%x", part_info->part_version); + DUMP_KEY("instance_id", "%d", part_info->instance_id); + for (i = 0; i < ARRAY_SIZE(part_info->module); ++i) { + DUMP_PRINTABLE_BYTES("module.name", part_info->module[i].name); + DUMP_KEY("module.meta_size", "0x%x", part_info->module[i].meta_size); + DUMP_KEY("module.type", "0x%x", part_info->module[i].type); + } +} + +static int parse_partition_info_ext(const toml_table_t *toml, struct parse_ctx *pctx, + struct partition_info_ext *out, bool verbose) +{ + static const uint8_t module_reserved[3] = {0x00, 0xff, 0xff}; + struct partition_info_module *mod; + toml_table_t *partition_info; + toml_array_t *module_array; + toml_table_t *module; + struct parse_ctx ctx; + int ret; + int i; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + partition_info = toml_table_in(toml, "partition_info"); + if (!partition_info) + return err_key_not_found("partition_info"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non-configurable fields */ + out->ext_type = PART_INFO_EXT_TYPE; + out->ext_len = sizeof(struct partition_info_ext); + memset(out->reserved, 0xff, sizeof(out->reserved)); + + /* configurable fields */ + parse_printable_key(partition_info, &ctx, "name", out->name, sizeof(out->name), &ret); + if (ret < 0) + return ret; + + out->vcn = parse_uint32_key(partition_info, &ctx, "vcn", 0, &ret); + if (ret < 0) + return ret; + + out->part_version = + parse_uint32_hex_key(partition_info, &ctx, "part_version", 0x10000000, &ret); + if (ret < 0) + return ret; + + out->vcn = parse_uint32_hex_key(partition_info, &ctx, "part_version", 0x10000000, &ret); + if (ret < 0) + return ret; + + out->vcn = parse_uint32_hex_key(partition_info, &ctx, "fmt_version", 0, &ret); + if (ret < 0) + return ret; + + out->instance_id = parse_uint32_key(partition_info, &ctx, "instance_id", 1, &ret); + if (ret < 0) + return ret; + + out->part_flags = parse_uint32_key(partition_info, &ctx, "part_flags", 0, &ret); + if (ret < 0) + return ret; + + /* check everything parsed, expect 1 array */ + ctx.array_cnt += 1; + ret = assert_everything_parsed(partition_info, &ctx); + if (ret < 0) + return ret; + + /* look for module array */ + module_array = toml_array_in(partition_info, "module"); + if (!module_array) + return err_key_not_found("module"); + if (toml_array_kind(module_array) != 't' || + toml_array_nelem(module_array) > ARRAY_SIZE(out->module)) + return err_key_parse("module", "wrong array type or length > %d", + ARRAY_SIZE(out->module)); + + /* parse module array elements */ + for (i = 0; i < toml_array_nelem(module_array); ++i) { + module = toml_table_at(module_array, i); + if (!module) + return err_key_parse("module", NULL); + mod = &out->module[i]; + + /* initialize parse context for each array element */ + parse_ctx_init(&ctx); + + /* non-configurable fields */ + memcpy(mod->reserved, module_reserved, sizeof(mod->reserved)); + + /* configurable fields */ + parse_printable_key(module, &ctx, "name", mod->name, sizeof(mod->name), &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->meta_size = parse_uint32_key(module, &ctx, "meta_size", 96, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + mod->type = parse_uint32_hex_key(module, &ctx, "type", 0x03, &ret); + if (ret < 0) + return err_key_parse("module", NULL); + + /* check everything parsed */ + ret = assert_everything_parsed(module, &ctx); + if (ret < 0) + return ret; + } + + if (verbose) + dump_partition_info_ext(out); + + /* + * values set in other places in code: + * - length + * - hash + * - module.hash + */ + + return 0; +} + +static int parse_info_ext_0x16(const toml_table_t *toml, struct parse_ctx *pctx, + struct info_ext_0x16 *out, bool verbose) +{ + /* known */ + out->ext_type = 0x16; + out->ext_len = sizeof(*out); + out->name[0] = 'A'; + out->name[1] = 'D'; + out->name[2] = 'S'; + out->name[3] = 'P'; + + /* copied from meu - unknown */ + out->data[0] = 0x10000000; + out->data[2] = 0x1; + out->data[3] = 0x0; + out->data[4] = 0x3003; + + return 0; +} + +static void dump_adsp_file_ext_v1_8(const struct sof_man_adsp_meta_file_ext_v1_8 *adsp_file) +{ + int i; + int j; + + DUMP("\nadsp_file_ext 1.8"); + DUMP_KEY("imr_type", "0x%x", adsp_file->imr_type); + for (i = 0; i < ARRAY_SIZE(adsp_file->comp_desc); ++i) { + DUMP_KEY("comp.version", "0x%x", adsp_file->comp_desc[i].version); + DUMP_KEY("comp.base_offset", "0x%x", adsp_file->comp_desc[i].base_offset); + for (j = 0; j < ARRAY_SIZE(adsp_file->comp_desc->attributes); ++j) + DUMP_KEY("comp.atributes[]", "%d", adsp_file->comp_desc[i].attributes[j]); + } +} + +static int parse_adsp_file_ext_v1_8(const toml_table_t *toml, struct parse_ctx *pctx, + struct sof_man_adsp_meta_file_ext_v1_8 *out, bool verbose) +{ + struct sof_man_component_desc_v1_8 *desc; + toml_array_t *attributes_array; + toml_table_t *adsp_file_ext; + toml_array_t *comp_array; + struct parse_ctx ctx; + toml_raw_t attribute; + toml_table_t *comp; + int64_t temp_i; + int ret; + int i; + int j; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + adsp_file_ext = toml_table_in(toml, "adsp_file"); + if (!adsp_file_ext) + return err_key_not_found("adsp_file"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non configurable flieds */ + out->ext_type = 17; /* always 17 for ADSP extension */ + out->ext_len = sizeof(struct sof_man_adsp_meta_file_ext_v1_8); + + /* configurable fields */ + out->imr_type = parse_uint32_hex_key(adsp_file_ext, &ctx, "imr_type", + MAN_DEFAULT_IMR_TYPE, &ret); + if (ret < 0) + return ret; + + /* check everything parsed, expect 1 array */ + ctx.array_cnt += 1; + ret = assert_everything_parsed(adsp_file_ext, &ctx); + if (ret < 0) + return ret; + + /* parse comp array */ + comp_array = toml_array_in(adsp_file_ext, "comp"); + if (!comp_array) + return err_key_not_found("comp"); + if (toml_array_nelem(comp_array) != 1 || toml_array_kind(comp_array) != 't') + return err_key_parse("comp", "wrong array type or length != 1"); + + /* parse comp array elements */ + for (i = 0; i < toml_array_nelem(comp_array); ++i) { + comp = toml_table_at(comp_array, i); + if (!comp) + return err_key_parse("comp", NULL); + desc = &out->comp_desc[i]; + + /* initialize parse context for each array element */ + parse_ctx_init(&ctx); + + /* non-configurable fields */ + + /* configurable fields */ + desc->version = parse_uint32_key(comp, &ctx, "version", 0, &ret); + if (ret < 0) + return err_key_parse("comp", NULL); + + desc->base_offset = parse_uint32_hex_key(comp, &ctx, "base_offset", + MAN_DESC_OFFSET_V1_8, &ret); + if (ret < 0) + return err_key_parse("comp", NULL); + + /* parse attributes array */ + attributes_array = toml_array_in(comp, "attributes"); + if (attributes_array) { + ++ctx.array_cnt; + if (toml_array_nelem(attributes_array) > ARRAY_SIZE(desc->attributes) || + toml_array_kind(attributes_array) != 'v' || + toml_array_type(attributes_array) != 'i') + return err_key_parse("comp.attributes", + "wrong array type or length > %d", + ARRAY_SIZE(desc->attributes)); + for (j = 0; j < toml_array_nelem(attributes_array); ++j) { + attribute = toml_raw_at(attributes_array, j); + if (!attribute) + err_key_parse("comp.attributes", NULL); + ret = toml_rtoi(attribute, &temp_i); + if (ret < 0 || temp_i < 0 || temp_i > UINT32_MAX) + err_key_parse("comp.attributes", NULL); + desc->attributes[j] = (uint32_t)temp_i; + } + } + + /* check everything parsed */ + ret = assert_everything_parsed(comp, &ctx); + if (ret < 0) + return ret; + } + + if (verbose) + dump_adsp_file_ext_v1_8(out); + + /* + * values set in other places in code: + * - imr_type + * - comp.limit_offset + */ + + return 0; +} + +static void dump_adsp_file_ext_v2_5(const struct sof_man_adsp_meta_file_ext_v2_5 *adsp_file) +{ + int i; + int j; + + DUMP("\nadsp_file 2.5"); + DUMP_KEY("imr_type", "0x%x", adsp_file->imr_type); + for (i = 0; i < ARRAY_SIZE(adsp_file->comp_desc); ++i) { + DUMP_KEY("comp.version", "0x%x", adsp_file->comp_desc[i].version); + DUMP_KEY("comp.base_offset", "0x%x", adsp_file->comp_desc[i].base_offset); + for (j = 0; j < ARRAY_SIZE(adsp_file->comp_desc->attributes); ++j) + DUMP_KEY("comp.atributes[]", "%d", adsp_file->comp_desc[i].attributes[j]); + } +} + +static int parse_adsp_file_ext_v2_5(const toml_table_t *toml, struct parse_ctx *pctx, + struct sof_man_adsp_meta_file_ext_v2_5 *out, bool verbose) +{ + struct sof_man_component_desc_v2_5 *desc; + toml_array_t *attributes_array; + toml_table_t *adsp_file_ext; + toml_array_t *comp_array; + struct parse_ctx ctx; + toml_raw_t attribute; + toml_table_t *comp; + int64_t temp_i; + int ret; + int i; + int j; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + adsp_file_ext = toml_table_in(toml, "adsp_file"); + if (!adsp_file_ext) + return err_key_not_found("adsp_file"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + /* non configurable flieds */ + out->ext_type = 17; /* always 17 for ADSP extension */ + out->ext_len = sizeof(struct sof_man_adsp_meta_file_ext_v2_5); + + /* configurable fields */ + out->imr_type = parse_uint32_hex_key(adsp_file_ext, &ctx, "imr_type", + MAN_DEFAULT_IMR_TYPE, &ret); + if (ret < 0) + return ret; + + /* check everything parsed, expect 1 array */ + ctx.array_cnt += 1; + ret = assert_everything_parsed(adsp_file_ext, &ctx); + if (ret < 0) + return ret; + + /* parse comp array */ + comp_array = toml_array_in(adsp_file_ext, "comp"); + if (!comp_array) + return err_key_not_found("comp"); + if (toml_array_nelem(comp_array) != 1 || toml_array_kind(comp_array) != 't') + return err_key_parse("comp", "wrong array type or length != 1"); + + /* parse comp array elements */ + for (i = 0; i < toml_array_nelem(comp_array); ++i) { + comp = toml_table_at(comp_array, i); + if (!comp) + return err_key_parse("comp", NULL); + desc = &out->comp_desc[i]; + + /* initialize parse context for each array element */ + parse_ctx_init(&ctx); + + /* non configurable flieds */ + + /* configurable fields */ + desc->version = parse_uint32_key(comp, &ctx, "version", 0, &ret); + if (ret < 0) + return err_key_parse("comp", NULL); + + desc->base_offset = parse_uint32_hex_key(comp, &ctx, "base_offset", 0x2000, &ret); + if (ret < 0) + return err_key_parse("comp", NULL); + + /* parse attributes array */ + attributes_array = toml_array_in(comp, "attributes"); + if (attributes_array) { + ++ctx.array_cnt; + if (toml_array_nelem(attributes_array) > ARRAY_SIZE(desc->attributes) || + toml_array_kind(attributes_array) != 'v' || + toml_array_type(attributes_array) != 'i') + return err_key_parse("comp.attributes", + "wrong array type or length > %d", + ARRAY_SIZE(desc->attributes)); + for (j = 0; j < toml_array_nelem(attributes_array); ++j) { + attribute = toml_raw_at(attributes_array, j); + if (!attribute) + err_key_parse("comp.attributes", NULL); + ret = toml_rtoi(attribute, &temp_i); + if (ret < 0 || temp_i < 0 || temp_i > UINT32_MAX) + err_key_parse("comp.attributes", NULL); + desc->attributes[j] = (uint32_t)temp_i; + } + } + + /* check everything parsed */ + ret = assert_everything_parsed(comp, &ctx); + if (ret < 0) + return ret; + } + + if (verbose) + dump_adsp_file_ext_v2_5(out); + + /* + * values set in other places in code: + * - imr_type + * - comp.limit_offset + */ + + return 0; +} + +static void dump_fw_desc(const struct sof_man_fw_desc *fw_desc) +{ + DUMP("\nfw_desc.header"); + DUMP_KEY("header_id", "'%c%c%c%c'", fw_desc->header.header_id[0], + fw_desc->header.header_id[1], fw_desc->header.header_id[2], + fw_desc->header.header_id[3]); + DUMP_PRINTABLE_BYTES("name", fw_desc->header.name); + DUMP_KEY("preload_page_count", "%d", fw_desc->header.preload_page_count); + DUMP_KEY("fw_image_flags", "0x%x", fw_desc->header.fw_image_flags); + DUMP_KEY("feature_mask", "0x%x", fw_desc->header.feature_mask); + DUMP_KEY("hw_buf_base_addr", "0x%x", fw_desc->header.fw_compat); + DUMP_KEY("hw_buf_length", "0x%x", fw_desc->header.hw_buf_length); + DUMP_KEY("load_offset", "0x%x", fw_desc->header.load_offset); +} + +static int parse_fw_desc(const toml_table_t *toml, struct parse_ctx *pctx, + struct sof_man_fw_desc *out, bool verbose) +{ + static const uint8_t header_id[4] = SOF_MAN_FW_HDR_ID; + struct parse_ctx ctx; + toml_table_t *header; + toml_table_t *desc; + int ret; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + desc = toml_table_in(toml, "fw_desc"); + if (!desc) + return err_key_not_found("fw_desc"); + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + header = toml_table_in(desc, "header"); + if (!header) + return err_key_not_found("header"); + ++ctx.table_cnt; + + /* check everything parsed */ + ret = assert_everything_parsed(desc, &ctx); + if (ret < 0) + return ret; + + /* initialize parser context for header subtable */ + parse_ctx_init(&ctx); + + /* non configurable flieds */ + memcpy(&out->header.header_id, header_id, sizeof(header_id)); + out->header.header_len = sizeof(struct sof_man_fw_header); + + /* configurable fields */ + parse_printable_key(header, &ctx, "name", out->header.name, sizeof(out->header.name), + &ret); + if (ret < 0) + return err_key_parse("header", NULL); + + out->header.preload_page_count = + parse_uint32_key(header, &ctx, "preload_page_count", 0, &ret); + if (ret < 0) + return err_key_parse("header", NULL); + + out->header.fw_image_flags = + parse_uint32_hex_key(header, &ctx, "fw_image_flags", SOF_MAN_FW_HDR_FLAGS, &ret); + if (ret < 0) + return err_key_parse("header", NULL); + + out->header.feature_mask = + parse_uint32_hex_key(header, &ctx, "feature_mask", SOF_MAN_FW_HDR_FEATURES, &ret); + if (ret < 0) + return err_key_parse("header", NULL); + + out->header.fw_compat = + parse_uint32_hex_key(header, &ctx, "hw_buf_base_addr", 0, &ret); + if (ret < 0) + return err_key_parse("header", NULL); + + out->header.hw_buf_length = parse_uint32_hex_key(header, &ctx, "hw_buf_length", 0, &ret); + if (ret < 0) + return err_key_parse("header", NULL); + + out->header.load_offset = parse_uint32_hex_key(header, &ctx, "load_offset", -1, &ret); + if (ret < 0) + return err_key_parse("header", NULL); + + /* check everything parsed */ + ret = assert_everything_parsed(header, &ctx); + if (ret < 0) + return ret; + + if (verbose) + dump_fw_desc(out); + + /* + * values set in other places in code: + * - major_version + * - minor_version + * - build_version + * - num_module_entries + */ + + return 0; +} + +static int parse_scheduling(const toml_table_t *mod_entry, struct parse_ctx *ctx, + struct fw_image_ext_mod_config *ext_mod_config, int *ext_length) +{ + toml_array_t *arr; + toml_raw_t raw; + int64_t val; + int ret; + + /* check "sched_caps" key */ + arr = toml_array_in(mod_entry, "sched_caps"); + if (!arr) { + ext_mod_config->header.num_scheduling_capabilities = 0; + *ext_length = 0; + return 0; + } + + if (toml_array_type(arr) != 'i' || toml_array_nelem(arr) != 2 || + toml_array_kind(arr) != 'v') + return err_key_parse("sched_caps", "wrong array type or length != 2"); + + ctx->array_cnt++; + + raw = toml_raw_at(arr, 0); + if (raw == 0) + return err_key_parse("frame_length", NULL); + ret = toml_rtoi(raw, &val); + if (ret < 0) + return err_key_parse("frame_length", "can't convert element to integer"); + ext_mod_config->sched_caps.frame_length = val; + + raw = toml_raw_at(arr, 1); + if (raw == 0) + return err_key_parse("multiples_supported", NULL); + ret = toml_rtoi(raw, &val); + if (ret < 0) + return err_key_parse("multiples_supported", "can't convert element to integer"); + ext_mod_config->sched_caps.multiples_supported.ul = val; + + ext_mod_config->header.num_scheduling_capabilities = 1; + *ext_length = sizeof(const struct mod_scheduling_caps); + + return 0; +} + +static int parse_pin(const toml_table_t *mod_entry, struct parse_ctx *ctx, + struct fw_image_ext_mod_config *ext_mod_config, int *ext_length) +{ + toml_array_t *arr; + toml_raw_t raw; + int64_t val; + int ret; + int i, j; + + /* check "pin" key */ + arr = toml_array_in(mod_entry, "pin"); + if (!arr) { + ext_mod_config->header.num_pin_entries = 0; + *ext_length = 0; + return 0; + } + + if (toml_array_type(arr) != 'i' || toml_array_kind(arr) != 'v') + return err_key_parse("pin", "wrong array type"); + + ctx->array_cnt++; + + ext_mod_config->header.num_pin_entries = toml_array_nelem(arr) / 6; + ext_mod_config->pin_desc = calloc(sizeof(const struct fw_pin_description), + toml_array_nelem(arr) / 6); + + if(!ext_mod_config->pin_desc) + return err_malloc("pin"); + + j = 0; + for (i = 0; ; i += 6, j++) { + raw = toml_raw_at(arr, i); + if (raw == 0) + break; + + ret = toml_rtoi(raw, &val); + if (ret < 0) + return err_key_parse("pin", "can't convert element to integer"); + ext_mod_config->pin_desc[j].caps.ul = (uint16_t)val; + + raw = toml_raw_at(arr, i + 1); + ret = toml_rtoi(raw, &val); + if (ret < 0) + return err_key_parse("pin", "can't convert element to integer"); + ext_mod_config->pin_desc[j].format_type = (enum mod_stream_type)val; + + raw = toml_raw_at(arr, i + 2); + ret = toml_rtoi(raw, &val); + if (ret < 0) + return err_key_parse("pin", "can't convert element to integer"); + ext_mod_config->pin_desc[j].sample_rate.ul = (uint32_t)val; + + raw = toml_raw_at(arr, i + 3); + ret = toml_rtoi(raw, &val); + if (ret < 0) + return err_key_parse("pin", "can't convert element to integer"); + ext_mod_config->pin_desc[j].sample_size.ul = (uint16_t)val; + + raw = toml_raw_at(arr, i + 4); + ret = toml_rtoi(raw, &val); + if (ret < 0) + return err_key_parse("pin", "can't convert element to integer"); + ext_mod_config->pin_desc[j].sample_container.ul = (uint32_t)val; + + raw = toml_raw_at(arr, i + 5); + ret = toml_rtoi(raw, &val); + if (ret < 0) + return err_key_parse("pin", "can't convert element to integer"); + ext_mod_config->pin_desc[j].ch_cfg.ul = (uint32_t)val; + } + + *ext_length = ext_mod_config->header.num_pin_entries * + sizeof(const struct fw_pin_description); + + return 0; +} + +static int parse_mod_config(const toml_table_t *mod_entry, struct parse_ctx *ctx, + struct fw_image_manifest_module *modules, + struct sof_man_module *mod_man) +{ + toml_array_t *arr; + toml_raw_t raw; + int *pin_data; + int64_t val; + int ret; + int i; + + /* check "pin" key */ + arr = toml_array_in(mod_entry, "mod_cfg"); + if (!arr) { + mod_man->cfg_count = 0; + return 0; + } + + if (toml_array_type(arr) != 'i' || toml_array_kind(arr) != 'v') + return err_key_parse("mod_cfg", "wrong array type"); + + ctx->array_cnt++; + + pin_data = (int *)(modules->mod_cfg + modules->mod_cfg_count); + mod_man->cfg_offset = modules->mod_cfg_count; + modules->mod_cfg_count += toml_array_nelem(arr) / 11; + mod_man->cfg_count = toml_array_nelem(arr) / 11; + + /* parse "pin" array elements */ + for (i = 0; ; ++i) { + raw = toml_raw_at(arr, i); + if (raw == 0) + break; + + ret = toml_rtoi(raw, &val); + if (ret < 0) + return err_key_parse("mod_cfg", "can't convert element to integer"); + pin_data[i] = val; + } + + return 0; +} + +static void dump_module(struct fw_image_manifest_module *man_cavs) +{ + int i; + + DUMP("\nmodule"); + DUMP_KEY("moudle count", "%d", man_cavs->mod_man_count); + DUMP_KEY("module config count", "%d", man_cavs->mod_cfg_count); + + for (i = 0; i < man_cavs->mod_man_count; i++) { + DUMP_PRINTABLE_BYTES("module name", man_cavs->mod_man[i].name); + DUMP_KEY("load type", "%d", man_cavs->mod_man[i].type.load_type); + DUMP_KEY("init config", "%d", man_cavs->mod_man[i].type.init_config); + DUMP_KEY("domain ll", "%d", man_cavs->mod_man[i].type.domain_ll); + DUMP_KEY("domain dp", "%d", man_cavs->mod_man[i].type.domain_dp); + DUMP_KEY("config count", "%d", man_cavs->mod_man[i].cfg_count); + DUMP_KEY("config offset", "%d", man_cavs->mod_man[i].cfg_offset); + } +} + +static int parse_module(const toml_table_t *toml, struct parse_ctx *pctx, + struct adsp *out, bool verbose) +{ + struct fw_image_manifest_module *modules; + toml_array_t *mod_entry_array; + toml_table_t *module; + toml_table_t *mod_entry; + struct parse_ctx ctx; + int entry_count; + int type, ext_length; + int tmp_cfg_count; + int ret, i; + + /* look for subtable in toml, increment pctx parsed table cnt and initialize local ctx */ + module = toml_table_in(toml, "module"); + if (!module) + return 0; + + out->write_firmware_ext_man = ext_man_write_cavs_25; + + modules = calloc(sizeof(struct fw_image_manifest_module), 1); + if (!modules) + return err_malloc("man_cavs"); + out->modules = modules; + + ++pctx->table_cnt; + parse_ctx_init(&ctx); + + entry_count = parse_uint32_key(module, &ctx, "count", 2, &ret); + if (ret < 0) + return ret; + + ctx.array_cnt += 1; + + mod_entry_array = toml_array_in(module, "entry"); + if (!mod_entry_array) + return err_key_not_found("entry"); + if (toml_array_kind(mod_entry_array) != 't' || + toml_array_nelem(mod_entry_array) != entry_count) + return err_key_parse("entry", "wrong array type or length != %d", entry_count); + + modules->mod_ext.mod_conf_count = entry_count; + modules->mod_man = calloc(sizeof(const struct sof_man_module), entry_count); + if (!modules->mod_man) + return -ENOMEM; + + modules->mod_man_count = toml_array_nelem(mod_entry_array); + + tmp_cfg_count = entry_count * 32; + modules->mod_cfg = calloc(sizeof(const struct sof_man_mod_config), tmp_cfg_count); + + /* parse entry array elements */ + for (i = 0; i < toml_array_nelem(mod_entry_array); ++i) { + struct fw_ext_mod_config_header *header; + struct sof_man_module *mod_man; + struct parse_ctx ctx_entry; + char buf[48]; + + mod_entry = toml_table_at(mod_entry_array, i); + if (!mod_entry) + return err_key_parse("entry", NULL); + + /* initialize parse context for each array element */ + parse_ctx_init(&ctx_entry); + + mod_man = &modules->mod_man[i]; + + memcpy(mod_man->struct_id, "$AME", 4); + + /* configurable fields */ + parse_printable_key(mod_entry, &ctx_entry, "name", mod_man->name, + sizeof(mod_man->name), &ret); + if (ret < 0) + return err_key_parse("name", NULL); + + parse_str_key(mod_entry, &ctx_entry, "uuid", buf, sizeof(buf), + &ret); + if (ret < 0) + return err_key_parse("uuid", NULL); + + parse_uuid(buf, mod_man->uuid); + + mod_man->affinity_mask = parse_uint32_hex_key(mod_entry, &ctx_entry, + "affinity_mask", 1, &ret); + if (ret < 0) + return err_key_parse("affinity_mask", NULL); + + mod_man->instance_max_count = parse_uint32_hex_key(mod_entry, &ctx_entry, + "instance_count", 1, &ret); + if (ret < 0) + return err_key_parse("instance_count", NULL); + + type = parse_uint32_hex_key(mod_entry, &ctx_entry, "domain_types", 0, &ret); + if (ret < 0) + return err_key_parse("domain_types", NULL); + if (!type) + mod_man->type.domain_ll = 1; + else + mod_man->type.domain_dp = 1; + + mod_man->type.load_type = parse_uint32_hex_key(mod_entry, &ctx_entry, + "load_type", 1, &ret); + if (ret < 0) + return err_key_parse("load_type", NULL); + + mod_man->type.init_config = parse_uint32_hex_key(mod_entry, &ctx_entry, + "init_config", 0, &ret); + if (ret < 0) + return err_key_parse("init_config", NULL); + + mod_man->type.auto_start = parse_uint32_hex_key(mod_entry, &ctx_entry, + "auto_start", 1, &ret); + if (ret < 0) + return err_key_parse("auto_start", NULL); + + header = &modules->mod_ext.ext_mod_config_array[i].header; + header->version_major = 2; + header->version_minor = 5; + header->ext_module_config_length = sizeof(struct fw_ext_mod_config_header); + memcpy(header->guid, mod_man->uuid, sizeof(mod_man->uuid)); + + type = parse_uint32_hex_key(mod_entry, &ctx_entry, "module_type", 1, &ret); + if (ret < 0) + return err_key_parse("module_type", NULL); + + header->module_type = type; + + ret = parse_scheduling(mod_entry, &ctx_entry, + modules->mod_ext.ext_mod_config_array + i, &ext_length); + if (ret < 0) + return err_key_parse("schd_caps", NULL); + header->ext_module_config_length += ext_length; + + ret = parse_pin(mod_entry, &ctx_entry, modules->mod_ext.ext_mod_config_array + i, + &ext_length); + if (ret < 0) + return err_key_parse("pin", NULL); + header->ext_module_config_length += ext_length; + + ret = parse_mod_config(mod_entry, &ctx_entry, modules, mod_man); + if (ret < 0) + return err_key_parse("mod_cfg", NULL); + + if (modules->mod_cfg_count > tmp_cfg_count) + return -ENOMEM; + + /* check everything parsed */ + ret = assert_everything_parsed(mod_entry, &ctx_entry); + if (ret < 0) + return ret; + } + + /* check everything parsed */ + ret = assert_everything_parsed(module, &ctx); + if (ret < 0) + return ret; + + if (verbose) + dump_module(modules); + + return 0; +} + +static int parse_adsp_config_v1_0(const toml_table_t *toml, struct image *image) +{ + struct adsp *out = image->adsp; + bool verbose = image->verbose; + struct parse_ctx ctx; + int ret; + + /* version array has already been parsed, so increment ctx.array_cnt */ + parse_ctx_init(&ctx); + ++ctx.array_cnt; + + /* parse each adsp subtable, sue platform has different manifest definition */ + ret = parse_adsp(toml, &ctx, out, verbose); + if (ret < 0) + return err_key_parse("adsp", NULL); + + /* assign correct write functions */ + out->write_firmware = simple_write_firmware; + out->write_firmware_meu = NULL; + + /* check everything parsed */ + ret = assert_everything_parsed(toml, &ctx); + if (ret < 0) + return ret; + + return 0; +} + +static int parse_adsp_config_v1_5(const toml_table_t *toml, struct image *image) +{ + struct adsp *out = image->adsp; + bool verbose = image->verbose; + struct parse_ctx ctx; + int ret; + + /* version array has already been parsed, so increment ctx.array_cnt */ + parse_ctx_init(&ctx); + ++ctx.array_cnt; + + /* parse each adsp subtable, sue platform has different manifest definition */ + ret = parse_adsp(toml, &ctx, out, verbose); + if (ret < 0) + return err_key_parse("adsp", NULL); + + /* suecreek has dedicated manifest file */ + if (!strcmp(out->name, "sue")) { + /* out free is done in client code */ + out->man_v1_5_sue = malloc(sizeof(struct fw_image_manifest_v1_5_sue)); + if (!out->man_v1_5_sue) + return err_malloc("man_v1_5_sue"); + + /* clear memory */ + memset(out->man_v1_5_sue, 0, sizeof(*out->man_v1_5_sue)); + + /* assign correct write functions */ + out->write_firmware = man_write_fw_v1_5_sue; + out->write_firmware_meu = man_write_fw_meu_v1_5; + out->verify_firmware = ri_manifest_verify_v1_5; + + /* parse others sibtables */ + ret = parse_fw_desc(toml, &ctx, &out->man_v1_5_sue->desc, verbose); + if (ret < 0) + return err_key_parse("fw_desc", NULL); + } else { + /* out free is done in client code */ + out->man_v1_5 = malloc(sizeof(struct fw_image_manifest_v1_5)); + if (!out->man_v1_5) + return err_malloc("man_v1_5"); + + /* clear memory */ + memset(out->man_v1_5, 0, sizeof(*out->man_v1_5)); + + /* assign correct write functions */ + out->write_firmware = man_write_fw_v1_5; + out->write_firmware_meu = man_write_fw_meu_v1_5; + out->verify_firmware = ri_manifest_verify_v1_5; + + /* parse others sibtables */ + ret = parse_css_v1_5(toml, &ctx, &out->man_v1_5->css_header, verbose); + if (ret < 0) + return err_key_parse("css", NULL); + + ret = parse_fw_desc(toml, &ctx, &out->man_v1_5->desc, verbose); + if (ret < 0) + return err_key_parse("fw_desc", NULL); + } + + /* check everything parsed */ + ret = assert_everything_parsed(toml, &ctx); + if (ret < 0) + return ret; + + return 0; +} + +static int parse_adsp_config_v1_8(const toml_table_t *toml, struct image *image) +{ + struct adsp *out = image->adsp; + bool verbose = image->verbose; + struct parse_ctx ctx; + int ret; + + /* out free is done in client code */ + out->man_v1_8 = malloc(sizeof(struct fw_image_manifest_v1_8)); + if (!out->man_v1_8) + return err_malloc("man_v1_8"); + + /* clear memory */ + memset(out->man_v1_8, 0, sizeof(*out->man_v1_8)); + + /* assign correct write functions */ + out->write_firmware = man_write_fw_v1_8; + out->write_firmware_meu = man_write_fw_meu_v1_8; + out->verify_firmware = ri_manifest_verify_v1_8; + + /* version array has already been parsed, so increment ctx.array_cnt */ + parse_ctx_init(&ctx); + ++ctx.array_cnt; + + /* parse each toml subtable */ + ret = parse_adsp(toml, &ctx, out, verbose); + if (ret < 0) + return err_key_parse("adsp", NULL); + + ret = parse_cse(toml, &ctx, &out->man_v1_8->cse_partition_dir_header, + out->man_v1_8->cse_partition_dir_entry, MAN_CSE_PARTS, verbose); + if (ret < 0) + return err_key_parse("cse", NULL); + + ret = parse_css_v1_8(toml, &ctx, &out->man_v1_8->css, verbose); + if (ret < 0) + return err_key_parse("css", NULL); + + ret = parse_signed_pkg(toml, &ctx, image, verbose); + if (ret < 0) + return err_key_parse("signed_pkg", NULL); + + ret = parse_partition_info_ext(toml, &ctx, &out->man_v1_8->partition_info, verbose); + if (ret < 0) + return err_key_parse("partition_info", NULL); + + ret = parse_adsp_file_ext_v1_8(toml, &ctx, &out->man_v1_8->adsp_file_ext, verbose); + if (ret < 0) + return err_key_parse("adsp_file", NULL); + + ret = parse_fw_desc(toml, &ctx, &out->man_v1_8->desc, verbose); + if (ret < 0) + return err_key_parse("fw_desc", NULL); + + /* check everything parsed */ + ret = assert_everything_parsed(toml, &ctx); + if (ret < 0) + return ret; + + return 0; +} + +static int parse_adsp_config_v2_5(const toml_table_t *toml, struct image *image) +{ + struct adsp *out = image->adsp; + bool verbose = image->verbose; + struct parse_ctx ctx; + int ret; + + /* out free is done in client code */ + out->man_v2_5 = malloc(sizeof(struct fw_image_manifest_v2_5)); + if (!out->man_v2_5) + return err_malloc("man_v2_5"); + + /* clear memory */ + memset(out->man_v2_5, 0, sizeof(*out->man_v2_5)); + + /* assign correct write functions */ + out->write_firmware = man_write_fw_v2_5; + out->write_firmware_meu = man_write_fw_meu_v2_5; + out->verify_firmware = ri_manifest_verify_v2_5; + + /* version array has already been parsed, so increment ctx.array_cnt */ + parse_ctx_init(&ctx); + ++ctx.array_cnt; + + /* parse each toml subtable */ + ret = parse_adsp(toml, &ctx, out, verbose); + if (ret < 0) + return err_key_parse("adsp", NULL); + + ret = parse_cse_v2_5(toml, &ctx, &out->man_v2_5->cse_partition_dir_header, + out->man_v2_5->cse_partition_dir_entry, MAN_CSE_PARTS, verbose); + if (ret < 0) + return err_key_parse("cse", NULL); + + ret = parse_css_v2_5(toml, &ctx, &out->man_v2_5->css, verbose); + if (ret < 0) + return err_key_parse("css", NULL); + + ret = parse_signed_pkg_v2_5(toml, &ctx, image, verbose); + if (ret < 0) + return err_key_parse("signed_pkg", NULL); + + ret = parse_info_ext_0x16(toml, &ctx, &out->man_v2_5->info_0x16, verbose); + if (ret < 0) + return err_key_parse("partition_info", NULL); + + ret = parse_adsp_file_ext_v2_5(toml, &ctx, &out->man_v2_5->adsp_file_ext, verbose); + if (ret < 0) + return err_key_parse("adsp_file", NULL); + + ret = parse_fw_desc(toml, &ctx, &out->man_v2_5->desc, verbose); + if (ret < 0) + return err_key_parse("fw_desc", NULL); + + ret = parse_module(toml, &ctx, out, verbose); + if (ret < 0) + return err_key_parse("module", NULL); + + /* check everything parsed */ + ret = assert_everything_parsed(toml, &ctx); + if (ret < 0) + return ret; + + return 0; +} + +static int parse_adsp_config_ace_v1_5(const toml_table_t *toml, struct image *image) +{ + struct adsp *out = image->adsp; + bool verbose = image->verbose; + struct parse_ctx ctx; + int ret; + + out->man_ace_v1_5 = malloc(sizeof(struct fw_image_manifest_ace_v1_5)); + if (!out->man_ace_v1_5) + return err_malloc("man_ace_v1_5"); + + /* clear memory */ + memset(out->man_ace_v1_5, 0, sizeof(*out->man_ace_v1_5)); + + /* assign correct write functions */ + out->write_firmware = man_write_fw_ace_v1_5; + out->write_firmware_meu = man_write_fw_meu_v2_5; + out->verify_firmware = ri_manifest_verify_v2_5; + + /* version array has already been parsed, so increment ctx.array_cnt */ + parse_ctx_init(&ctx); + ++ctx.array_cnt; + + /* parse each toml subtable */ + ret = parse_adsp(toml, &ctx, out, verbose); + if (ret < 0) + return err_key_parse("adsp", NULL); + + ret = parse_cse_v2_5(toml, &ctx, &out->man_ace_v1_5->cse_partition_dir_header, + out->man_ace_v1_5->cse_partition_dir_entry, 3, verbose); + if (ret < 0) + return err_key_parse("cse", NULL); + + ret = parse_css_v2_5(toml, &ctx, &out->man_ace_v1_5->css, verbose); + if (ret < 0) + return err_key_parse("css", NULL); + + ret = parse_signed_pkg_ace_v1_5(toml, &ctx, image, verbose); + if (ret < 0) + return err_key_parse("signed_pkg", NULL); + + ret = parse_info_ext_0x16(toml, &ctx, &out->man_ace_v1_5->info_0x16, verbose); + if (ret < 0) + return err_key_parse("partition_info", NULL); + + ret = parse_adsp_file_ext_v2_5(toml, &ctx, &out->man_ace_v1_5->adsp_file_ext, verbose); + if (ret < 0) + return err_key_parse("adsp_file", NULL); + + ret = parse_fw_desc(toml, &ctx, &out->man_ace_v1_5->desc, verbose); + if (ret < 0) + return err_key_parse("fw_desc", NULL); + + ret = parse_module(toml, &ctx, out, verbose); + if (ret < 0) + return err_key_parse("module", NULL); + + /* check everything parsed */ + ret = assert_everything_parsed(toml, &ctx); + if (ret < 0) + return ret; + + return 0; +} + +struct config_parser { + int major; + int minor; + int (*parse)(const toml_table_t *toml, struct image *image); +}; + +static const struct config_parser *find_config_parser(int64_t version[2]) +{ + /* list of supported configuration version with handler to parser */ + static const struct config_parser parsers[] = { + {1, 0, parse_adsp_config_v1_0}, + {1, 5, parse_adsp_config_v1_5}, + {1, 8, parse_adsp_config_v1_8}, + {2, 5, parse_adsp_config_v2_5}, + {3, 0, parse_adsp_config_ace_v1_5}, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(parsers); ++i) { + if (parsers[i].major == version[0] && + parsers[i].minor == version[1]) { + return &parsers[i]; + } + } + return NULL; +} + +static int adsp_parse_config_fd(FILE *fd, struct image *image) +{ + const struct config_parser *parser; + int64_t manifest_version[2]; + toml_table_t *toml; + char errbuf[256]; + int ret; + + /* whole toml file is parsed to global toml table at once */ + toml = toml_parse_file(fd, errbuf, ARRAY_SIZE(errbuf)); + if (!toml) + return log_err(-EINVAL, "error: toml file parsing, %s\n", errbuf); + + /* manifest version is in toml root */ + ret = parse_version(toml, manifest_version); + if (ret < 0) + goto error; + + /* find parser compatible with manifest version */ + parser = find_config_parser(manifest_version); + if (!parser) { + ret = log_err(-EINVAL, "error: Unsupported config version %d.%d\n", + manifest_version[0], manifest_version[1]); + goto error; + } + + /* run dedicated toml configuration parser */ + ret = parser->parse(toml, image); +error: + toml_free(toml); + return ret; +} + +/* public function, fully handle parsing process */ +int adsp_parse_config(const char *file, struct image *image) +{ + FILE *fd; + int ret; + + fd = fopen(file, "r"); + if (!fd) + return file_error("unable to open file for reading", file); + + ret = adsp_parse_config_fd(fd, image); + fclose(fd); + return ret; +} + +/* free given pointer and internally allocated memory */ +void adsp_free(struct adsp *adsp) +{ + if (!adsp) + return; + + if (adsp->man_v1_5) + free(adsp->man_v1_5); + + if (adsp->man_v1_5_sue) + free(adsp->man_v1_5_sue); + + if (adsp->man_v1_8) + free(adsp->man_v1_8); + + if (adsp->man_v2_5) + free(adsp->man_v2_5); + + if (adsp->modules) + free(adsp->modules); + + if (adsp->name) + free((char *)adsp->name); + + free(adsp); +} diff --git a/tools/rimage/src/cse.c b/tools/rimage/src/cse.c new file mode 100644 index 000000000000..3c5e9c561856 --- /dev/null +++ b/tools/rimage/src/cse.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2017 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// Keyon Jie <yang.jie@linux.intel.com> + +#include <stdio.h> +#include <stdbool.h> +#include <rimage/rimage.h> +#include <rimage/cse.h> +#include <rimage/manifest.h> + +void ri_cse_create(struct image *image) +{ + struct CsePartitionDirHeader *cse_hdr = image->fw_image; + struct sof_man_adsp_meta_file_ext_v1_8 *meta = image->fw_image + + MAN_META_EXT_OFFSET_V1_8; + struct CsePartitionDirEntry *cse_entry = + image->fw_image + sizeof(*cse_hdr); + uint8_t csum = 0, *val = image->fw_image; + int i, size; + + fprintf(stdout, " cse: completing CSE V1.8 manifest\n"); + + cse_entry[2].length = meta->comp_desc[0].limit_offset - + MAN_DESC_OFFSET_V1_8; + + /* calculate checksum using BSD algo */ + size = sizeof(*cse_hdr) + sizeof(*cse_entry) * MAN_CSE_PARTS; + for (i = 0; i < size; i++) { + if (i == 11) + continue; + csum += val[i]; + } + cse_hdr->checksum = 0x100 - csum; +} + +static uint32_t crc32(uint8_t *input, int size, uint32_t poly, uint32_t init, + bool rev_in, bool rev_out, uint32_t xor_out) +{ + uint32_t crc = init; + uint32_t t32; + uint8_t val; + uint8_t t8; + int i; + int j; + + for (i = 0; i < size; i++) { + val = input[i]; + if (rev_in) { + t8 = 0; + for (j = 0; j < 8; j++) { + if (val & (1 << j)) + t8 |= (uint8_t)(1 << (7 - j)); + } + val = t8; + } + crc ^= (uint32_t)(val << 24); + for (j = 0; j < 8; j++) { + if (crc & 0x80000000) + crc = (uint32_t)((crc << 1) ^ poly); + else + crc <<= 1; + } + } + + if (rev_out) { + t32 = 0; + for (i = 0; i < 32; i++) { + if (crc & (1U << i)) + t32 |= (uint32_t)(1 << (31 - i)); + } + crc = t32; + } + + return crc ^ xor_out; +} + +void ri_cse_create_v2_5(struct image *image) +{ + struct CsePartitionDirHeader_v2_5 *cse_hdr = image->fw_image; + struct sof_man_adsp_meta_file_ext_v2_5 *meta = image->fw_image + + MAN_META_EXT_OFFSET_V2_5; + struct CsePartitionDirEntry *cse_entry = + image->fw_image + sizeof(*cse_hdr); + uint8_t *val = image->fw_image; + int size; + + fprintf(stdout, " cse: completing CSE V2.5 manifest\n"); + + cse_entry[2].length = meta->comp_desc[0].limit_offset - + MAN_DESC_OFFSET_V1_8; + + /* + * calculate checksum using crc-32/iso-hdlc + * + * polynomial: 0x04c11db7 + * initial value: 0xffffffff + * reverse input: true + * reverse output: true + * xor output: 0xffffffff + */ + size = (sizeof(*cse_hdr) + (sizeof(*cse_entry) * MAN_CSE_PARTS)); + cse_hdr->checksum = crc32(val, size, 0x04c11db7, 0xffffffff, true, true, 0xffffffff); + + fprintf(stdout, " cse: cse checksum %x\n", cse_hdr->checksum); +} + +void ri_cse_create_ace_v1_5(struct image *image) +{ + struct CsePartitionDirHeader_v2_5 *cse_hdr = image->fw_image; + struct sof_man_adsp_meta_file_ext_v2_5 *meta = image->fw_image + + MAN_META_EXT_OFFSET_ACE_V1_5; + struct CsePartitionDirEntry *cse_entry = + image->fw_image + sizeof(*cse_hdr); + uint8_t *val = image->fw_image; + int size; + + fprintf(stdout, " cse: completing CSE V2.5 manifest\n"); + + cse_entry[2].length = meta->comp_desc[0].limit_offset - + MAN_DESC_OFFSET_V1_8; + + /* + * calculate checksum using crc-32/iso-hdlc + * + * polynomial: 0x04c11db7 + * initial value: 0xffffffff + * reverse input: true + * reverse output: true + * xor output: 0xffffffff + */ + size = (sizeof(*cse_hdr) + (sizeof(*cse_entry) * MAN_CSE_PARTS)); + cse_hdr->checksum = crc32(val, size, 0x04c11db7, 0xffffffff, true, true, 0xffffffff); + + fprintf(stdout, " cse: cse checksum %x\n", cse_hdr->checksum); +} diff --git a/tools/rimage/src/css.c b/tools/rimage/src/css.c new file mode 100644 index 000000000000..a69d5c80f76b --- /dev/null +++ b/tools/rimage/src/css.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2017 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// Keyon Jie <yang.jie@linux.intel.com> + +#include <stdio.h> +#include <errno.h> +#include <time.h> +#include <sys/time.h> +#include <rimage/rimage.h> +#include <rimage/css.h> +#include <rimage/manifest.h> + +void ri_css_v2_5_hdr_create(struct image *image) +{ + struct css_header_v2_5 *css = image->fw_image + MAN_CSS_HDR_OFFSET_2_5; + struct tm *date; + struct timeval tv; + time_t seconds; + int val; + + fprintf(stdout, " cse: %s completing CSS manifest\n", __func__); + + /* get local time and date */ + gettimeofday(&tv, NULL); + seconds = tv.tv_sec; + date = localtime(&seconds); + + if (!date) { + fprintf(stderr, "error: cant get localtime %d\n", -errno); + return; + } + + date->tm_year += 1900; + fprintf(stdout, " css: set build date to %d:%2.2d:%2.2d\n", + date->tm_year, date->tm_mon, date->tm_mday); + + /* year yYyy */ + val = date->tm_year / 1000; + css->date |= val << 28; + date->tm_year -= val * 1000; + /* year yyYy */ + val = date->tm_year / 100; + css->date |= val << 24; + date->tm_year -= val * 100; + /* year yyyY */ + val = date->tm_year / 10; + css->date |= val << 20; + date->tm_year -= val * 10; + /* year Yyyy */ + val = date->tm_year; + css->date |= val << 16; + + /* month Mm - for some reason month starts at 0 */ + val = ++date->tm_mon / 10; + css->date |= val << 12; + date->tm_mon -= (val * 10); + /* month mM */ + val = date->tm_mon; + css->date |= val << 8; + + /* Day Dd */ + val = date->tm_mday / 10; + css->date |= val << 4; + date->tm_mday -= (val * 10); + /* Day dD */ + val = date->tm_mday; + css->date |= val << 0; +} + +void ri_css_v1_8_hdr_create(struct image *image) +{ + struct css_header_v1_8 *css = image->fw_image + MAN_CSS_HDR_OFFSET; + struct tm *date; + struct timeval tv; + time_t seconds; + int val; + + fprintf(stdout, " cse: %s completing CSS manifest\n", __func__); + + /* get local time and date */ + gettimeofday(&tv, NULL); + seconds = tv.tv_sec; + date = localtime(&seconds); + + if (!date) { + fprintf(stderr, "error: cant get localtime %d\n", -errno); + return; + } + + date->tm_year += 1900; + fprintf(stdout, " css: set build date to %d:%2.2d:%2.2d\n", + date->tm_year, date->tm_mon, date->tm_mday); + + /* year yYyy */ + val = date->tm_year / 1000; + css->date |= val << 28; + date->tm_year -= val * 1000; + /* year yyYy */ + val = date->tm_year / 100; + css->date |= val << 24; + date->tm_year -= val * 100; + /* year yyyY */ + val = date->tm_year / 10; + css->date |= val << 20; + date->tm_year -= val * 10; + /* year Yyyy */ + val = date->tm_year; + css->date |= val << 16; + + /* month Mm - for some reason month starts at 0 */ + val = ++date->tm_mon / 10; + css->date |= val << 12; + date->tm_mon -= (val * 10); + /* month mM */ + val = date->tm_mon; + css->date |= val << 8; + + /* Day Dd */ + val = date->tm_mday / 10; + css->date |= val << 4; + date->tm_mday -= (val * 10); + /* Day dD */ + val = date->tm_mday; + css->date |= val << 0; +} + +void ri_css_v1_5_hdr_create(struct image *image) +{ + struct css_header_v1_5 *css = image->fw_image; + struct tm *date; + struct timeval tv; + time_t seconds; + int val; + + fprintf(stdout, " cse: %s completing CSS manifest\n", __func__); + + /* get local time and date */ + gettimeofday(&tv, NULL); + seconds = tv.tv_sec; + date = localtime(&seconds); + + if (!date) { + fprintf(stderr, "error: cant get localtime %d\n", -errno); + return; + } + + date->tm_year += 1900; + fprintf(stdout, " css: set build date to %d:%2.2d:%2.2d\n", + date->tm_year, date->tm_mon, date->tm_mday); + + /* year yYyy */ + val = date->tm_year / 1000; + css->date |= val << 28; + date->tm_year -= val * 1000; + /* year yyYy */ + val = date->tm_year / 100; + css->date |= val << 24; + date->tm_year -= val * 100; + /* year yyyY */ + val = date->tm_year / 10; + css->date |= val << 20; + date->tm_year -= val * 10; + /* year Yyyy */ + val = date->tm_year; + css->date |= val << 16; + + /* month Mm - for some reason month starts at 0 */ + val = ++date->tm_mon / 10; + css->date |= val << 12; + date->tm_mon -= (val * 10); + /* month mM */ + val = date->tm_mon; + css->date |= val << 8; + + /* Day Dd */ + val = date->tm_mday / 10; + css->date |= val << 4; + date->tm_mday -= (val * 10); + /* Day dD */ + val = date->tm_mday; + css->date |= val << 0; +} diff --git a/tools/rimage/src/elf_file.c b/tools/rimage/src/elf_file.c new file mode 100644 index 000000000000..efb9cc912b4e --- /dev/null +++ b/tools/rimage/src/elf_file.c @@ -0,0 +1,571 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Adrian Warecki <adrian.warecki@intel.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <rimage/elf_file.h> +#include <rimage/file_utils.h> +#include <rimage/misc_utils.h> + + /* Values for e_type. */ +static struct name_val e_type[] = { + NAME_VAL_ENTRY(ET_NONE), /* Unknown type. */ + NAME_VAL_ENTRY(ET_REL), /* Relocatable. */ + NAME_VAL_ENTRY(ET_EXEC), /* Executable. */ + NAME_VAL_ENTRY(ET_DYN), /* Shared object. */ + NAME_VAL_ENTRY(ET_CORE), /* Core file. */ + NAME_VAL_END +}; + +static struct name_val sh_types[] = { + NAME_VAL_ENTRY(SHT_NULL), /* inactive */ + NAME_VAL_ENTRY(SHT_PROGBITS), /* program defined information */ + NAME_VAL_ENTRY(SHT_SYMTAB), /* symbol table section */ + NAME_VAL_ENTRY(SHT_STRTAB), /* string table section */ + NAME_VAL_ENTRY(SHT_RELA), /* relocation section with addends */ + NAME_VAL_ENTRY(SHT_HASH), /* symbol hash table section */ + NAME_VAL_ENTRY(SHT_DYNAMIC), /* dynamic section */ + NAME_VAL_ENTRY(SHT_NOTE), /* note section */ + NAME_VAL_ENTRY(SHT_NOBITS), /* no space section */ + NAME_VAL_ENTRY(SHT_REL), /* relocation section - no addends */ + NAME_VAL_ENTRY(SHT_SHLIB), /* reserved - purpose unknown */ + NAME_VAL_ENTRY(SHT_DYNSYM), /* dynamic symbol table section */ + NAME_VAL_ENTRY(SHT_INIT_ARRAY), /* Initialization function pointers. */ + NAME_VAL_ENTRY(SHT_FINI_ARRAY), /* Termination function pointers. */ + NAME_VAL_ENTRY(SHT_PREINIT_ARRAY), /* Pre-initialization function ptrs. */ + NAME_VAL_ENTRY(SHT_GROUP), /* Section group. */ + NAME_VAL_ENTRY(SHT_SYMTAB_SHNDX), /* Section indexes (see SHN_XINDEX). */ + NAME_VAL_ENTRY(SHT_LOOS), /* First of OS specific semantics */ + NAME_VAL_ENTRY(SHT_HIOS), /* Last of OS specific semantics */ + NAME_VAL_ENTRY(SHT_GNU_VERDEF), + NAME_VAL_ENTRY(SHT_GNU_VERNEED), + NAME_VAL_ENTRY(SHT_GNU_VERSYM), + NAME_VAL_ENTRY(SHT_LOPROC), /* reserved range for processor */ + NAME_VAL_ENTRY(SHT_HIPROC), /* specific section header types */ + NAME_VAL_ENTRY(SHT_LOUSER), /* reserved range for application */ + NAME_VAL_ENTRY(SHT_HIUSER), /* specific indexes */ + NAME_VAL_END +}; + +/* Flags for sh_flags. */ +static struct name_val sh_flags[] = { + NAME_VAL_ENTRY(SHF_WRITE), /* Section contains writable data. */ + NAME_VAL_ENTRY(SHF_ALLOC), /* Section occupies memory. */ + NAME_VAL_ENTRY(SHF_EXECINSTR), /* Section contains instructions. */ + NAME_VAL_ENTRY(SHF_MERGE), /* Section may be merged. */ + NAME_VAL_ENTRY(SHF_STRINGS), /* Section contains strings. */ + NAME_VAL_ENTRY(SHF_INFO_LINK), /* sh_info holds section index. */ + NAME_VAL_ENTRY(SHF_LINK_ORDER), /* Special ordering requirements. */ + NAME_VAL_ENTRY(SHF_OS_NONCONFORMING), /* OS-specific processing required. */ + NAME_VAL_ENTRY(SHF_GROUP), /* Member of section group. */ + NAME_VAL_ENTRY(SHF_TLS), /* Section contains TLS data. */ + NAME_VAL_END +}; + +/* Values for p_type. */ +static struct name_val p_type[] = { + NAME_VAL_ENTRY(PT_NULL), /* Unused entry. */ + NAME_VAL_ENTRY(PT_LOAD), /* Loadable segment. */ + NAME_VAL_ENTRY(PT_DYNAMIC), /* Dynamic linking information segment. */ + NAME_VAL_ENTRY(PT_INTERP), /* Pathname of interpreter. */ + NAME_VAL_ENTRY(PT_NOTE), /* Auxiliary information. */ + NAME_VAL_ENTRY(PT_SHLIB), /* Reserved (not used). */ + NAME_VAL_ENTRY(PT_PHDR), /* Location of program header itself. */ + NAME_VAL_ENTRY(PT_TLS), /* Thread local storage segment */ + NAME_VAL_END +}; + +/* Values for p_flags. */ +static struct name_val p_flags[] = { + NAME_VAL_ENTRY(PF_X), /* Executable. */ + NAME_VAL_ENTRY(PF_W), /* Writable. */ + NAME_VAL_ENTRY(PF_R), /* Readable. */ + NAME_VAL_END +}; + +/** + * Print elf related error message + * + * @param elf elf file structure + * @param msg error message + * @param error error code to return + * @return error code + */ +static int elf_error(const struct elf_file *elf, const char *msg, int error) +{ + fprintf(stderr, "Error: %s: %s\n", elf->filename, msg); + return -error; +} + +/** + * Read elf header + * + * @param elf elf file structure + * @return error code, 0 when success + */ +static int elf_header_read(struct elf_file *elf) +{ + size_t count; + + /* read in elf header */ + count = fread(&elf->header, sizeof(elf->header), 1, elf->file); + if (count != 1) { + if (count < 0) + return file_error("failed to read elf header", elf->filename); + else + return elf_error(elf, "Corrupted file.", ENODATA); + } + + if (strncmp((char *)elf->header.ident, "\177ELF\001\001", 5)) + return elf_error(elf, "Not a 32 bits ELF-LE file", EILSEQ); + + if (elf->header.version != EV_CURRENT) + return elf_error(elf, "Unsupported file version.", EINVAL); + + if (elf->header.ehsize < sizeof(Elf32_Ehdr)) + return elf_error(elf, "Invalid file header size.", EINVAL); + + if (elf->header.phoff >= elf->file_size) + return elf_error(elf, "Invalid program header file offset.", EINVAL); + + if (elf->header.phentsize < sizeof(Elf32_Phdr)) + return elf_error(elf, "Invalid program header size.", EINVAL); + + if (elf->header.phoff + elf->header.phnum * sizeof(Elf32_Phdr) > elf->file_size) + return elf_error(elf, "Invalid number of program header entries.", EINVAL); + + if (elf->header.shoff >= elf->file_size) + return elf_error(elf, "Invalid section header file offset.", EINVAL); + + if (elf->header.shentsize < sizeof(Elf32_Shdr)) + return elf_error(elf, "Invalid section header size.", EINVAL); + + if (elf->header.shoff + elf->header.shnum * sizeof(Elf32_Shdr) > elf->file_size) + return elf_error(elf, "Invalid number of section header entries.", EINVAL); + + if (elf->header.shstrndx >= elf->header.shnum) + return elf_error(elf, "Invalid section name strings section index.", EINVAL); + + return 0; +} + +void elf_header_print(const struct elf_file *elf) +{ + fprintf(stdout, "\tfile type\t 0x%8.8x ", elf->header.type); + print_enum(elf->header.type, e_type); + fprintf(stdout, "\tarchitecture\t 0x%8.8x\n", elf->header.machine); + fprintf(stdout, "\tformat version\t 0x%8.8x\n", elf->header.version); + fprintf(stdout, "\tarch flags\t 0x%8.8x\n", elf->header.flags); + fprintf(stdout, "\theader size\t 0x%8.8x\n", elf->header.ehsize); + fprintf(stdout, "\tentry point\t 0x%8.8x\n", elf->header.entry); + fprintf(stdout, "\tprogram offset\t 0x%8.8x\n", elf->header.phoff); + fprintf(stdout, "\tsection offset\t 0x%8.8x\n", elf->header.shoff); + fprintf(stdout, "\tprogram size\t 0x%8.8x\n", elf->header.phentsize); + fprintf(stdout, "\tprogram count\t 0x%8.8x\n", elf->header.phnum); + fprintf(stdout, "\tsection size\t 0x%8.8x\n", elf->header.shentsize); + fprintf(stdout, "\tsection count\t 0x%8.8x\n", elf->header.shnum); + fprintf(stdout, "\tstring index\t 0x%8.8x\n\n", elf->header.shstrndx); +} + +/** + * Read sections headers from elf file + * + * @param elf elf file structure + * @return error code, 0 when success + */ +static int elf_section_headers_read(struct elf_file *elf) +{ + int i, ret; + size_t offset, count; + + elf->sections = calloc(elf->header.shnum, sizeof(struct elf_section_header)); + if (!elf->sections) + return elf_error(elf, "Cannot allocate section array.", ENOMEM); + + /* In case of error, sections memory are released in elf_open function. */ + + offset = elf->header.shoff; + for (i = 0; i < elf->header.shnum; i++, offset += elf->header.shentsize) { + ret = fseek(elf->file, offset, SEEK_SET); + if (ret) + return file_error("unable to seek to section header", elf->filename); + + count = fread(&elf->sections[i].data, sizeof(Elf32_Shdr), 1, elf->file); + if (count != 1) { + if (count < 0) + return file_error("failed to read section header", elf->filename); + else + return elf_error(elf, "Corrupted file.", ENODATA); + } + } + + elf->sections_count = elf->header.shnum; + return 0; +} + +/** + * Update name of a section in the section headers + * + * @param elf elf file structure + * @return error code, 0 when success + */ +static int elf_set_sections_names(struct elf_file *elf, const struct elf_strings *strings) +{ + int ret, i; + + for (i = 0; i < elf->sections_count; i++) { + ret = elf_strings_get(strings, elf->sections[i].data.name, &elf->sections[i].name); + if (ret) + return ret; + } + + return 0; +} + +void elf_print_sections(const struct elf_file *elf) +{ + int i; + + for (i = 0; i < elf->sections_count; i++) { + fprintf(stdout, "Section %d:\n", i); + elf_section_header_print(&elf->sections[i]); + } +} + +/** + * Read program headers from elf file + * + * @param elf elf file structure + * @return error code, 0 when success + */ +static int elf_program_headers_read(struct elf_file *elf) +{ + int i, ret; + size_t offset, count; + + elf->programs = calloc(elf->header.phnum, sizeof(Elf32_Phdr)); + if (!elf->programs) + return elf_error(elf, "Cannot allocate program array.", ENOMEM); + + /* In case of error, programs memory are released in elf_open function. */ + + offset = elf->header.phoff; + for (i = 0; i < elf->header.phnum; i++, offset += elf->header.phentsize) { + ret = fseek(elf->file, offset, SEEK_SET); + if (ret) + return file_error("unable to seek to program header", elf->filename); + + count = fread(&elf->programs[i], sizeof(Elf32_Phdr), 1, elf->file); + if (count != 1) { + if (count < 0) + return file_error("failed to read program header", elf->filename); + else + return elf_error(elf, "Corrupted file.", ENODATA); + } + } + + elf->programs_count = elf->header.phnum; + return 0; +} + +void elf_print_programs(const struct elf_file *elf) +{ + int i; + + for (i = 0; i < elf->programs_count; i++) { + fprintf(stdout, "\nProgram %d:\n", i); + elf_program_header_print(&elf->programs[i]); + } +} + +/** + * Copy elf_header structure. Allocates a new copy of the name string. + * + * @param [in]src Source section header structure + * @param [out]dst Destination section header structure + * @return error code, 0 when success + */ +static int elf_section_header_copy(const struct elf_section_header *src, + struct elf_section_header *dst) +{ + if (src->name) { + dst->name = strdup(src->name); + if (!dst->name) + return -ENOMEM; + } else { + dst->name = NULL; + } + + memcpy(&dst->data, &src->data, sizeof(dst->data)); + return 0; +} + +int elf_section_header_get_by_index(const struct elf_file *elf, int index, + const struct elf_section_header **header) +{ + if (index >= elf->sections_count) + return elf_error(elf, "Invalid section index.", EINVAL); + + *header = &elf->sections[index]; + + return 0; +} + +int elf_section_header_get_by_name(const struct elf_file *elf, const char* name, + const struct elf_section_header **header) +{ + int i; + + *header = NULL; + + for (i = 0; i < elf->sections_count; i++) + if (strcmp(elf->sections[i].name, name) == 0) { + *header = &elf->sections[i]; + return 0; + } + + return -ENOENT; +} + +void elf_section_header_print(const struct elf_section_header *header) +{ + fprintf(stdout, "\tname\t\t0x%8.8x\n", header->data.name); + fprintf(stdout, "\tname\t\t%s\n", header->name); + fprintf(stdout, "\ttype\t\t0x%8.8x ", header->data.type); + print_enum(header->data.type, sh_types); + fprintf(stdout, "\tflags\t\t0x%8.8x ", header->data.flags); + print_flags(header->data.flags, sh_flags); + fprintf(stdout, "\taddr\t\t0x%8.8x\n", header->data.vaddr); + fprintf(stdout, "\toffset\t\t0x%8.8x\n", header->data.off); + fprintf(stdout, "\tsize\t\t0x%8.8x\n", header->data.size); + fprintf(stdout, "\tlink\t\t0x%8.8x\n", header->data.link); + fprintf(stdout, "\tinfo\t\t0x%8.8x\n", header->data.info); + fprintf(stdout, "\taddralign\t0x%8.8x\n", header->data.addralign); + fprintf(stdout, "\tentsize\t\t0x%8.8x\n\n", header->data.entsize); +} + +/** + * Release section header structure + * + * @param sec_hdr Section header structure + */ +static void elf_section_header_free(struct elf_section_header *sec_hdr) +{ + free(sec_hdr->name); + sec_hdr->name = NULL; +} + + +int elf_open(struct elf_file *elf, const char *filename) +{ + struct elf_strings names; + int ret = -ENOMEM; + + memset(elf, 0, sizeof(*elf)); + elf->filename = strdup(filename); + if (!elf->filename) { + ret = -ENOMEM; + goto err; + } + + elf->file = fopen(filename, "rb"); + if (!elf->file) { + ret = file_error("Unable to open elf file", elf->filename); + goto err; + } + + ret = get_file_size(elf->file, elf->filename, &elf->file_size); + if (ret) + goto err; + + ret = elf_header_read(elf); + if (ret) + goto err; + + ret = elf_program_headers_read(elf); + if (ret) + goto err; + + ret = elf_section_headers_read(elf); + if (ret) + goto err; + + ret = elf_strings_read_by_index(elf, elf->header.shstrndx, &names); + if (ret) + goto err; + + ret = elf_set_sections_names(elf, &names); + if (ret) { + elf_strings_free(&names); + goto err; + } + elf_strings_free(&names); + + return 0; + +err: + free(elf->filename); + free(elf->programs); + + if (elf->file) + fclose(elf->file); + + if (elf->sections) { + for (int i = 0; i < elf->sections_count; i++) + elf_section_header_free(&elf->sections[i]); + + free(elf->sections); + } + + return ret; +} + +/** +* Close elf file and release resources +* @param elf elf file structure +*/ +void elf_free(struct elf_file *elf) +{ + int i; + + free(elf->filename); + fclose(elf->file); + + for (i = 0; i < elf->sections_count; i++) + elf_section_header_free(&elf->sections[i]); + + free(elf->sections); + free(elf->programs); +} + +int elf_section_read_content(const struct elf_file *elf, const struct elf_section_header *header, + void *buffer, const size_t size) +{ + int ret; + size_t count; + + if ((header->data.type == SHT_NOBITS) || (header->data.type == SHT_NULL) || + !header->data.size) + return elf_error(elf, "Can't read section without data.", ENODATA); + + if (!header->data.off || (header->data.off + header->data.size) > elf->file_size) + return elf_error(elf, "Invalid section position in file.", ENFILE); + + if (header->data.size > size) + return elf_error(elf, "Output buffer too small.", ENOSPC); + + ret = fseek(elf->file, header->data.off, SEEK_SET); + if (ret) + return file_error("unable to seek to section data", elf->filename); + + count = fread(buffer, header->data.size, 1, elf->file); + if (count != 1) { + if (count < 0) + return file_error("failed to read section data", elf->filename); + else + return elf_error(elf, "Corrupted file.", ENODATA); + } + + return 0; +} + +int elf_section_read(const struct elf_file *elf, const struct elf_section_header *header, + struct elf_section *section) +{ + int ret; + + section->data = malloc(header->data.size); + if (!section->data) + return elf_error(elf, "No memory for section buffer.", ENOMEM); + + ret = elf_section_header_copy(header, §ion->header); + if (ret) + goto err; + + ret = elf_section_read_content(elf, header, section->data, header->data.size); + if (ret) + goto err; + + return 0; + +err: + elf_section_header_free(§ion->header); + free(section->data); + return ret; +} + +int elf_section_read_by_name(const struct elf_file *elf, const char *name, + struct elf_section *section) +{ + const struct elf_section_header *header; + int ret; + + ret = elf_section_header_get_by_name(elf, name, &header); + + if (ret) + return ret; + + return elf_section_read(elf, header, section); +} + +void elf_section_free(struct elf_section *section) +{ + free(section->data); +} + +int elf_strings_read_by_index(const struct elf_file *elf, int index, struct elf_strings *strings) +{ + const struct elf_section_header *header; + int ret; + + ret = elf_section_header_get_by_index(elf, index, &header); + if (ret) + return ret; + + if (header->data.type != SHT_STRTAB) + return elf_error(elf, "Invalid section type.", EINVAL); + + ret = elf_section_read(elf, header, &strings->section); + if (ret) + return elf_error(elf, "Unable to read section names section.", ret); + + return 0; +} + +int elf_strings_get(const struct elf_strings *strings, int index, char **str) +{ + if (index >= strings->section.header.data.size) + return -EINVAL; + + *str = strdup((const char *)strings->section.data + index); + if (!*str) + return -ENOMEM; + + return 0; +} + +void elf_strings_free(struct elf_strings *strings) +{ + elf_section_free(&strings->section); +} + +void elf_program_header_print(const Elf32_Phdr *header) +{ + fprintf(stdout, "\ttype\t 0x%8.8x ", header->type); + print_enum(header->type, p_type); + fprintf(stdout, "\tflags\t 0x%8.8x ", header->flags); + print_flags(header->flags, p_flags); + fprintf(stdout, "\toffset\t 0x%8.8x\n", header->off); + fprintf(stdout, "\tvaddr\t 0x%8.8x\n", header->vaddr); + fprintf(stdout, "\tpaddr\t 0x%8.8x\n", header->paddr); + fprintf(stdout, "\tfilesz\t 0x%8.8x\n", header->filesz); + fprintf(stdout, "\tmemsz\t 0x%8.8x\n", header->memsz); + fprintf(stdout, "\talign\t 0x%8.8x\n\n", header->align); +} diff --git a/tools/rimage/src/ext_manifest.c b/tools/rimage/src/ext_manifest.c new file mode 100644 index 000000000000..c6d3c02e887e --- /dev/null +++ b/tools/rimage/src/ext_manifest.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. +// +// Author: Karol Trzcinski <karolx.trzcinski@linux.intel.com> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include <rimage/ext_manifest_gen.h> +#include <rimage/sof/kernel/ext_manifest.h> +#include <rimage/rimage.h> +#include <rimage/cavs/cavs_ext_manifest.h> +#include <rimage/manifest.h> +#include <rimage/file_utils.h> + +const struct ext_man_header ext_man_template = { + .magic = EXT_MAN_MAGIC_NUMBER, + .header_version = EXT_MAN_VERSION, + .header_size = sizeof(struct ext_man_header), + .full_size = 0, /* runtime variable */ +}; + +static int ext_man_open_file(struct image *image) +{ + int ret; + + ret = create_file_name(image->out_ext_man_file, sizeof(image->out_ext_man_file), + image->out_file, "xman"); + if (ret) + return ret; + + /* open extended manifest outfile for writing */ + image->out_ext_man_fd = fopen(image->out_ext_man_file, "wb"); + if (!image->out_ext_man_fd) + return file_error("unable to open file for writing", image->out_ext_man_file); + + return 0; +} + +static const struct elf_file *ext_man_find_module(const struct image *image, + const struct elf_section_header **section) +{ + const struct manifest_module *module; + int i; + + for (i = 0; i < image->num_modules; i++) { + module = &image->module[i]; + + if (module->is_bootloader) + continue; + + if (!elf_section_header_get_by_name(&module->file.elf, EXT_MAN_DATA_SECTION, + section)) + return &module->file.elf; + } + + return NULL; +} + +static int ext_man_validate(uint32_t section_size, const void *section_data) +{ + uint8_t *sbuf = (uint8_t *)section_data; + struct ext_man_elem_header head; + uint32_t offset = 0; + + /* copy each head to local struct to omit memory align issues */ + while (offset < section_size) { + memcpy(&head, &sbuf[offset], sizeof(head)); + fprintf(stdout, "Extended manifest found module, type: 0x%04X size: 0x%04X (%4d) offset: 0x%04X\n", + head.type, head.elem_size, head.elem_size, offset); + if (head.elem_size == 0 || head.elem_size % EXT_MAN_ALIGN) { + fprintf(stderr, + "error: invalid extended manifest element size\n"); + return -EINVAL; + } + offset += head.elem_size; + } + + /* sum of packets size != section size */ + if (offset != section_size) { + fprintf(stderr, + "error: fw_metadata section is inconsistent, section size: 0x%04X != 0x%04X sum of packets size\n", + section_size, offset); + return -EINVAL; + } else { + return 0; + } +} + +static int ext_man_build(const struct elf_file *file, const struct elf_section_header *section, + struct ext_man_header **dst_buff) +{ + struct ext_man_header *ext_man; + size_t size; + int ret; + + size = ext_man_template.header_size + section->data.size; + if (size % 4) { + fprintf(stderr, "error: extended manifest size must be aligned to 4\n"); + return -EINVAL; + } + + ext_man = calloc(1, size); + if (!ext_man) + return -ENOMEM; + + /* fill ext_man struct, size aligned to 4 to avoid unaligned accesses */ + memcpy(ext_man, &ext_man_template, ext_man_template.header_size); + ext_man->full_size = size; + + ret = elf_section_read_content(file, section, ext_man + 1, + size - ext_man_template.header_size); + if (ret < 0) { + fprintf(stderr, "error: failed to read %s section content, code %d\n", + EXT_MAN_DATA_SECTION, ret); + free(ext_man); + return ret; + } + + *dst_buff = ext_man; + return 0; +} + +int ext_man_write(struct image *image) +{ + const struct elf_file *file; + struct ext_man_header *ext_man = NULL; + const struct elf_section_header *section; + int count; + int ret; + + ret = ext_man_open_file(image); + if (ret) + goto out; + + file = ext_man_find_module(image, §ion); + if (!file) { + ret = -ECANCELED; + goto out; + } + + ret = ext_man_build(file, section, &ext_man); + if (ret) + goto out; + + /* validate metadata section */ + ret = ext_man_validate(ext_man->full_size - ext_man->header_size, + (char *)ext_man + ext_man->header_size); + if (ret) { + ret = -errno; + goto out; + } + + /* write extended metadata to file */ + count = fwrite(ext_man, 1, ext_man->full_size, image->out_ext_man_fd); + + if (count != ext_man->full_size) { + ret = file_error("can't write extended manifest", image->out_ext_man_file); + goto out; + } + + fprintf(stdout, "Extended manifest saved to file %s size 0x%04X (%d) bytes\n\n", + image->out_ext_man_file, ext_man->full_size, + ext_man->full_size); + +out: + if (ext_man) + free(ext_man); + if (image->out_ext_man_fd) + fclose(image->out_ext_man_fd); + return ret; +} + +int ext_man_write_cavs_25(struct image *image) +{ + struct fw_image_ext_module *mod_ext; + struct fw_ext_man_cavs_header header; + int pin_count; + int count, i; + int ret; + size_t write_ret; + + ret = ext_man_open_file(image); + if (ret) + goto out; + + mod_ext = &image->adsp->modules->mod_ext; + count = mod_ext->mod_conf_count; + header.version_major = EXTENDED_MANIFEST_VERSION_MAJOR; + header.version_minor = EXTENDED_MANIFEST_VERSION_MINOR; + header.num_module_entries = count; + header.id = EXTENDED_MANIFEST_MAGIC_HEADER_ID; + header.len = sizeof(const struct fw_ext_man_cavs_header); + + for (i = 0; i < count; i++) + header.len += mod_ext->ext_mod_config_array[i].header.ext_module_config_length; + fwrite(&header, 1, sizeof(header), image->out_ext_man_fd); + + for (i = 0; i < count; i++) { + write_ret = fwrite(&mod_ext->ext_mod_config_array[i].header, + sizeof(struct fw_ext_mod_config_header), 1, + image->out_ext_man_fd); + if (write_ret != 1) { + ret = file_error("can't write fw_ext_mod_config_header", + image->out_ext_man_file); + goto out; + } + + if (mod_ext->ext_mod_config_array[i].header.num_scheduling_capabilities) { + write_ret = fwrite(&mod_ext->ext_mod_config_array[i].sched_caps, + sizeof(struct mod_scheduling_caps), 1, + image->out_ext_man_fd); + if (write_ret != 1) { + ret = file_error("can't write mod_scheduling_caps", + image->out_ext_man_file); + goto out; + } + } + + pin_count = mod_ext->ext_mod_config_array[i].header.num_pin_entries; + if (pin_count) { + write_ret = fwrite(mod_ext->ext_mod_config_array[i].pin_desc, + sizeof(struct fw_pin_description), pin_count, + image->out_ext_man_fd); + + if (write_ret != pin_count) { + ret = file_error("can't write fw_pin_description", + image->out_ext_man_file); + goto out; + } + } + } + +out: + if (image->out_ext_man_fd) + fclose(image->out_ext_man_fd); + return ret; +} diff --git a/tools/rimage/src/file_simple.c b/tools/rimage/src/file_simple.c new file mode 100644 index 000000000000..e87689f44133 --- /dev/null +++ b/tools/rimage/src/file_simple.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2015 Intel Corporation. All rights reserved. + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +#include <rimage/rimage.h> +#include <rimage/manifest.h> +#include <rimage/file_utils.h> + +static int get_mem_zone_type(const struct memory_config *memory, + const struct module_section *section) +{ + uint32_t start, end, base, size; + int i; + + start = section->load_address; + end = start + section->size; + + for (i = SOF_FW_BLK_TYPE_START; i < SOF_FW_BLK_TYPE_NUM; i++) { + base = memory->zones[i].base; + size = memory->zones[i].size; + + if (start < base) + continue; + if (start >= base + size) + continue; + if (end > base + size) + continue; + return i; + } + return SOF_FW_BLK_TYPE_INVALID; +} + +static int block_idx; + +static int write_block(struct image *image, struct manifest_module *module, + const struct module_section *section) +{ + const struct adsp *adsp = image->adsp; + struct snd_sof_blk_hdr block; + uint32_t padding = 0; + size_t count; + int ret; + + block.size = section->size; + if (block.size % 4) { + /* make block.size divisible by 4 to avoid unaligned accesses */ + padding = 4 - (block.size % 4); + block.size += padding; + } + + ret = get_mem_zone_type(&adsp->mem, section); + if (ret != SOF_FW_BLK_TYPE_INVALID) { + block.type = ret; + block.offset = section->load_address - adsp->mem.zones[ret].base + + adsp->mem.zones[ret].host_offset; + } else { + fprintf(stderr, "error: invalid block address/size 0x%x/0x%zx\n", + section->load_address, section->size); + return -EINVAL; + } + + /* write header */ + count = fwrite(&block, sizeof(block), 1, image->out_fd); + if (count != 1) + return file_error("Write header failed", image->out_file); + + /* write out section data */ + ret = module_write_section(&module->file, section, padding, image->out_fd, image->out_file); + if (ret) { + fprintf(stderr, "error: cant write section data. foffset %d size 0x%zx mem addr 0x%x\n", + section->header->data.off, section->size, section->load_address); + return ret; + } + + fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8zx\t0x%8.8lx\t%s\t%s\n", block_idx++, + section->load_address, section->size, ftell(image->out_fd), + block.type == SOF_FW_BLK_TYPE_IRAM ? "TEXT" : "DATA", + section->header->name); + + /* return padding size */ + if (ret >= 0) + return padding; + + return ret; +} + +/** + * Write all linked sections + * + * @param image program global structure + * @param module modules manifest description + * @param section module section descriptor + * @return size of used padding, error code on error + */ +static int write_blocks(struct image *image, struct manifest_module *module, + const struct module_section *section) +{ + int ret, padding = 0; + + while (section) { + ret = write_block(image, module, section); + if (ret < 0) { + fprintf(stderr, "error: failed to write section %s\n", + section->header->name); + return ret; + } + + padding += ret; + section = section->next_section; + } + + return padding; +} + +static int simple_write_module(struct image *image, struct manifest_module *module) +{ + struct snd_sof_mod_hdr hdr; + size_t count; + int err; + int ptr_hdr, ptr_cur; + uint32_t padding; + + hdr.num_blocks = module->file.text.count + module->file.data.count; + hdr.size = module->file.text.size + module->file.data.size + + sizeof(struct snd_sof_blk_hdr) * hdr.num_blocks; + hdr.type = SOF_FW_BASE; + + /* Get the pointer of writing hdr */ + ptr_hdr = ftell(image->out_fd); + if (ptr_hdr < 0) + return file_error("cant get file position", image->out_file); + + count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd); + if (count != 1) + return file_error("failed to write section header", image->out_file); + + module_print_zones(&module->file); + + fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\t\tType\tName\n"); + + /* Write text sections */ + err = write_blocks(image, module, module->file.text.first_section); + if (err < 0) + return err; + padding = err; + + /* Write data sections */ + err = write_blocks(image, module, module->file.data.first_section); + if (err < 0) + return err; + padding += err; + + hdr.size += padding; + /* Record current pointer, will set it back after overwriting hdr */ + ptr_cur = ftell(image->out_fd); + if (ptr_cur < 0) + return file_error("cant get file position", image->out_file); + + /* overwrite hdr */ + err = fseek(image->out_fd, ptr_hdr, SEEK_SET); + if (err) + return file_error("cant seek to header", image->out_file); + + count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd); + if (count != 1) + return file_error("failed to write section header", image->out_file); + + err = fseek(image->out_fd, ptr_cur, SEEK_SET); + if (err) + return file_error("cant seek", image->out_file); + + fprintf(stdout, "\n"); + /* return padding size */ + return padding; +} + +static int write_block_reloc(struct image *image, struct manifest_module *module) +{ + struct snd_sof_blk_hdr block; + size_t count; + int ret; + + block.size = module->file.elf.file_size; + block.type = SOF_FW_BLK_TYPE_DRAM; + block.offset = 0; + + /* write header */ + count = fwrite(&block, sizeof(block), 1, image->out_fd); + if (count != 1) + return file_error("cant write header", image->out_file); + + ret = module_write_whole_elf(&module->file, image->out_fd, image->out_file); + if (ret) + return ret; + + fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8zx\t0x%8.8lx\t%s\n", block_idx++, + 0, module->file.elf.file_size, ftell(image->out_fd), + block.type == SOF_FW_BLK_TYPE_IRAM ? "TEXT" : "DATA"); + + return ret; +} + +static int simple_write_module_reloc(struct image *image, struct manifest_module *module) +{ + struct snd_sof_mod_hdr hdr; + size_t count; + int err; + + hdr.num_blocks = 1; + hdr.size = module->file.text.size + module->file.data.size; + hdr.type = SOF_FW_BASE; // module + + count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd); + if (count != 1) + return file_error("failed to write section header", image->out_file); + + module_print_zones(&module->file); + + fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\t\tType\n"); + + err = write_block_reloc(image, module); + if (err < 0) { + fprintf(stderr, "error: failed to write section #%d\n", err); + return err; + } + + fprintf(stdout, "\n"); + return 0; +} + +/* used by others */ +int simple_write_firmware(struct image *image) +{ + struct snd_sof_fw_header hdr; + struct manifest_module *module; + size_t count; + int i, ret; + + memcpy(hdr.sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE); + + hdr.num_modules = image->num_modules; + hdr.abi = SND_SOF_FW_ABI; + hdr.file_size = 0; + + for (i = 0; i < image->num_modules; i++) { + module = &image->module[i]; + module->output_size = module->file.data.size + module->file.text.size; + module->output_size += sizeof(struct snd_sof_blk_hdr) * + (module->file.data.count + module->file.text.count); + module->output_size += sizeof(struct snd_sof_mod_hdr) * + hdr.num_modules; + hdr.file_size += module->output_size; + } + + count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd); + if (count != 1) + return file_error("failed to write header", image->out_file); + + for (i = 0; i < image->num_modules; i++) { + module = &image->module[i]; + + fprintf(stdout, "writing module %d %s\n", i, module->file.elf.filename); + + if (image->reloc) + ret = simple_write_module_reloc(image, module); + else + ret = simple_write_module(image, module); + if (ret < 0) { + fprintf(stderr, "error: failed to write module %d\n", + i); + return ret; + } + /* add padding size */ + hdr.file_size += ret; + } + /* overwrite hdr */ + ret = fseek(image->out_fd, 0, SEEK_SET); + if (ret) + return file_error("can't seek set", image->out_file); + + + count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd); + if (count != 1) + return file_error("failed to write header", image->out_file); + + fprintf(stdout, "firmware: image size %ld (0x%lx) bytes %d modules\n\n", + (long)(hdr.file_size + sizeof(hdr)), + (long)(hdr.file_size + sizeof(hdr)), + hdr.num_modules); + + return 0; +} diff --git a/tools/rimage/src/file_utils.c b/tools/rimage/src/file_utils.c new file mode 100644 index 000000000000..89a89ae40954 --- /dev/null +++ b/tools/rimage/src/file_utils.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2018-2023 Intel Corporation. All rights reserved. +// +// Author: Adrian Warecki <adrian.warecki@intel.com> + +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> +#include <string.h> + +#include <rimage/file_utils.h> + +int file_error(const char *msg, const char *filename) +{ + int code = errno; + char sys_msg[256]; + + strerror_r(code, sys_msg, sizeof(sys_msg)); + + fprintf(stderr, "%s:\terror: %s. %s (errno = %d)\n", filename, msg, sys_msg, code); + return -code; +} + +int create_file_name(char *new_name, const size_t name_size, const char *template_name, + const char *new_ext) +{ + int len; + + assert(new_name); + + len = snprintf(new_name, name_size, "%s.%s", template_name, new_ext); + if (len >= name_size) { + fprintf(stderr, "error: output file name too long\n"); + return -ENAMETOOLONG; + } + + unlink(new_name); + + return 0; +} + +int get_file_size(FILE *f, const char* filename, size_t *size) +{ + int ret; + long pos; + assert(size); + + /* get file size */ + ret = fseek(f, 0, SEEK_END); + if (ret) + return file_error("unable to seek eof", filename); + + pos = ftell(f); + if (pos < 0) + return file_error("unable to get file size", filename); + + ret = fseek(f, 0, SEEK_SET); + if (ret) + return file_error("unable to seek set", filename); + + *size = pos; + return 0; +} diff --git a/tools/rimage/src/hash.c b/tools/rimage/src/hash.c new file mode 100644 index 000000000000..0604670e9c6e --- /dev/null +++ b/tools/rimage/src/hash.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> + * Keyon Jie <yang.jie@linux.intel.com> + * Adrian Warecki <adrian.warecki@intel.com> + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +#include <openssl/conf.h> +#include <openssl/evp.h> +#include <openssl/err.h> + +#include <rimage/rimage.h> +#include <rimage/manifest.h> +#include <rimage/hash.h> + +#define DEBUG_HASH 0 + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +void EVP_MD_CTX_free(EVP_MD_CTX *ctx); +EVP_MD_CTX *EVP_MD_CTX_new(void); + +static void *OPENSSL_zalloc(size_t num) +{ + void *ret = OPENSSL_malloc(num); + + if (ret) + memset(ret, 0, num); + return ret; +} + +EVP_MD_CTX *EVP_MD_CTX_new(void) +{ + return OPENSSL_zalloc(sizeof(EVP_MD_CTX)); +} + +void EVP_MD_CTX_free(EVP_MD_CTX *ctx) +{ + EVP_MD_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} +#endif + +static int hash_error(struct hash_context *context, int errcode, const char *msg) +{ + EVP_MD_CTX_free(context->context); + context->context = NULL; + context->state = HS_ERROR; + context->error = -errcode; + fprintf(stderr, "hash: %s\n", msg); + return context->error; +} + +int hash_init(struct hash_context *context, const EVP_MD *algo) +{ + assert(context); + assert(algo); + + context->error = 0; + context->digest_length = 0; + context->algo = algo; + + context->context = EVP_MD_CTX_new(); + if (!context->context) + return hash_error(context, ENOMEM, "Unable to allocate hash context."); + + if (!EVP_DigestInit_ex(context->context, context->algo, NULL)) { + EVP_MD_CTX_free(context->context); + return hash_error(context, ENOTRECOVERABLE, "Unable to initialize hash context."); + } + + context->state = HS_UPDATE; + return 0; +} + +int hash_sha256_init(struct hash_context *context) +{ + return hash_init(context, EVP_sha256()); +} + +int hash_sha384_init(struct hash_context *context) +{ + return hash_init(context, EVP_sha384()); +} + +int hash_update(struct hash_context *context, const void *data, size_t size) +{ + assert(context); + assert(data); + + if (context->error) + return context->error; + + assert(context->state == HS_UPDATE); + + if (!EVP_DigestUpdate(context->context, data, size)) + return hash_error(context, EINVAL, "Unable to update hash context."); + + return 0; +} + +int hash_finalize(struct hash_context *context) +{ + assert(context); + + if (context->error) + return context->error; + + assert(context->state == HS_UPDATE); + + if (!EVP_DigestFinal_ex(context->context, context->digest, &context->digest_length)) + return hash_error(context, EINVAL, "Unable to finalize hash context."); + + context->state = HS_DONE; + +#if DEBUG_HASH + fprintf(stdout, "Hash result is: "); + hash_print(context); +#endif + + EVP_MD_CTX_free(context->context); + context->context = NULL; + return 0; +} + +int hash_get_digest(struct hash_context *context, void *output, size_t output_len) +{ + assert(context); + assert(output); + + if (context->error) + return context->error; + + assert(context->state == HS_DONE); + + if (context->digest_length > output_len) + return -ENOBUFS; + + memcpy(output, context->digest, context->digest_length); + return context->digest_length; +} + +void hash_print(struct hash_context *context) +{ + unsigned int i; + + assert(context); + assert(context->state == HS_DONE); + assert(context->digest_length); + + for (i = 0; i < context->digest_length; i++) + fprintf(stdout, "%02x", context->digest[i]); + fprintf(stdout, "\n"); +} + +int hash_single(const void *data, size_t size, const EVP_MD *algo, void *output, size_t output_len) +{ + int algo_out_size; + + assert(algo); + assert(data); + assert(output); + + //algo_out_size = EVP_MD_get_size(algo); + algo_out_size = EVP_MD_size(algo); + if (algo_out_size <= 0) + return -EINVAL; + + if (output_len > algo_out_size) + return -ENOBUFS; + + if (!EVP_Digest(data, size, output, NULL, algo, NULL)) { + fprintf(stderr, "Unable to compute hash."); + return -ENOTRECOVERABLE; + } + + return 0; +} + +int hash_sha256(const void *data, size_t size, void *output, size_t output_len) +{ + return hash_single(data, size, EVP_sha256(), output, output_len); +} + +int hash_sha384(const void *data, size_t size, void *output, size_t output_len) +{ + return hash_single(data, size, EVP_sha384(), output, output_len); +} diff --git a/tools/rimage/src/include/rimage/adsp_config.h b/tools/rimage/src/include/rimage/adsp_config.h new file mode 100644 index 000000000000..e87c78c65f91 --- /dev/null +++ b/tools/rimage/src/include/rimage/adsp_config.h @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. + +#include <rimage/rimage.h> +#include <stdbool.h> + +int adsp_parse_config(const char *file, struct image *image); +void adsp_free(struct adsp *adsp); diff --git a/tools/rimage/src/include/rimage/cavs/cavs_ext_manifest.h b/tools/rimage/src/include/rimage/cavs/cavs_ext_manifest.h new file mode 100644 index 000000000000..4002f37fddb1 --- /dev/null +++ b/tools/rimage/src/include/rimage/cavs/cavs_ext_manifest.h @@ -0,0 +1,251 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2021 Intel Corporation. All rights reserved. + * + * Author: Rander Wang <rander.wang@linux.intel.com> + */ + +#ifndef __RIMAGE_CAVS_EXT_MANIFEST_H__ +#define __RIMAGE_CAVS_EXT_MANIFEST_H__ + +/* Structure of ext manifest : + * ExtendedManifestHeader + * ExtendedModuleConfig[0] + * SchedulingCapability[] + * PinDescr[] + * ExtendedModuleConfig[1] + * SchedulingCapability[] + * PinDescr[] + * ... + * ExtendedModuleConfig[N] + * SchedulingCapability[] + * PinDescr[] + */ + +/* ExtendedManifestHeader id $AE1 */ +#define EXTENDED_MANIFEST_MAGIC_HEADER_ID 0x31454124 +#define EXTENDED_MANIFEST_VERSION_MAJOR 0x0001 +#define EXTENDED_MANIFEST_VERSION_MINOR 0x0000 + +#define FW_MAX_EXT_MODULE_NUM 32 + +struct uuid_t { + uint32_t d0; + uint16_t d1; + uint16_t d2; + uint8_t d3; + uint8_t d4; + uint8_t d5; + uint8_t d6; + uint8_t d7; + uint8_t d8; + uint8_t d9; + uint8_t d10; +} __attribute__((packed)); + +union mod_multiples { + uint16_t ul; + struct { + uint16_t x1 : 1; + uint16_t x2 : 1; + uint16_t x3 : 1; + uint16_t x4 : 1; + uint16_t x5 : 1; + uint16_t x6 : 1; + uint16_t x7 : 1; + uint16_t x8 : 1; + uint16_t x9 : 1; + uint16_t x10 : 1; + uint16_t x11 : 1; + uint16_t x12 : 1; + uint16_t x13 : 1; + uint16_t x14 : 1; + uint16_t x15 : 1; + uint16_t all : 1; + } r; +} __attribute__((packed)); + +struct mod_scheduling_caps { + /* scheduling period in Samples (sample groups) (note: 1 Sample = 1 sample per channel) */ + uint16_t frame_length; + union mod_multiples multiples_supported; +} __attribute__((packed)); + +enum mod_pin_direction { + pin_input = 0, + pin_output = 1 +}; + +union mod_pin_caps { + uint32_t ul; + struct { + uint16_t direction : 1; /* 0 : input; 1: output */ + uint16_t reserved0 : 15; + uint16_t reserved1 : 16; + } r; +} __attribute__((packed)); + +union mod_sample_rates { + uint32_t ul; + struct { + uint32_t freq_8000 : 1; + uint32_t freq_11025 : 1; + uint32_t freq_12000 : 1; + uint32_t freq_16000 : 1; + uint32_t freq_18900 : 1; + uint32_t freq_22050 : 1; + uint32_t freq_24000 : 1; + uint32_t freq_32000 : 1; + uint32_t freq_37800 : 1; + uint32_t freq_44100 : 1; + uint32_t freq_48000 : 1; + uint32_t freq_64000 : 1; + uint32_t freq_88200 : 1; + uint32_t freq_96000 : 1; + uint32_t freq_176400 : 1; + uint32_t freq_192000 : 1; + uint32_t reserved : 16; + } r; +} __attribute__((packed)); + +union mod_sample_sizes { + uint32_t ul; + struct { + uint16_t bits_8 : 1; + uint16_t bits_16 : 1; + uint16_t bits_24 : 1; + uint16_t bits_32 : 1; + uint16_t bits_64 : 1; + uint16_t reserved0 : 11; + uint16_t reserved1 : 16; + } r; +} __attribute__((packed)); + +union mod_sample_containers { + uint32_t ul; + struct { + uint16_t bits_8 : 1; + uint16_t bits_16 : 1; + uint16_t bits_24 : 1; + uint16_t bits_32 : 1; + uint16_t bits_64 : 1; + uint16_t reserved0 : 11; + uint16_t reserved1 : 16; + } r; +} __attribute__((packed)); + +union mod_channel_config { + uint32_t ul; + struct { + /* FRONT_CENTER */ + uint32_t channel_mono : 1; + /* FRONT_LEFT | BACK_LEFT */ + uint32_t channel_dual_mono : 1; + /* FRONT_LEFT | FRONT_RIGHT */ + uint32_t channel_stereo : 1; + /* FRONT_LEFT | FRONT_RIGHT | LOW_FREQUENCY */ + uint32_t channel_2_1 : 1; + /* FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER */ + uint32_t channel_3_0 : 1; + /* FRONT_LEFT | FRONT_RIGHT | BACK_LEFT | BACK_RIGHT */ + uint32_t channel_quad : 1; + /* FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | BACK_CENTER */ + uint32_t channel_surround : 1; + /* FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | LOW_FREQUENCY */ + uint32_t channel_3_1 : 1; + /* FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | BACK_LEFT | BACK_RIGHT */ + uint32_t channel_5_0 : 1; + /* FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | SIDE_LEFT | SIDE_RIGHT */ + uint32_t channel_5_0_surround : 1; + /* FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | LOW_FREQUENCY | BACK_LEFT | + * BACK_RIGHT + */ + uint32_t channel_5_1 : 1; + /* FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | LOW_FREQUENCY | SIDE_LEFT | + * SIDE_RIGHT + */ + uint32_t channel_5_1_surround : 1; + /* FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | BACK_LEFT | BACK_RIGHT | + * FRONT_LEFT_OF_CENTER | FRONT_RIGHT_OF_CENTER + */ + uint32_t channel_7_0 : 1; + /* FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | BACK_LEFT | BACK_RIGHT | + * SIDE_LEFT | SIDE_RIGHT + */ + uint32_t channel_7_0_surround : 1; + /* FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | LOW_FREQUENCY | BACK_LEFT | + * BACK_RIGHT | FRONT_LEFT_OF_CENTER | FRONT_RIGHT_OF_CENTER + */ + uint32_t channel_7_1 : 1; + /* FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | LOW_FREQUENCY | BACK_LEFT | + * BACK_RIGHT | SIDE_LEFT | SIDE_RIGHT + */ + uint32_t channel_7_1_surround : 1; + uint32_t reserved : 16; + } r; +} __attribute__((packed)); + +enum mod_stream_type { + epcm = 0, /* PCM stream */ + emp3, /* MP3 encoded stream */ + eaac, /* AAC encoded stream */ + emax_stream_type, + estream_type_invalid = 0xFF +}; + +enum mod_type { + ebasefw = 0, + emixin, + emixout, + ecopier, + epeakvol, + eupdwmix, + emux, + esrc, + ewov, + efx, + eaec, + ekpb, + emicselect, + efxf, /*i.e.SmartAmp */ + eaudclass, + efakecopier, + eiodriver, + ewhm, + egdbstub, + esensing, + emax, + einvalid = emax +} ; + +struct fw_pin_description { + union mod_pin_caps caps; + enum mod_stream_type format_type; + union mod_sample_rates sample_rate; + union mod_sample_sizes sample_size; + union mod_sample_containers sample_container; + union mod_channel_config ch_cfg; +} __attribute__((packed)); + +struct fw_ext_man_cavs_header { + uint32_t id; + uint32_t len; /* sizeof(Extend Manifest) in bytes */ + uint16_t version_major; /* Version of Extended Manifest structure */ + uint16_t version_minor; /* Version of Extended Manifest structure */ + uint32_t num_module_entries; +} __attribute__((packed)); + +struct fw_ext_mod_config_header { + uint32_t ext_module_config_length; /* sizeof(fw_ext_mod_config_header) in bytes */ + uint32_t guid[4]; /* Module GUID */ + uint16_t version_major; /* Module version */ + uint16_t version_minor; /* Module version */ + uint16_t version_hotfix; /* Module version */ + uint16_t version_build; /* Module version */ + enum mod_type module_type; + uint32_t init_settings_min_size; /* Minimum size of initialization settings (in bytes) */ + uint16_t num_scheduling_capabilities; /* number scheduling capabilities supported by the module */ + uint16_t num_pin_entries; /* Number of Pin (inputs + ouptuts) */ +} __attribute__((packed)); + +#endif diff --git a/tools/rimage/src/include/rimage/cse.h b/tools/rimage/src/include/rimage/cse.h new file mode 100644 index 000000000000..9a14b93b99f6 --- /dev/null +++ b/tools/rimage/src/include/rimage/cse.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + */ + +#ifndef __CSE_H__ +#define __CSE_H__ + +#include <stdint.h> + +struct image; + +#define CSE_HEADER_MAKER 0x44504324 /* "DPC$" */ + +struct CsePartitionDirHeader { + uint32_t header_marker; + uint32_t nb_entries; + uint8_t header_version; + uint8_t entry_version; + uint8_t header_length; + uint8_t checksum; + uint8_t partition_name[4]; +} __attribute__((packed)); + +struct CsePartitionDirHeader_v2_5 { + uint32_t header_marker; + uint32_t nb_entries; + uint8_t header_version; + uint8_t entry_version; + uint8_t header_length; + uint8_t not_used; /* set to zero - old checksum */ + uint8_t partition_name[4]; + uint32_t checksum; /* crc32 checksum */ +} __attribute__((packed)); + +struct CsePartitionDirEntry { + uint8_t entry_name[12]; + uint32_t offset; + uint32_t length; + uint32_t reserved; +} __attribute__((packed)); + +void ri_cse_create(struct image *image); +void ri_cse_create_v2_5(struct image *image); +void ri_cse_create_ace_v1_5(struct image *image); + +#endif diff --git a/tools/rimage/src/include/rimage/css.h b/tools/rimage/src/include/rimage/css.h new file mode 100644 index 000000000000..6283cdaf9042 --- /dev/null +++ b/tools/rimage/src/include/rimage/css.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + */ + +#ifndef __CSS_H__ +#define __CSS_H__ + +#include <stdint.h> + +struct image; + +#define MAN_CSS_LT_MODULE_TYPE 0x00000006 +#define MAN_CSS_MOD_TYPE 4 +#define MAN_CSS_HDR_SIZE 161 /* in words */ +#define MAN_CSS_HDR_SIZE_2_5 225 /* in words */ +#define MAN_CSS_HDR_VERSION 0x10000 +#define MAN_CSS_HDR_VERSION_2_5 0x21000 +#define MAN_CSS_MOD_VENDOR 0x8086 +#define MAN_CSS_HDR_ID {'$', 'M', 'N', '2'} + +#define MAN_CSS_KEY_SIZE (MAN_RSA_KEY_MODULUS_LEN >> 2) +#define MAN_CSS_MOD_SIZE (MAN_RSA_KEY_MODULUS_LEN >> 2) +#define MAN_CSS_MOD_SIZE_2_5 (MAN_RSA_KEY_MODULUS_LEN_2_5 >> 2) +#define MAN_CSS_EXP_SIZE (MAN_RSA_KEY_EXPONENT_LEN >> 2) +#define MAN_CSS_MAN_SIZE_V1_8 \ + (sizeof(struct fw_image_manifest_v1_8) >> 2) +#define MAN_CSS_MAN_SIZE_V1_5 \ + (sizeof(struct fw_image_manifest_v1_5) >> 2) + +/* + * RSA Key and Crypto + */ +#define MAN_RSA_KEY_MODULUS_LEN 256 +#define MAN_RSA_KEY_MODULUS_LEN_2_5 384 +#define MAN_RSA_KEY_EXPONENT_LEN 4 +#define MAN_RSA_SIGNATURE_LEN 256 +#define MAN_RSA_SIGNATURE_LEN_2_5 384 + +struct fw_version { + uint16_t major_version; + uint16_t minor_version; + uint16_t hotfix_version; + uint16_t build_version; +} __attribute__((packed)); + +struct css_header_v2_5 { + uint32_t header_type; + uint32_t header_len; + uint32_t header_version; + uint32_t reserved0; /* must be 0x1 */ + uint32_t module_vendor; + uint32_t date; + uint32_t size; + uint8_t header_id[4]; + uint32_t padding; /* must be 0x0 */ + struct fw_version version; + uint32_t svn; + uint32_t reserved1[18]; /* must be 0x0 */ + uint32_t modulus_size; + uint32_t exponent_size; + uint8_t modulus[MAN_RSA_KEY_MODULUS_LEN_2_5]; + uint8_t exponent[MAN_RSA_KEY_EXPONENT_LEN]; + uint8_t signature[MAN_RSA_SIGNATURE_LEN_2_5]; +} __attribute__((packed)); + +struct css_header_v1_8 { + uint32_t header_type; + uint32_t header_len; + uint32_t header_version; + uint32_t reserved0; /* must be 0x0 */ + uint32_t module_vendor; + uint32_t date; + uint32_t size; + uint8_t header_id[4]; + uint32_t padding; /* must be 0x0 */ + struct fw_version version; + uint32_t svn; + uint32_t reserved1[18]; /* must be 0x0 */ + uint32_t modulus_size; + uint32_t exponent_size; + uint8_t modulus[MAN_RSA_KEY_MODULUS_LEN]; + uint8_t exponent[MAN_RSA_KEY_EXPONENT_LEN]; + uint8_t signature[MAN_RSA_SIGNATURE_LEN]; +} __attribute__((packed)); + +struct css_header_v1_5 { + uint32_t module_type; + uint32_t header_len; + uint32_t header_version; + uint32_t reserved0; /* must be 0x0 */ + uint32_t module_vendor; + uint32_t date; + uint32_t size; + uint32_t key_size; + uint32_t modulus_size; + uint32_t exponent_size; + uint32_t reserved[22]; + uint8_t modulus[MAN_RSA_KEY_MODULUS_LEN]; + uint8_t exponent[MAN_RSA_KEY_EXPONENT_LEN]; + uint8_t signature[MAN_RSA_SIGNATURE_LEN]; +} __attribute__((packed)); + +void ri_css_v1_8_hdr_create(struct image *image); +void ri_css_v1_5_hdr_create(struct image *image); +void ri_css_v2_5_hdr_create(struct image *image); + +#endif diff --git a/tools/rimage/src/include/rimage/elf.h b/tools/rimage/src/include/rimage/elf.h new file mode 100644 index 000000000000..13a4965e059e --- /dev/null +++ b/tools/rimage/src/include/rimage/elf.h @@ -0,0 +1,936 @@ +/* SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1996-1998 John D. Polstra. All rights reserved. + * Copyright (c) 2001 David E. O'Brien + * Portions Copyright 2009 The Go Authors. All rights reserved. + */ + +#ifndef __ELF_H__ +#define __ELF_H__ + +/* + * ELF definitions that are independent of architecture or word size. + */ + +/* + * Note header. The ".note" section contains an array of notes. Each + * begins with this header, aligned to a word boundary. Immediately + * following the note header is n_namesz bytes of name, padded to the + * next word boundary. Then comes n_descsz bytes of descriptor, again + * padded to a word boundary. The values of n_namesz and n_descsz do + * not include the padding. + */ + +#include <stdint.h> + +typedef uint64_t uint64; +typedef uint32_t uint32; +typedef uint16_t uint16; +typedef uint8_t uint8; + +typedef int64_t int64; +typedef int32_t int32; +typedef int16_t int16; +typedef int8_t int8; + + +typedef struct { + uint32 n_namesz; /* Length of name. */ + uint32 n_descsz; /* Length of descriptor. */ + uint32 n_type; /* Type of this note. */ +} Elf_Note; + +/* Indexes into the e_ident array. Keep synced with + http://www.sco.com/developer/gabi/ch4.eheader.html */ +#define EI_MAG0 0 /* Magic number, byte 0. */ +#define EI_MAG1 1 /* Magic number, byte 1. */ +#define EI_MAG2 2 /* Magic number, byte 2. */ +#define EI_MAG3 3 /* Magic number, byte 3. */ +#define EI_CLASS 4 /* Class of machine. */ +#define EI_DATA 5 /* Data format. */ +#define EI_VERSION 6 /* ELF format version. */ +#define EI_OSABI 7 /* Operating system / ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define OLD_EI_BRAND 8 /* Start of architecture identification. */ +#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ +#define EI_NIDENT 16 /* Size of e_ident array. */ + +/* Values for the magic number bytes. */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" /* magic string */ +#define SELFMAG 4 /* magic string size */ + +/* Values for e_ident[EI_VERSION] and e_version. */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* Values for e_ident[EI_CLASS]. */ +#define ELFCLASSNONE 0 /* Unknown class. */ +#define ELFCLASS32 1 /* 32-bit architecture. */ +#define ELFCLASS64 2 /* 64-bit architecture. */ + +/* Values for e_ident[EI_DATA]. */ +#define ELFDATANONE 0 /* Unknown data format. */ +#define ELFDATA2LSB 1 /* 2's complement little-endian. */ +#define ELFDATA2MSB 2 /* 2's complement big-endian. */ + +/* Values for e_ident[EI_OSABI]. */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_AIX 7 /* AIX */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_OPENVMS 13 /* Open VMS */ +#define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define ELFOSABI_SYSV ELFOSABI_NONE /* symbol used in old spec */ +#define ELFOSABI_MONTEREY ELFOSABI_AIX /* Monterey */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ +#define ET_LOOS 0xfe00 /* First operating system specific. */ +#define ET_HIOS 0xfeff /* Last operating system-specific. */ +#define ET_LOPROC 0xff00 /* First processor-specific. */ +#define ET_HIPROC 0xffff /* Last processor-specific. */ + +/* Values for e_machine. */ +#define EM_NONE 0 /* Unknown machine. */ +#define EM_M32 1 /* AT&T WE32100. */ +#define EM_SPARC 2 /* Sun SPARC. */ +#define EM_386 3 /* Intel i386. */ +#define EM_68K 4 /* Motorola 68000. */ +#define EM_88K 5 /* Motorola 88000. */ +#define EM_860 7 /* Intel i860. */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only. */ +#define EM_S370 9 /* IBM System/370. */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 Little-Endian. */ +#define EM_PARISC 15 /* HP PA-RISC. */ +#define EM_VPP500 17 /* Fujitsu VPP500. */ +#define EM_SPARC32PLUS 18 /* SPARC v8plus. */ +#define EM_960 19 /* Intel 80960. */ +#define EM_PPC 20 /* PowerPC 32-bit. */ +#define EM_PPC64 21 /* PowerPC 64-bit. */ +#define EM_S390 22 /* IBM System/390. */ +#define EM_V800 36 /* NEC V800. */ +#define EM_FR20 37 /* Fujitsu FR20. */ +#define EM_RH32 38 /* TRW RH-32. */ +#define EM_RCE 39 /* Motorola RCE. */ +#define EM_ARM 40 /* ARM. */ +#define EM_SH 42 /* Hitachi SH. */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit. */ +#define EM_TRICORE 44 /* Siemens TriCore embedded processor. */ +#define EM_ARC 45 /* Argonaut RISC Core. */ +#define EM_H8_300 46 /* Hitachi H8/300. */ +#define EM_H8_300H 47 /* Hitachi H8/300H. */ +#define EM_H8S 48 /* Hitachi H8S. */ +#define EM_H8_500 49 /* Hitachi H8/500. */ +#define EM_IA_64 50 /* Intel IA-64 Processor. */ +#define EM_MIPS_X 51 /* Stanford MIPS-X. */ +#define EM_COLDFIRE 52 /* Motorola ColdFire. */ +#define EM_68HC12 53 /* Motorola M68HC12. */ +#define EM_MMA 54 /* Fujitsu MMA. */ +#define EM_PCP 55 /* Siemens PCP. */ +#define EM_NCPU 56 /* Sony nCPU. */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor. */ +#define EM_STARCORE 58 /* Motorola Star*Core processor. */ +#define EM_ME16 59 /* Toyota ME16 processor. */ +#define EM_ST100 60 /* STMicroelectronics ST100 processor. */ +#define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */ +#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ + +/* Non-standard or deprecated. */ +#define EM_486 6 /* Intel i486. */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_ALPHA_STD 41 /* Digital Alpha (standard value). */ +#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI) */ + +/* Special section indexes. */ +#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ +#define SHN_LORESERVE 0xff00 /* First of reserved range. */ +#define SHN_LOPROC 0xff00 /* First processor-specific. */ +#define SHN_HIPROC 0xff1f /* Last processor-specific. */ +#define SHN_LOOS 0xff20 /* First operating system-specific. */ +#define SHN_HIOS 0xff3f /* Last operating system-specific. */ +#define SHN_ABS 0xfff1 /* Absolute values. */ +#define SHN_COMMON 0xfff2 /* Common data. */ +#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */ +#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends */ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relocation section - no addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_INIT_ARRAY 14 /* Initialization function pointers. */ +#define SHT_FINI_ARRAY 15 /* Termination function pointers. */ +#define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs. */ +#define SHT_GROUP 17 /* Section group. */ +#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */ +#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ +#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ +#define SHT_GNU_VERDEF 0x6ffffffd +#define SHT_GNU_VERNEED 0x6ffffffe +#define SHT_GNU_VERSYM 0x6fffffff +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Flags for sh_flags. */ +#define SHF_WRITE 0x1 /* Section contains writable data. */ +#define SHF_ALLOC 0x2 /* Section occupies memory. */ +#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ +#define SHF_MERGE 0x10 /* Section may be merged. */ +#define SHF_STRINGS 0x20 /* Section contains strings. */ +#define SHF_INFO_LINK 0x40 /* sh_info holds section index. */ +#define SHF_LINK_ORDER 0x80 /* Special ordering requirements. */ +#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */ +#define SHF_GROUP 0x200 /* Member of section group. */ +#define SHF_TLS 0x400 /* Section contains TLS data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */ + +/* Values for p_type. */ +#define PT_NULL 0 /* Unused entry. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ +#define PT_INTERP 3 /* Pathname of interpreter. */ +#define PT_NOTE 4 /* Auxiliary information. */ +#define PT_SHLIB 5 /* Reserved (not used). */ +#define PT_PHDR 6 /* Location of program header itself. */ +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* First OS-specific. */ +#define PT_HIOS 0x6fffffff /* Last OS-specific. */ +#define PT_LOPROC 0x70000000 /* First processor-specific type. */ +#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ +#define PT_GNU_STACK 0x6474e551 +#define PT_PAX_FLAGS 0x65041580 + +/* Values for p_flags. */ +#define PF_X 0x1 /* Executable. */ +#define PF_W 0x2 /* Writable. */ +#define PF_R 0x4 /* Readable. */ +#define PF_MASKOS 0x0ff00000 /* Operating system-specific. */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific. */ + +/* Values for d_tag. */ +#define DT_NULL 0 /* Terminating entry. */ +/* String table offset of a needed shared library. */ +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ +#define DT_PLTGOT 3 /* Processor-dependent address. */ +#define DT_HASH 4 /* Address of symbol hash table. */ +#define DT_STRTAB 5 /* Address of string table. */ +#define DT_SYMTAB 6 /* Address of symbol table. */ +#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ +#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ +#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ +#define DT_STRSZ 10 /* Size of string table. */ +#define DT_SYMENT 11 /* Size of each symbol table entry. */ +#define DT_INIT 12 /* Address of initialization function. */ +#define DT_FINI 13 /* Address of finalization function. */ +/* String table offset of shared object name. */ +#define DT_SONAME 14 +#define DT_RPATH 15 /* String table offset of library path. [sup] */ +#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ +#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ +#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ +#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ +#define DT_PLTREL 20 /* Type of relocation used for PLT. */ +#define DT_DEBUG 21 /* Reserved (not used). */ +/* Indicates there may be relocations in non-writable segments. [sup] */ +#define DT_TEXTREL 22 +#define DT_JMPREL 23 /* Address of PLT relocations. */ +#define DT_BIND_NOW 24 /* [sup] */ +/* Address of the array of pointers to initialization functions */ +#define DT_INIT_ARRAY 25 +/* Address of the array of pointers to termination functions */ +#define DT_FINI_ARRAY 26 +/* Size in bytes of the array of initialization functions. */ +#define DT_INIT_ARRAYSZ 27 +/* Size in bytes of the array of terminationfunctions. */ +#define DT_FINI_ARRAYSZ 28 +/* String table offset of a null-terminated library search path string. */ +#define DT_RUNPATH 29 +#define DT_FLAGS 30 /* Object specific flag values. */ +/* Values greater than or equal to DT_ENCODING and less than + DT_LOOS follow the rules for the interpretation of the d_un + union as follows: even == 'd_ptr', even == 'd_val' or none */ +#define DT_ENCODING 32 +/* Address of the array of pointers to pre-initialization functions. */ +#define DT_PREINIT_ARRAY 32 +/* Size in bytes of the array of pre-initialization functions. */ +#define DT_PREINIT_ARRAYSZ 33 +#define DT_LOOS 0x6000000d /* First OS-specific */ +#define DT_HIOS 0x6ffff000 /* Last OS-specific */ +#define DT_LOPROC 0x70000000 /* First processor-specific type. */ +#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff +#define DT_VERSYM 0x6ffffff0 + +/* Values for DT_FLAGS */ +/* Indicates that the object being loaded may make reference to + the $ORIGIN substitution string */ +#define DF_ORIGIN 0x0001 +#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ +/* Indicates there may be relocations in non-writable segments. */ +#define DF_TEXTREL 0x0004 +/* Indicates that the dynamic linker should process all + relocations for the object containing this entry before + transferring control to the program. */ +#define DF_BIND_NOW 0x0008 +/* Indicates that the shared object or executable contains code + using a static thread-local storage scheme. */ +#define DF_STATIC_TLS 0x0010 + +/* Values for n_type. Used in core files. */ +#define NT_PRSTATUS 1 /* Process status. */ +#define NT_FPREGSET 2 /* Floating point registers. */ +#define NT_PRPSINFO 3 /* Process state info. */ + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_LOOS 10 /* Reserved range for operating system */ +#define STB_HIOS 12 /* specific semantics. */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific semantics. */ + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* Unspecified type. */ +#define STT_OBJECT 1 /* Data object. */ +#define STT_FUNC 2 /* Function. */ +#define STT_SECTION 3 /* Section. */ +#define STT_FILE 4 /* Source file. */ +#define STT_COMMON 5 /* Uninitialized common block. */ +#define STT_TLS 6 /* TLS object. */ +#define STT_LOOS 10 /* Reserved range for operating system */ +#define STT_HIOS 12 /* specific semantics. */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific semantics. */ + +/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */ +#define STV_DEFAULT 0x0 /* Default visibility (see binding). */ +#define STV_INTERNAL 0x1 /* Special meaning in relocatable objects. */ +#define STV_HIDDEN 0x2 /* Not visible. */ +#define STV_PROTECTED 0x3 /* Visible but not preemptible. */ + +/* Special symbol table indexes. */ +#define STN_UNDEF 0 /* Undefined symbol index. */ + +/* + * ELF definitions common to all 32-bit architectures. + */ + +typedef uint32 Elf32_Addr; +typedef uint16 Elf32_Half; +typedef uint32 Elf32_Off; +typedef int32 Elf32_Sword; +typedef uint32 Elf32_Word; + +typedef Elf32_Word Elf32_Hashelt; + +/* Non-standard class-dependent datatype used for abstraction. */ +typedef Elf32_Word Elf32_Size; +typedef Elf32_Sword Elf32_Ssize; + +/* + * ELF header. + */ + +typedef struct { + unsigned char ident[EI_NIDENT]; /* File identification. */ + Elf32_Half type; /* File type. */ + Elf32_Half machine; /* Machine architecture. */ + Elf32_Word version; /* ELF format version. */ + Elf32_Addr entry; /* Entry point. */ + Elf32_Off phoff; /* Program header file offset. */ + Elf32_Off shoff; /* Section header file offset. */ + Elf32_Word flags; /* Architecture-specific flags. */ + Elf32_Half ehsize; /* Size of ELF header in bytes. */ + Elf32_Half phentsize; /* Size of program header entry. */ + Elf32_Half phnum; /* Number of program header entries. */ + Elf32_Half shentsize; /* Size of section header entry. */ + Elf32_Half shnum; /* Number of section header entries. */ + Elf32_Half shstrndx; /* Section name strings section. */ +} Elf32_Ehdr; + +/* + * Section header. + */ + +typedef struct { + Elf32_Word name; /* Section name (index into the + section header string table). */ + Elf32_Word type; /* Section type. */ + Elf32_Word flags; /* Section flags. */ + Elf32_Addr vaddr; /* Address in memory image. */ + Elf32_Off off; /* Offset in file. */ + Elf32_Word size; /* Size in bytes. */ + Elf32_Word link; /* Index of a related section. */ + Elf32_Word info; /* Depends on section type. */ + Elf32_Word addralign; /* Alignment in bytes. */ + Elf32_Word entsize; /* Size of each entry in section. */ +} Elf32_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf32_Word type; /* Entry type. */ + Elf32_Off off; /* File offset of contents. */ + Elf32_Addr vaddr; /* Virtual address in memory image. */ + Elf32_Addr paddr; /* Physical address (not used). */ + Elf32_Word filesz; /* Size of contents in file. */ + Elf32_Word memsz; /* Size of contents in memory. */ + Elf32_Word flags; /* Access permission flags. */ + Elf32_Word align; /* Alignment in memory and file. */ +} Elf32_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf32_Sword d_tag; /* Entry type. */ + union { + Elf32_Word d_val; /* Integer value. */ + Elf32_Addr d_ptr; /* Address value. */ + } d_un; +} Elf32_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf32_Addr off; /* Location to be relocated. */ + Elf32_Word info; /* Relocation type and symbol index. */ +} Elf32_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf32_Addr off; /* Location to be relocated. */ + Elf32_Word info; /* Relocation type and symbol index. */ + Elf32_Sword addend; /* Addend. */ +} Elf32_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +/* Macro for constructing r_info from field values. */ +#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) + +/* + * Relocation types. + */ + +#define R_X86_64_NONE 0 /* No relocation. */ +#define R_X86_64_64 1 /* Add 64 bit symbol value. */ +#define R_X86_64_PC32 2 /* PC-relative 32 bit signed sym value. */ +#define R_X86_64_GOT32 3 /* PC-relative 32 bit GOT offset. */ +#define R_X86_64_PLT32 4 /* PC-relative 32 bit PLT offset. */ +#define R_X86_64_COPY 5 /* Copy data from shared object. */ +#define R_X86_64_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_X86_64_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_X86_64_RELATIVE 8 /* Add load address of shared object. */ +#define R_X86_64_GOTPCREL 9 /* Add 32 bit signed pcrel offset to GOT. */ +#define R_X86_64_32 10 /* Add 32 bit zero extended symbol value */ +#define R_X86_64_32S 11 /* Add 32 bit sign extended symbol value */ +#define R_X86_64_16 12 /* Add 16 bit zero extended symbol value */ +#define R_X86_64_PC16 13 /* Add 16 bit signed extended pc relative symbol value */ +#define R_X86_64_8 14 /* Add 8 bit zero extended symbol value */ +#define R_X86_64_PC8 15 /* Add 8 bit signed extended pc relative symbol value */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in static TLS block */ +#define R_X86_64_TLSGD 19 /* PC relative offset to GD GOT entry */ +#define R_X86_64_TLSLD 20 /* PC relative offset to LD GOT entry */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */ +#define R_X86_64_TPOFF32 23 /* Offset in static TLS block */ + +#define R_X86_64_COUNT 24 /* Count of defined relocation types. */ + + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_OP_PUSH 12 /* OP stack push */ +#define R_ALPHA_OP_STORE 13 /* OP stack pop and store */ +#define R_ALPHA_OP_PSUB 14 /* OP stack subtract */ +#define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */ +#define R_ALPHA_GPVALUE 16 +#define R_ALPHA_GPRELHIGH 17 +#define R_ALPHA_GPRELLOW 18 +#define R_ALPHA_IMMED_GP_16 19 +#define R_ALPHA_IMMED_GP_HI32 20 +#define R_ALPHA_IMMED_SCN_HI32 21 +#define R_ALPHA_IMMED_BR_HI32 22 +#define R_ALPHA_IMMED_LO32 23 +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ + +#define R_ALPHA_COUNT 28 + + +#define R_ARM_NONE 0 /* No relocation. */ +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy data from shared object. */ +#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */ +#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */ +#define R_ARM_RELATIVE 23 /* Add load address of shared object. */ +#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */ +#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */ +#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */ +#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */ +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_V4BX 40 +#define R_ARM_GOT_PREL 96 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_TLS_IE32 107 +#define R_ARM_TLS_LE32 108 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS32 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +#define R_ARM_COUNT 38 /* Count of defined relocation types. */ + + +#define R_386_NONE 0 /* No relocation. */ +#define R_386_32 1 /* Add symbol value. */ +#define R_386_PC32 2 /* Add PC-relative symbol value. */ +#define R_386_GOT32 3 /* Add PC-relative GOT offset. */ +#define R_386_PLT32 4 /* Add PC-relative PLT offset. */ +#define R_386_COPY 5 /* Copy data from shared object. */ +#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_386_RELATIVE 8 /* Add load address of shared object. */ +#define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */ +#define R_386_GOTPC 10 /* Add PC-relative GOT table address. */ +#define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */ +#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */ +#define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */ +#define R_386_TLS_LE 17 /* Negative offset relative to static TLS */ +#define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */ +#define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */ +#define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */ +#define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */ +#define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */ +#define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */ +#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */ + +#define R_386_COUNT 38 /* Count of defined relocation types. */ + +#define R_PPC_NONE 0 /* No relocation. */ +#define R_PPC_ADDR32 1 +#define R_PPC_ADDR24 2 +#define R_PPC_ADDR16 3 +#define R_PPC_ADDR16_LO 4 +#define R_PPC_ADDR16_HI 5 +#define R_PPC_ADDR16_HA 6 +#define R_PPC_ADDR14 7 +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 +#define R_PPC_REL14 11 +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +#define R_PPC_COUNT 37 /* Count of defined relocation types. */ + +#define R_PPC_TLS 67 +#define R_PPC_DTPMOD32 68 +#define R_PPC_TPREL16 69 +#define R_PPC_TPREL16_LO 70 +#define R_PPC_TPREL16_HI 71 +#define R_PPC_TPREL16_HA 72 +#define R_PPC_TPREL32 73 +#define R_PPC_DTPREL16 74 +#define R_PPC_DTPREL16_LO 75 +#define R_PPC_DTPREL16_HI 76 +#define R_PPC_DTPREL16_HA 77 +#define R_PPC_DTPREL32 78 +#define R_PPC_GOT_TLSGD16 79 +#define R_PPC_GOT_TLSGD16_LO 80 +#define R_PPC_GOT_TLSGD16_HI 81 +#define R_PPC_GOT_TLSGD16_HA 82 +#define R_PPC_GOT_TLSLD16 83 +#define R_PPC_GOT_TLSLD16_LO 84 +#define R_PPC_GOT_TLSLD16_HI 85 +#define R_PPC_GOT_TLSLD16_HA 86 +#define R_PPC_GOT_TPREL16 87 +#define R_PPC_GOT_TPREL16_LO 88 +#define R_PPC_GOT_TPREL16_HI 89 +#define R_PPC_GOT_TPREL16_HA 90 + +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 + + /* Count of defined relocation types. */ +#define R_PPC_EMB_COUNT (R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1) + + +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 +#define R_SPARC_PC_HH22 37 +#define R_SPARC_PC_HM10 38 +#define R_SPARC_PC_LM22 39 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_GLOB_JMP 42 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 +#define R_SPARC_DISP64 46 +#define R_SPARC_PLT64 47 +#define R_SPARC_HIX22 48 +#define R_SPARC_LOX10 49 +#define R_SPARC_H44 50 +#define R_SPARC_M44 51 +#define R_SPARC_L44 52 +#define R_SPARC_REGISTER 53 +#define R_SPARC_UA64 54 +#define R_SPARC_UA16 55 + + +/* + * Magic number for the elf trampoline, chosen wisely to be an immediate + * value. + */ +#define ARM_MAGIC_TRAMP_NUMBER 0x5c000003 + + +/* + * Symbol table entries. + */ + +typedef struct { + Elf32_Word name; /* String table index of name. */ + Elf32_Addr value; /* Symbol value. */ + Elf32_Word size; /* Size of associated object. */ + unsigned char info; /* Type and binding information. */ + unsigned char other; /* Reserved (not used). */ + Elf32_Half shndx; /* Section index of symbol. */ +} Elf32_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF32_ST_BIND(info) ((info) >> 4) +#define ELF32_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Macro for accessing the fields of st_other. */ +#define ELF32_ST_VISIBILITY(oth) ((oth) & 0x3) + +/* + * ELF definitions common to all 64-bit architectures. + */ + +typedef uint64 Elf64_Addr; +typedef uint16 Elf64_Half; +typedef uint64 Elf64_Off; +typedef int32 Elf64_Sword; +typedef int64 Elf64_Sxword; +typedef uint32 Elf64_Word; +typedef uint64 Elf64_Xword; + +/* + * Types of dynamic symbol hash table bucket and chain elements. + * + * This is inconsistent among 64 bit architectures, so a machine dependent + * typedef is required. + */ + +#ifdef __alpha__ +typedef Elf64_Off Elf64_Hashelt; +#else +typedef Elf64_Word Elf64_Hashelt; +#endif + +/* Non-standard class-dependent datatype used for abstraction. */ +typedef Elf64_Xword Elf64_Size; +typedef Elf64_Sxword Elf64_Ssize; + +/* + * ELF header. + */ + +typedef struct { + unsigned char ident[EI_NIDENT]; /* File identification. */ + Elf64_Half type; /* File type. */ + Elf64_Half machine; /* Machine architecture. */ + Elf64_Word version; /* ELF format version. */ + Elf64_Addr entry; /* Entry point. */ + Elf64_Off phoff; /* Program header file offset. */ + Elf64_Off shoff; /* Section header file offset. */ + Elf64_Word flags; /* Architecture-specific flags. */ + Elf64_Half ehsize; /* Size of ELF header in bytes. */ + Elf64_Half phentsize; /* Size of program header entry. */ + Elf64_Half phnum; /* Number of program header entries. */ + Elf64_Half shentsize; /* Size of section header entry. */ + Elf64_Half shnum; /* Number of section header entries. */ + Elf64_Half shstrndx; /* Section name strings section. */ +} Elf64_Ehdr; + +/* + * Section header. + */ + +typedef struct Elf64_Shdr Elf64_Shdr; +struct Elf64_Shdr { + Elf64_Word name; /* Section name (index into the + section header string table). */ + Elf64_Word type; /* Section type. */ + Elf64_Xword flags; /* Section flags. */ + Elf64_Addr addr; /* Address in memory image. */ + Elf64_Off off; /* Offset in file. */ + Elf64_Xword size; /* Size in bytes. */ + Elf64_Word link; /* Index of a related section. */ + Elf64_Word info; /* Depends on section type. */ + Elf64_Xword addralign; /* Alignment in bytes. */ + Elf64_Xword entsize; /* Size of each entry in section. */ +}; + +/* + * Program header. + */ + +typedef struct { + Elf64_Word type; /* Entry type. */ + Elf64_Word flags; /* Access permission flags. */ + Elf64_Off off; /* File offset of contents. */ + Elf64_Addr vaddr; /* Virtual address in memory image. */ + Elf64_Addr paddr; /* Physical address (not used). */ + Elf64_Xword filesz; /* Size of contents in file. */ + Elf64_Xword memsz; /* Size of contents in memory. */ + Elf64_Xword align; /* Alignment in memory and file. */ +} Elf64_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf64_Sxword d_tag; /* Entry type. */ + union { + Elf64_Xword d_val; /* Integer value. */ + Elf64_Addr d_ptr; /* Address value. */ + } d_un; +} Elf64_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf64_Addr off; /* Location to be relocated. */ + Elf64_Xword info; /* Relocation type and symbol index. */ +} Elf64_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf64_Addr off; /* Location to be relocated. */ + Elf64_Xword info; /* Relocation type and symbol index. */ + Elf64_Sxword addend; /* Addend. */ +} Elf64_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((info) & 0xffffffffL) + +/* Macro for constructing r_info from field values. */ +#define ELF64_R_INFO(sym, type) ((((uint64)(sym)) << 32) + (((uint64)(type)) & 0xffffffffULL)) + +/* + * Symbol table entries. + */ + +typedef struct { + Elf64_Word name; /* String table index of name. */ + unsigned char info; /* Type and binding information. */ + unsigned char other; /* Reserved (not used). */ + Elf64_Half shndx; /* Section index of symbol. */ + Elf64_Addr value; /* Symbol value. */ + Elf64_Xword size; /* Size of associated object. */ +} Elf64_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF64_ST_BIND(info) ((info) >> 4) +#define ELF64_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Macro for accessing the fields of st_other. */ +#define ELF64_ST_VISIBILITY(oth) ((oth) & 0x3) + +/* + * Go linker interface + */ + +#define ELF64HDRSIZE 64 +#define ELF64PHDRSIZE 56 +#define ELF64SHDRSIZE 64 +#define ELF64RELSIZE 16 +#define ELF64RELASIZE 24 +#define ELF64SYMSIZE sizeof(Elf64_Sym) + +#define ELF32HDRSIZE sizeof(Elf32_Ehdr) +#define ELF32PHDRSIZE sizeof(Elf32_Phdr) +#define ELF32SHDRSIZE sizeof(Elf32_Shdr) +#define ELF32SYMSIZE sizeof(Elf32_Sym) +#define ELF32RELSIZE 8 + +#endif /* __ELF_H__ */ diff --git a/tools/rimage/src/include/rimage/elf_file.h b/tools/rimage/src/include/rimage/elf_file.h new file mode 100644 index 000000000000..13bfe98cf1f7 --- /dev/null +++ b/tools/rimage/src/include/rimage/elf_file.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Adrian Warecki <adrian.warecki@intel.com> + */ + +#ifndef __ELF_FILE_H__ +#define __ELF_FILE_H__ + +#include <stddef.h> + +#include "elf.h" + +struct elf_section_header { + Elf32_Shdr data; + char *name; +}; + +struct elf_section { + struct elf_section_header header; + void *data; +}; + +struct elf_strings { + struct elf_section section; +}; + +struct elf_file { + FILE *file; + char *filename; + size_t file_size; + Elf32_Ehdr header; + struct elf_section_header *sections; + Elf32_Phdr *programs; + uint16_t sections_count; + uint16_t programs_count; +}; + +/** + * Open elf file + * + * @param [out]elf elf file structure + * @param [in]filename File name to open + * @return error code, 0 when success + */ +int elf_open(struct elf_file *elf, const char *filename); + +/** + * Close elf file and release resources + * + * @param elf elf file structure + */ +void elf_free(struct elf_file *elf); + +/** + * Print elf file header + * + * @param elf elf file structure + */ +void elf_header_print(const struct elf_file *elf); + +/** + * Print program headers + * + * @param elf elf file structure + */ +void elf_print_programs(const struct elf_file *elf); + +/** + * Print single program header + * + * @param header program header structure + */ +void elf_program_header_print(const Elf32_Phdr *header); + +/** + * Print elf sections headers + * + * @param elf elf file structure + */ +void elf_print_sections(const struct elf_file *elf); + +/** + * Return section header by index + * + * @param [in]elf elf file structure + * @param [in]index section index + * @param [out]header section header data + * @return error code, 0 when success + */ +int elf_section_header_get_by_index(const struct elf_file *elf, int index, + const struct elf_section_header **header); + +/** + * Return section header by index + * + * @param [in]elf elf file structure + * @param [in]index section index + * @param [out]header section header data + * @return error code, 0 when success + */ +int elf_section_header_get_by_name(const struct elf_file *elf, const char* name, + const struct elf_section_header **header); +/** + * Print elf section header + * + * @param header section header structure + */ +void elf_section_header_print(const struct elf_section_header *header); + +/** + * Read elf section using given header + * + * @param [in]elf elf file structure + * @param [in]header section header + * @param [out]section section data + * @return error code, 0 when success + */ +int elf_section_read(const struct elf_file *elf, const struct elf_section_header *header, + struct elf_section *section); + +/** +* Read elf section using given header to specified buffer +* +* @param [in]elf elf file structure +* @param [in]header section header +* @param [out]buffer buffer for a section data +* @param [in]size buffer size +* @return error code, 0 when success +*/ +int elf_section_read_content(const struct elf_file *elf, const struct elf_section_header *header, + void *buffer, const size_t size); + +/** + * Read elf section with given name + * + * @param [in]elf elf file structure + * @param [in]name section name + * @param [out]section section data + * @return error code, 0 when success + */ +int elf_section_read_by_name(const struct elf_file *elf, const char *name, struct elf_section *section); + +/** + * Release section + * + * @param [in]section section structure + */ +void elf_section_free(struct elf_section *section); + +/** + * Read elf strings section with given index + * + * @param [in]elf elf file structure + * @param [in]index strings section index + * @param [out]strings strings section data + * @return error code, 0 when success + */ +int elf_strings_read_by_index(const struct elf_file *elf, int index, struct elf_strings *strings); + +/** + * Get string value. Allocate new copy using strdup. + * + * @param [in]strings strings section structure + * @param [in]index string index + * @param [out]str Pointer to the variable in which the pointer to the allocated string will be placed + * @return error code, 0 when success + */ +int elf_strings_get(const struct elf_strings *strings, int index, char **str); + +/** + * Release string section + * @param [in]strings strings section structure + */ +void elf_strings_free(struct elf_strings *strings); + +#endif /* __ELF_FILE_H__ */ diff --git a/tools/rimage/src/include/rimage/ext_manifest_gen.h b/tools/rimage/src/include/rimage/ext_manifest_gen.h new file mode 100644 index 000000000000..7f106834a0ca --- /dev/null +++ b/tools/rimage/src/include/rimage/ext_manifest_gen.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski <karolx.trzcinski@linux.intel.com> + */ + +/* + * Extended manifest is a place to store metadata about firmware, known during + * compilation time - for example firmware version or used compiler. + * Given information are read on host side before firmware startup. + * This part of output binary is not signed. + * + * To add new content to ext_man, in firmware code define struct which starts + * with ext_man_elem_head followed by usage dependent content and place whole + * struct in "fw_metadata" section. Moreover kernel code should be modified to + * properly read new packet. + * + * Extended manifest designed to be extensible. In header there is a field which + * describe header length, so after appending some data to header then it can be + * easily skipped by device with older version of this header. + * From other side, unknown ext_man elements should be just skipped by host, + * to be backward compatible. Field ext_man_elem_header.elem_size should be + * used in such a situation. + */ + +#ifndef __EXT_MAN_H__ +#define __EXT_MAN_H__ + +#include <rimage/rimage.h> + +#define EXT_MAN_DATA_SECTION ".fw_metadata" + +int ext_man_write(struct image *image); +int ext_man_write_cavs_25(struct image *image); + +#endif /* __EXT_MAN_H__ */ diff --git a/tools/rimage/src/include/rimage/file_utils.h b/tools/rimage/src/include/rimage/file_utils.h new file mode 100644 index 000000000000..34ecc89f5bad --- /dev/null +++ b/tools/rimage/src/include/rimage/file_utils.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + */ + +#ifndef __FILE_UTILS_H__ +#define __FILE_UTILS_H__ + +#include <stddef.h> + +/** + * Print file operation error message + * @param [in]msg error message + * @param [in]filename File name used to display the error message + * @param error code + */ +int file_error(const char *msg, const char *filename); + +/** + * Create new file name using output file name as template. + * @param [out] new_name char[] destination of new file name + * @param [in] name_size new file name buffer capacity + * @param [in] template_name File name used as a template for the new name + * @param [in] new_ext extension of the new file name + * @param error code, 0 when success + */ +int create_file_name(char *new_name, const size_t name_size, const char *template_name, + const char *new_ext); + +/** + * Get file size + * @param [in] f file handle + * @param [in] filename File name used to display the error message + * @param [out] size output for file size + * @param error code, 0 when success + */ +int get_file_size(FILE *f, const char *filename, size_t *size); + +#endif /* __FILE_UTILS_H__ */ diff --git a/tools/rimage/src/include/rimage/hash.h b/tools/rimage/src/include/rimage/hash.h new file mode 100644 index 000000000000..47a00101af4f --- /dev/null +++ b/tools/rimage/src/include/rimage/hash.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + */ + +#ifndef __HASH_H__ +#define __HASH_H__ + +#include <openssl/conf.h> +#include <openssl/evp.h> +#include <openssl/err.h> + +#include <stdint.h> + +/* Hash context state used to detect invalid use of hash functions */ +enum hash_state { HS_INIT, HS_UPDATE, HS_DONE, HS_ERROR }; + +struct hash_context { + enum hash_state state; + EVP_MD_CTX *context; + const EVP_MD *algo; + uint8_t digest[EVP_MAX_MD_SIZE]; + unsigned int digest_length; + int error; +}; + +/** + * Initialize hash context with given algorithm + * @param [out]context structure storing the hash context + * @param [in]algo hash algorithm + * @return error code, 0 when success + */ +int hash_init(struct hash_context *context, const EVP_MD *algo); + +/** + * Initialize sha256 hash context + * @param [out]context structure storing the hash context + * @return error code, 0 when success + */ +int hash_sha256_init(struct hash_context *context); + +/** + * Initialize sha384 hash context + * @param [out]context structure storing the hash context + * @return error code, 0 when success + */ +int hash_sha384_init(struct hash_context *context); + +/** + * Add data to hash + * @param [in]context structure storing the hash context + * @param [in]data data to be added + * @param [in]size length of data in bytes + * @return error code, 0 when success + */ +int hash_update(struct hash_context *context, const void *data, size_t size); + +/** + * Completes the hash calculation. No more data can be added! + * @param [in]context structure storing the hash context + * @return error code, 0 when success + */ +int hash_finalize(struct hash_context *context); + +/** + * Read out computed digest. Must finalize first. + * @param [in]context structure storing the hash context + * @param [out]output pointer to array where place hash value + * @param [in]output_len size of the output buffer + * @return copied digest length, < 0 if error + */ +int hash_get_digest(struct hash_context *context, void *output, size_t output_len); + +/** + * Print digest value + * @param [in]context structure storing the hash context + */ +void hash_print(struct hash_context *context); + +/** + * Calculates hash of a single memory buffer + * @param [in]data pointer to the data to be processed + * @param [in]size length of the data to be processed + * @param [in]algo hash algorithm + * @param [out]output pointer to array where place hash value + * @param [in]output_len size of the output buffer + * @return error code, 0 when success + */ +int hash_single(const void* data, size_t size, const EVP_MD *algo, void *output, size_t output_len); + +/** + * Calculates sha256 hash of a memory buffer + * @param [in]data pointer to the data to be processed + * @param [in]size length of the data to be processed + * @param [out]output pointer to array where place hash value + * @param [in]output_len size of the output buffer + * @return error code, 0 when success + */ +int hash_sha256(const void* data, size_t size, void *output, size_t output_len); + +/** + * Calculates sha384 hash of a memory buffer + * @param [in]data pointer to the data to be processed + * @param [in]size length of the data to be processed + * @param [out]output pointer to array where place hash value + * @param [in]output_len size of the output buffer + * @return error code, 0 when success + */ +int hash_sha384(const void* data, size_t size, void *output, size_t output_len); + +#endif /* __HASH_H__ */ diff --git a/tools/rimage/src/include/rimage/manifest.h b/tools/rimage/src/include/rimage/manifest.h new file mode 100644 index 000000000000..840cd7d797bf --- /dev/null +++ b/tools/rimage/src/include/rimage/manifest.h @@ -0,0 +1,239 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + */ + +#ifndef __MANIFEST_H__ +#define __MANIFEST_H__ + +#include <stdint.h> +#include <stdbool.h> +#include <rimage/sof/user/manifest.h> +#include <rimage/css.h> +#include <rimage/cse.h> +#include <rimage/plat_auth.h> +#include <rimage/module.h> + +/* + * Manifest module data + */ +struct manifest_module { + struct module file; + + /* Following fields are used in manifest creation process */ + bool is_bootloader; + + /* Size of the module in the output image. + * Includes text and data sections size + image headers*/ + size_t output_size; + + /* executable header module */ + int exec_header; + + /* module offset in image file */ + size_t foffset; + + size_t text_fixup_size; +}; + +#define MAN_PAGE_SIZE 4096 + +/* start offset for modules built using xcc */ +#define DEFAULT_XCC_MOD_OFFSET 0x8 + +/* start offset for base FW module */ +#define FILE_TEXT_OFFSET_V1_8 0x8000 +#define FILE_TEXT_OFFSET_V1_5 0x2000 +#define FILE_TEXT_OFFSET_V1_5_SUE 0xA000 + +/* + * CSE values for CNL + */ +#define MAN_CSE_PARTS 3 + + +#define MAN_CSE_HDR_OFFSET 0 +#define MAN_CSE_PADDING_SIZE 0x30 +#define MAN_EXT_PADDING 0x20 +#define MAN_DESC_OFFSET_V1_8 0x2000 +#define MAN_DESC_OFFSET_V1_5 0x284 +#define MAN_DESC_OFFSET_V1_5_SUE 0x2000 +#define MAN_DEFAULT_IMR_TYPE 3 + +#define MAN_CSS_HDR_OFFSET \ + (MAN_CSE_HDR_OFFSET + \ + sizeof(struct CsePartitionDirHeader) + \ + MAN_CSE_PARTS * sizeof(struct CsePartitionDirEntry)) + +#define MAN_CSS_HDR_OFFSET_2_5 \ + (MAN_CSE_HDR_OFFSET + \ + sizeof(struct CsePartitionDirHeader_v2_5) + \ + MAN_CSE_PARTS * sizeof(struct CsePartitionDirEntry)) + +#define MAN_FW_DESC_OFFSET_ACE_V1_5 \ + (MAN_META_EXT_OFFSET_ACE_V1_5 + \ + sizeof(struct sof_man_adsp_meta_file_ext_v2_5) + \ + MAN_EXT_PADDING) + +#define MAN_FW_DESC_OFFSET_V2_5 \ + (MAN_META_EXT_OFFSET_V2_5 + \ + sizeof(struct sof_man_adsp_meta_file_ext_v2_5) + \ + MAN_EXT_PADDING) + +#define MAN_DESC_PADDING_SIZE_ACE_V1_5 \ + (MAN_DESC_OFFSET_V1_8 - MAN_FW_DESC_OFFSET_ACE_V1_5) + +#define MAN_DESC_PADDING_SIZE_V2_5 \ + (MAN_DESC_OFFSET_V1_8 - MAN_FW_DESC_OFFSET_V2_5) + +#define MAN_SIG_PKG_OFFSET_V1_8 \ + (MAN_CSS_HDR_OFFSET + \ + sizeof(struct css_header_v1_8)) + +#define MAN_SIG_PKG_OFFSET_V2_5 \ + (MAN_CSS_HDR_OFFSET_2_5 + \ + sizeof(struct css_header_v2_5)) + +#define MAN_PART_INFO_OFFSET_V1_8 \ + (MAN_SIG_PKG_OFFSET_V1_8 + \ + sizeof(struct signed_pkg_info_ext)) + +#define MAN_PART_INFO_OFFSET_ACE_V1_5 \ + (MAN_SIG_PKG_OFFSET_V2_5 + \ + sizeof(struct signed_pkg_info_ext_ace_v1_5)) + +#define MAN_PART_INFO_OFFSET_V2_5 \ + (MAN_SIG_PKG_OFFSET_V2_5 + \ + sizeof(struct signed_pkg_info_ext_v2_5)) + +#define MAN_META_EXT_OFFSET_V1_8 \ + (MAN_SIG_PKG_OFFSET_V1_8 + \ + sizeof(struct signed_pkg_info_ext) + \ + sizeof(struct partition_info_ext) + \ + MAN_CSE_PADDING_SIZE) + +#define MAN_META_EXT_OFFSET_ACE_V1_5 \ + (MAN_SIG_PKG_OFFSET_V2_5 + \ + sizeof(struct signed_pkg_info_ext_ace_v1_5) + \ + sizeof(struct info_ext_0x16) + \ + 0) + +#define MAN_META_EXT_OFFSET_V2_5 \ + (MAN_SIG_PKG_OFFSET_V2_5 + \ + sizeof(struct signed_pkg_info_ext_v2_5) + \ + sizeof(struct info_ext_0x16) + \ + 0) + +#define MAN_FW_DESC_OFFSET_V1_8 \ + (MAN_META_EXT_OFFSET_V1_8 + \ + sizeof(struct sof_man_adsp_meta_file_ext_v1_8) + \ + MAN_EXT_PADDING) + +#define MAN_DESC_PADDING_SIZE_V1_8 \ + (MAN_DESC_OFFSET_V1_8 - MAN_FW_DESC_OFFSET_V1_8) + +#define MAN_SIG_PKG_OFFSET_V1_5 \ + (MAN_CSS_HDR_OFFSET + \ + sizeof(struct css_header_v1_5)) + +#define MAN_META_EXT_OFFSET_V1_5 \ + (MAN_SIG_PKG_OFFSET_V1_5 + \ + sizeof(struct signed_pkg_info_ext) + \ + sizeof(struct partition_info_ext) + \ + MAN_CSE_PADDING_SIZE) + +#define MAN_FW_DESC_OFFSET_V1_5 \ + (MAN_META_EXT_OFFSET_V1_5 + \ + sizeof(struct sof_man_adsp_meta_file_ext_v1_8) + \ + MAN_EXT_PADDING) + +/* + * Firmware manifest header ACE V1_5 used on MTL onwards + */ +struct fw_image_manifest_ace_v1_5 { + /* MEU tool needs these sections to be 0s */ + struct CsePartitionDirHeader_v2_5 cse_partition_dir_header; + struct CsePartitionDirEntry cse_partition_dir_entry[MAN_CSE_PARTS]; + struct css_header_v2_5 css; + struct signed_pkg_info_ext_ace_v1_5 signed_pkg; + struct info_ext_0x16 info_0x16; + + struct sof_man_adsp_meta_file_ext_v2_5 adsp_file_ext; + + /* reserved / pading at end of ext data - all 0s*/ + uint8_t reserved[MAN_EXT_PADDING]; + + /* start of the unsigned binary for MEU input must start at MAN_DESC_OFFSET */ + uint8_t padding[MAN_DESC_PADDING_SIZE_ACE_V1_5]; + + struct sof_man_fw_desc desc; /* at offset MAN_DESC_OFFSET */ +} __attribute__((packed)); + +/* + * Firmware manifest header V2.5 used on TGL onwards + */ +struct fw_image_manifest_v2_5 { + /* MEU tool needs these sections to be 0s */ + struct CsePartitionDirHeader_v2_5 cse_partition_dir_header; + struct CsePartitionDirEntry cse_partition_dir_entry[MAN_CSE_PARTS]; + struct css_header_v2_5 css; + struct signed_pkg_info_ext_v2_5 signed_pkg; + struct info_ext_0x16 info_0x16; + + struct sof_man_adsp_meta_file_ext_v2_5 adsp_file_ext; + + /* reserved / pading at end of ext data - all 0s*/ + uint8_t reserved[MAN_EXT_PADDING]; + + /* start of the unsigned binary for MEU input must start at MAN_DESC_OFFSET */ + uint8_t padding[MAN_DESC_PADDING_SIZE_V2_5]; + + struct sof_man_fw_desc desc; /* at offset MAN_DESC_OFFSET */ +} __attribute__((packed)); + +/* + * Firmware manifest header V1.8 used on APL onwards + */ +struct fw_image_manifest_v1_8 { + /* MEU tool needs these sections to be 0s */ + struct CsePartitionDirHeader cse_partition_dir_header; + struct CsePartitionDirEntry cse_partition_dir_entry[MAN_CSE_PARTS]; + struct css_header_v1_8 css; + struct signed_pkg_info_ext signed_pkg; + struct partition_info_ext partition_info; + uint8_t cse_padding[MAN_CSE_PADDING_SIZE]; + struct sof_man_adsp_meta_file_ext_v1_8 adsp_file_ext; + + /* reserved / pading at end of ext data - all 0s*/ + uint8_t reserved[MAN_EXT_PADDING]; + + /* start of the unsigned binary for MEU input must start at MAN_DESC_OFFSET */ + uint8_t padding[MAN_DESC_PADDING_SIZE_V1_8]; + + struct sof_man_fw_desc desc; /* at offset MAN_DESC_OFFSET */ +} __attribute__((packed)); + +/* + * Firmware manifest header V1.5 used on SKL and KBL + */ +struct fw_image_manifest_v1_5 { + struct css_header_v1_5 css_header; + struct sof_man_fw_desc desc; +} __attribute__((packed)); + +struct fw_image_manifest_v1_5_sue { + struct sof_man_fw_desc desc; +} __attribute__((packed)); + +struct image; +int simple_write_firmware(struct image *image); +int man_write_fw_v1_5(struct image *image); +int man_write_fw_v1_5_sue(struct image *image); +int man_write_fw_v1_8(struct image *image); +int man_write_fw_v2_5(struct image *image); +int man_write_fw_ace_v1_5(struct image *image); +int man_write_fw_meu_v1_5(struct image *image); +int man_write_fw_meu_v1_8(struct image *image); +int man_write_fw_meu_v2_5(struct image *image); + +#endif diff --git a/tools/rimage/src/include/rimage/misc_utils.h b/tools/rimage/src/include/rimage/misc_utils.h new file mode 100644 index 000000000000..e3432d57a391 --- /dev/null +++ b/tools/rimage/src/include/rimage/misc_utils.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + */ + +#ifndef __MISC_UTILS_H__ +#define __MISC_UTILS_H__ + +#include <stdint.h> + +#define DIV_ROUND_UP(val, div) (((val) + (div) - 1) / (div)) + +/** + * Reverses the order of bytes in the array + * @param ptr pointer to a array + * @param size of the array + */ +void bytes_swap(uint8_t *ptr, uint32_t size); + +struct name_val { + const char *name; + unsigned long value; +}; + +#define NAME_VAL_ENTRY(x) { .name = #x, .value = x } +#define NAME_VAL_END { .name = 0, .value = 0 } + +void print_enum(unsigned long value, const struct name_val *values); +void print_flags(unsigned long value, const struct name_val *flags); + +#endif /* __MISC_UTILS_H__ */ diff --git a/tools/rimage/src/include/rimage/module.h b/tools/rimage/src/include/rimage/module.h new file mode 100644 index 000000000000..3c265b20823b --- /dev/null +++ b/tools/rimage/src/include/rimage/module.h @@ -0,0 +1,190 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Adrian Warecki <adrian.warecki@intel.com> + */ + +#ifndef __MODULE_H__ +#define __MODULE_H__ + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> + +#include <rimage/elf_file.h> + +enum module_section_type { + MST_UNKNOWN, MST_DATA, MST_TEXT, MST_BSS, MST_NOTE +}; + +struct module_section { + const struct elf_section_header *header; + enum module_section_type type; + + /* The contents of the section lie in the rom memory space */ + bool rom; + + /* ADSP devices have their RAM regions mapped twice. The first mapping is set in the CPU + * to bypass the L1 cache, and so access through pointers in that region is coherent between + * CPUs (but slow). The second region accesses the same memory through the L1 cache and + * requires careful flushing when used with shared data. + * + * This distinction is exposed in the linker script, where some symbols (e.g. stack regions) + * are linked into cached memory, but others (general kernel memory) are not. + * + * Addresses of sections belonging to a rom memory are not converted. */ + + /* section virtual address, converted to cached address space */ + uint32_t address; + + /* section physical load address, converted to cached address space */ + uint32_t load_address; + + size_t size; + + /* next section of this type */ + struct module_section *next_section; +}; + +struct module_sections_info { + /* start address */ + uint32_t start; + + /* end address */ + uint32_t end; + + /* size without any gaps */ + size_t size; + + /* size include gap to nearest page */ + size_t file_size; + + /* sections count */ + unsigned int count; + + /* First section */ + struct module_section *first_section; +}; + +/* + * ELF module data + */ +struct module { + struct elf_file elf; + + /* Array of valid sections */ + struct module_section *sections; + + /* Number of valid sections */ + unsigned int num_sections; + + struct module_sections_info text; + struct module_sections_info data; + struct module_sections_info bss; +}; + +struct image; +struct memory_alias; +struct memory_config; + +/** + * Convert uncached memory address to cached + * + * @param alias alias memory configration + * @param address address to be converted + * @return cached address + */ +unsigned long uncache_to_cache(const struct memory_alias *alias, unsigned long address); + + +/** + * Load module file + * + * @param module module structure + * @param filename module file name + * @param verbose verbose logging selection + * @return error code + */ +int module_open(struct module *module, const char *filename, const bool verbose); + +/** + * Unloads module + * + * @param module module structure + */ +void module_close(struct module *module); + +/** + * Parse module sections + * + * @param module module structure + * @param mem_cfg memory configration structure + * @param verbose verbose logging selection + * @return error code + */ +void module_parse_sections(struct module *module, const struct memory_config *mem_cfg, + bool verbose); + +/** + * Read module section to memory buffer + * + * @param [in]module module structure + * @param [in]section module section structure + * @param [out]buffer destination buffer + * @param [in]size destination buffer size + * @return error code + */ +int module_read_section(const struct module *module, const struct module_section *section, + void *buffer, const size_t size); + +/** + * Read module section and write it to a file + * + * @param module module structure + * @param section module section structure + * @param padding count of padding bytes to write after section content + * @param out_file destination file handle + * @param filename output file name used to print error message + * @return error code + */ +int module_write_section(const struct module *module, const struct module_section *section, + const int padding, FILE *out_file, const char *filename); + +/** + * Read whole module elf file to a memory buffer + * + * @param [in]module module structure + * @param [out]buffer destination buffer + * @param [in]size destination buffer size + * @return error code + */ +int module_read_whole_elf(const struct module *module, void *buffer, size_t size); + +/** + * Read whore module elf file and write it to a file + * + * @param module module structure + * @param out_file destination file handle + * @param filename output file name used to print error message + * @return error code + */ +int module_write_whole_elf(const struct module *module, FILE *out_file, const char *filename); + +/** + * Displays information about the occupancy of each memory zone + * + * @param module module structure + */ +void module_print_zones(const struct module *module); + +/** + * Checks all modules to make sure their sections do not overlap with each other + * + * @param module module structure + * @param image program global structure + * @return error code + */ +int modules_validate(const struct image *image); + +#endif /* __MODULE_H__ */ diff --git a/tools/rimage/src/include/rimage/plat_auth.h b/tools/rimage/src/include/rimage/plat_auth.h new file mode 100644 index 000000000000..64cdcd98db5f --- /dev/null +++ b/tools/rimage/src/include/rimage/plat_auth.h @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + */ + +#ifndef __PLAT_AUTH_H__ +#define __PLAT_AUTH_H__ + +#include <stdint.h> + +struct image; + +#define PLAT_AUTH_SHA256_LEN 32 +#define PLAT_AUTH_SHA384_LEN 48 +#define PLAT_AUTH_NAME_LEN 12 +#define PLAT_AUTH_PADDING 48 /* pad at end of struct */ + +#define SIGN_PKG_EXT_TYPE 15 +#define SIGN_PKG_NUM_MODULE 1 + +#define SIGN_PKG_EXT_TYPE_ACE_V1_5 0x23 + +struct signed_pkg_info_module { + uint8_t name[PLAT_AUTH_NAME_LEN]; /* must be padded with 0 */ + uint8_t type; + uint8_t hash_algo; + uint16_t hash_size; + uint32_t meta_size; + uint8_t hash[PLAT_AUTH_SHA256_LEN]; +} __attribute__((packed)); + +struct signed_pkg_info_module_v2_5 { + uint8_t name[PLAT_AUTH_NAME_LEN]; /* must be padded with 0 */ + uint8_t type; + uint8_t hash_algo; + uint16_t hash_size; + uint32_t meta_size; + uint8_t hash[PLAT_AUTH_SHA384_LEN]; +} __attribute__((packed)); + +struct signed_pkg_info_ext { + uint32_t ext_type; + uint32_t ext_len; + + uint8_t name[4]; + uint32_t vcn; + uint8_t bitmap[16]; + uint32_t svn; + uint8_t fw_type; + uint8_t fw_sub_type; + uint8_t reserved[14]; /* must be 0 */ + + /* variable length of modules */ + struct signed_pkg_info_module module[SIGN_PKG_NUM_MODULE]; +} __attribute__((packed)); + +struct signed_pkg_info_ext_v2_5 { + uint32_t ext_type; + uint32_t ext_len; + + uint8_t name[4]; + uint32_t vcn; /* 0 */ + uint8_t bitmap[16]; + uint32_t svn; + uint8_t fw_type; + uint8_t fw_sub_type; + uint8_t reserved[14]; /* must be 0 */ + + /* variable length of modules */ + struct signed_pkg_info_module_v2_5 module[SIGN_PKG_NUM_MODULE]; +} __attribute__((packed)); + +struct signed_pkg_info_module_ace_v1_5 { + uint8_t name[PLAT_AUTH_NAME_LEN]; /* must be padded with 0 */ + uint8_t type; + uint8_t hash_algo; + uint8_t reserved[2]; + uint32_t meta_size; + uint8_t hash[PLAT_AUTH_SHA384_LEN]; +} __attribute__((packed)); + +struct signed_pkg_info_ext_ace_v1_5 { + uint32_t ext_type; + uint32_t ext_len; + + uint8_t name[4]; + uint32_t vcn; /* 0 */ + uint32_t svn; + uint8_t partition_usage; + uint8_t reserved0; + uint8_t fw_type; + uint8_t fw_sub_type; + uint8_t number_of_modules; + uint8_t boot_strap_svn; + uint8_t reserved[14]; /* must be 0 */ + + /* variable length of modules */ + struct signed_pkg_info_module_ace_v1_5 module[SIGN_PKG_NUM_MODULE]; +} __attribute__((packed)); + +#define PART_INFO_EXT_TYPE 3 +#define PART_INFO_NUM_MODULE 1 + +struct partition_info_module { + uint8_t name[PLAT_AUTH_NAME_LEN]; /* must be padded with 0 */ + uint8_t type; + uint8_t reserved[3]; + uint32_t meta_size; + uint8_t hash[PLAT_AUTH_SHA256_LEN]; +} __attribute__((packed)); + +struct partition_info_ext { + uint32_t ext_type; + uint32_t ext_len; + + uint8_t name[4]; /* "ADSP" */ + uint32_t length; + uint8_t hash[PLAT_AUTH_SHA256_LEN]; + + uint32_t vcn; + uint32_t part_version; + uint32_t fmt_version; + uint32_t instance_id; + uint32_t part_flags; + uint8_t reserved[20]; /* must be 0 */ + + /* variable length of modules */ + struct partition_info_module module[PART_INFO_NUM_MODULE]; +} __attribute__((packed)); + +/* offset 0x458 id */ +struct info_ext_0x16 { + uint32_t ext_type; /* 0x16 */ + uint32_t ext_len; /* 0x68 */ + uint8_t name[4]; /* ADSP */ + uint32_t size; /* file size */ + uint32_t data[5]; /* 0 = 0x10000000, 0, 1, 1, 0x3003 */ + uint8_t hash[PLAT_AUTH_SHA384_LEN]; + uint32_t data1[5]; +} __attribute__((packed)); + + +#define PLAT_AUTH_SIZE \ + (sizeof(struct partition_info_ext) + \ + sizeof(struct signed_pkg_info_ext)) + +void ri_adsp_meta_data_create_v1_8(struct image *image, int meta_start_offset, + int meta_end_offset); +void ri_adsp_meta_data_create_v2_5(struct image *image, int meta_start_offset, + int meta_end_offset); +void ri_plat_ext_data_create(struct image *image); +void ri_plat_ext_data_create_v2_5(struct image *image); +void ri_plat_ext_data_create_ace_v1_5(struct image *image); + +#endif diff --git a/tools/rimage/src/include/rimage/rimage.h b/tools/rimage/src/include/rimage/rimage.h new file mode 100644 index 000000000000..61bc77bfca42 --- /dev/null +++ b/tools/rimage/src/include/rimage/rimage.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2015-2018 Intel Corporation. All rights reserved. + */ + +#ifndef __RIMAGE_H__ +#define __RIMAGE_H__ + +#include <stdint.h> +#include <stdio.h> + +#include <rimage/manifest.h> +#include <rimage/cavs/cavs_ext_manifest.h> +#include <rimage/sof/kernel/fw.h> + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#define MAX_MODULES 32 + +struct adsp; + +/* + * Firmware image context. + */ +struct image { + + const char *out_file; + const char *in_file; + FILE *out_fd; + void *pos; + + struct adsp *adsp; + int abi; + int verbose; + int reloc; /* ELF data is relocatable */ + int num_modules; + struct manifest_module module[MAX_MODULES]; + uint32_t image_end;/* module end, equal to output image size */ + int meu_offset; + const char *verify_file; + + /* private key file name*/ + const char *key_name; + + /* file IO */ + void *fw_image; + void *rom_image; + FILE *out_rom_fd; + FILE *out_man_fd; + FILE *out_ext_man_fd; + FILE *out_unsigned_fd; + char out_rom_file[256]; + char out_man_file[256]; + char out_ext_man_file[256]; + char out_unsigned_file[256]; + + /* fw version and build id */ + char* fw_ver_string; + char* fw_ver_build_string; + uint16_t fw_ver_major; + uint16_t fw_ver_minor; + uint16_t fw_ver_micro; + uint16_t fw_ver_build; + + uint32_t imr_type; + + /* Output image is a loadable module */ + bool loadable_module; +}; + +struct memory_zone { + uint32_t base; + uint32_t size; + uint32_t host_offset; +}; + +struct memory_alias { + uint32_t mask; + uint32_t cached; + uint32_t uncached; +}; + +struct memory_config { + struct memory_zone zones[SOF_FW_BLK_TYPE_NUM]; + struct memory_alias alias; +}; + +struct fw_image_ext_mod_config { + struct fw_ext_mod_config_header header; + struct mod_scheduling_caps sched_caps; + struct fw_pin_description *pin_desc; +}; + +struct fw_image_ext_module { + uint32_t mod_conf_count; + struct fw_image_ext_mod_config ext_mod_config_array[FW_MAX_EXT_MODULE_NUM]; +}; + +/* + * module manifest information defined in config file + */ +struct fw_image_manifest_module { + struct fw_image_ext_module mod_ext; + uint32_t mod_cfg_count; + struct sof_man_mod_config *mod_cfg; + uint32_t mod_man_count; + struct sof_man_module *mod_man; +}; + +/* + * Audio DSP descriptor and operations. + */ +struct adsp { + const char *name; + struct memory_config mem; + + uint32_t image_size; + + int (*write_firmware_ext_man)(struct image *image); + int (*write_firmware)(struct image *image); + int (*write_firmware_meu)(struct image *image); + int (*verify_firmware)(struct image *image); + struct fw_image_manifest_ace_v1_5 *man_ace_v1_5; + struct fw_image_manifest_v2_5 *man_v2_5; + struct fw_image_manifest_v1_8 *man_v1_8; + struct fw_image_manifest_v1_5 *man_v1_5; + struct fw_image_manifest_v1_5_sue *man_v1_5_sue; + struct fw_image_manifest_module *modules; + int exec_boot_ldr; +}; + +int ri_manifest_sign_v1_5(struct image *image); +int ri_manifest_sign_v1_8(struct image *image); +int ri_manifest_sign_v2_5(struct image *image); +int ri_manifest_sign_ace_v1_5(struct image *image); + +int pkcs_v1_5_sign_man_v1_5(struct image *image, + struct fw_image_manifest_v1_5 *man, + void *ptr1, unsigned int size1); +int pkcs_v1_5_sign_man_v1_8(struct image *image, + struct fw_image_manifest_v1_8 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2); +int pkcs_v1_5_sign_man_v2_5(struct image *image, + struct fw_image_manifest_v2_5 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2); +int pkcs_v1_5_sign_man_ace_v1_5(struct image *image, + struct fw_image_manifest_ace_v1_5 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2); + +int verify_image(struct image *image); +int ri_manifest_verify_v1_5(struct image *image); +int ri_manifest_verify_v1_8(struct image *image); +int ri_manifest_verify_v2_5(struct image *image); +int pkcs_v1_5_verify_man_v1_5(struct image *image, + struct fw_image_manifest_v1_5 *man, + void *ptr1, unsigned int size1); +int pkcs_v1_5_verify_man_v1_8(struct image *image, + struct fw_image_manifest_v1_8 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2); +int pkcs_v1_5_verify_man_v2_5(struct image *image, + struct fw_image_manifest_v2_5 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2); +int pkcs_v1_5_verify_man_ace_v1_5(struct image *image, + struct fw_image_manifest_ace_v1_5 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2); + +int resign_image(struct image *image); +int get_key_size(struct image *image); + +#endif diff --git a/tools/rimage/src/include/rimage/sof/kernel/ext_manifest.h b/tools/rimage/src/include/rimage/sof/kernel/ext_manifest.h new file mode 100644 index 000000000000..7d9b77735a11 --- /dev/null +++ b/tools/rimage/src/include/rimage/sof/kernel/ext_manifest.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski <karolx.trzcinski@linux.intel.com> + */ + +/* + * Extended manifest is a place to store metadata about firmware, known during + * compilation time - for example firmware version or used compiler. + * Given information are read on host side before firmware startup. + * This part of output binary is not signed. + * + * To add new content to ext_man, in firmware code define struct which starts + * with ext_man_elem_head followed by usage dependent content and place whole + * struct in "fw_metadata" section. Moreover kernel code should be modified to + * properly read new packet. + * + * Extended manifest is designed to be extensible. In header there is a field + * which describe header length, so after appending some data to header then it + * can be easily skipped by device with older version of this header. + * Unknown ext_man elements should be just skipped by host, + * to be backward compatible. Field `ext_man_elem_header.elem_size` should be + * used in such a situation. + */ + +#ifndef __RIMAGE_KERNEL_EXT_MANIFEST_H__ +#define __RIMAGE_KERNEL_EXT_MANIFEST_H__ + +#include <stdint.h> + +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + +/* In ASCII `XMan` */ +#define EXT_MAN_MAGIC_NUMBER 0x6e614d58 + +/* Build u32 number in format MMmmmppp */ +#define EXT_MAN_BUILD_VERSION(MAJOR, MINOR, PATH) ( \ + ((uint32_t)(MAJOR) << 24) | \ + ((uint32_t)(MINOR) << 12) | \ + (uint32_t)(PATH)) + +/* check extended manifest version consistency */ +#define EXT_MAN_VERSION_INCOMPATIBLE(host_ver, cli_ver) ( \ + ((host_ver) & GENMASK(31, 24)) != \ + ((cli_ver) & GENMASK(31, 24))) + +/* used extended manifest header version */ +#define EXT_MAN_VERSION EXT_MAN_BUILD_VERSION(1, 0, 0) + +/* struct size alignment for ext_man elements */ +#define EXT_MAN_ALIGN 16 + +/* extended manifest header, deleting any field breaks backward compatibility */ +struct ext_man_header { + uint32_t magic; /**< identification number, */ + /**< EXT_MAN_MAGIC_NUMBER */ + uint32_t full_size; /**< [bytes] full size of ext_man, */ + /**< (header + content + padding) */ + uint32_t header_size; /**< [bytes] makes header extensionable, */ + /**< after append new field to ext_man header */ + /**< then backward compatible won't be lost */ + uint32_t header_version; /**< value of EXT_MAN_VERSION */ + /**< not related with following content */ + + /* just after this header should be list of ext_man_elem_* elements */ +} __packed; + +/* Now define extended manifest elements */ + +/* extended manifest element header */ +struct ext_man_elem_header { + uint32_t type; /**< EXT_MAN_ELEM_* */ + uint32_t elem_size; /**< in bytes, including header size */ + + /* just after this header should be type dependent content */ +} __packed; + +#endif /* __RIMAGE_KERNEL_EXT_MANIFEST_H__ */ diff --git a/tools/rimage/src/include/rimage/sof/kernel/fw.h b/tools/rimage/src/include/rimage/sof/kernel/fw.h new file mode 100644 index 000000000000..14c8ca0c1585 --- /dev/null +++ b/tools/rimage/src/include/rimage/sof/kernel/fw.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> + * Keyon Jie <yang.jie@linux.intel.com> + */ + +/* + * Firmware file format . + */ + +#ifndef __RIMAGE_KERNEL_FW_H__ +#define __RIMAGE_KERNEL_FW_H__ + +#include <stdint.h> + +#define SND_SOF_FW_SIG_SIZE 4 +#define SND_SOF_FW_ABI 1 +#define SND_SOF_FW_SIG "Reef" + +/* + * Firmware module is made up of 1 . N blocks of different types. The + * Block header is used to determine where and how block is to be copied in the + * DSP/host memory space. + */ +enum snd_sof_fw_blk_type { + SOF_FW_BLK_TYPE_INVALID = -1, + SOF_FW_BLK_TYPE_START = 0, + SOF_FW_BLK_TYPE_RSRVD0 = SOF_FW_BLK_TYPE_START, + SOF_FW_BLK_TYPE_IRAM = 1, /* local instruction RAM */ + SOF_FW_BLK_TYPE_DRAM = 2, /* local data RAM */ + SOF_FW_BLK_TYPE_SRAM = 3, /* system RAM */ + SOF_FW_BLK_TYPE_ROM = 4, + SOF_FW_BLK_TYPE_IMR = 5, + SOF_FW_BLK_TYPE_HPSRAM = 6, + SOF_FW_BLK_TYPE_LPSRAM = 7, + SOF_FW_BLK_TYPE_RSRVD8 = 8, + SOF_FW_BLK_TYPE_RSRVD9 = 9, + SOF_FW_BLK_TYPE_RSRVD10 = 10, + SOF_FW_BLK_TYPE_RSRVD11 = 11, + SOF_FW_BLK_TYPE_RSRVD12 = 12, + SOF_FW_BLK_TYPE_RSRVD13 = 13, + SOF_FW_BLK_TYPE_RSRVD14 = 14, + /* use SOF_FW_BLK_TYPE_RSVRDX for new block types */ + SOF_FW_BLK_TYPE_NUM +}; + +struct snd_sof_blk_hdr { + enum snd_sof_fw_blk_type type; + uint32_t size; /* bytes minus this header */ + uint32_t offset; /* offset from base */ +} __attribute__((packed)); + +/* + * Firmware file is made up of 1 .. N different modules types. The module + * type is used to determine how to load and parse the module. + */ +enum snd_sof_fw_mod_type { + SOF_FW_BASE = 0, /* base firmware image */ + SOF_FW_MODULE = 1, /* firmware module */ +}; + +struct snd_sof_mod_hdr { + enum snd_sof_fw_mod_type type; + uint32_t size; /* bytes minus this header */ + uint32_t num_blocks; /* number of blocks */ +} __attribute__((packed)); + +/* + * Firmware file header. + */ +struct snd_sof_fw_header { + unsigned char sig[SND_SOF_FW_SIG_SIZE]; /* "Reef" */ + uint32_t file_size; /* size of file minus this header */ + uint32_t num_modules; /* number of modules */ + uint32_t abi; /* version of header format */ +} __attribute__((packed)); + +#endif /* __RIMAGE_KERNEL_FW_H__ */ diff --git a/tools/rimage/src/include/rimage/sof/user/manifest.h b/tools/rimage/src/include/rimage/sof/user/manifest.h new file mode 100644 index 000000000000..d270ce98b309 --- /dev/null +++ b/tools/rimage/src/include/rimage/sof/user/manifest.h @@ -0,0 +1,238 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> + */ + +/** + * \file include/user/manifest.h + * \brief FW Image Manifest definitions. + * \author Liam Girdwood <liam.r.girdwood@linux.intel.com> + */ + +#ifndef __RIMAGE_USER_MANIFEST_H__ +#define __RIMAGE_USER_MANIFEST_H__ + +#include <stdint.h> + +/* start offset for base FW module */ +#define SOF_MAN_ELF_TEXT_OFFSET 0x2000 + +/* FW Extended Manifest Header id = $AE1 */ +#define SOF_MAN_EXT_HEADER_MAGIC 0x31454124 + +/* module type load type */ +#define SOF_MAN_MOD_TYPE_BUILTIN 0 +#define SOF_MAN_MOD_TYPE_MODULE 1 + +/* module init config */ +#define SOF_MAN_MOD_INIT_CONFIG_BASE_CFG 0 /* Base config only */ +#define SOF_MAN_MOD_INIT_CONFIG_BASE_CFG_WITH_EXT 1 /* Base config with extension */ + +#define MAN_MAX_SIZE_V1_8 (38 * 1024) + + +struct sof_man_module_type { + uint32_t load_type:4; /* SOF_MAN_MOD_TYPE_ */ + uint32_t auto_start:1; + uint32_t domain_ll:1; + uint32_t domain_dp:1; + uint32_t lib_code:1; + uint32_t init_config:4; /* SOF_MAN_MOD_INIT_CONFIG_ */ + uint32_t rsvd_:20; +}; + +/* segment flags.type */ +#define SOF_MAN_SEGMENT_TEXT 0 +#define SOF_MAN_SEGMENT_RODATA 1 +#define SOF_MAN_SEGMENT_DATA 1 +#define SOF_MAN_SEGMENT_BSS 2 +#define SOF_MAN_SEGMENT_EMPTY 15 + +union sof_man_segment_flags { + uint32_t ul; + struct { + uint32_t contents:1; + uint32_t alloc:1; + uint32_t load:1; + uint32_t readonly:1; + uint32_t code:1; + uint32_t data:1; + uint32_t _rsvd0:2; + uint32_t type:4; /* MAN_SEGMENT_ */ + uint32_t _rsvd1:4; + uint32_t length:16; /* of segment in pages */ + } r; +} __attribute__((packed)); + +/* + * Module segment descriptor. Used by ROM - Immutable. + */ +struct sof_man_segment_desc { + union sof_man_segment_flags flags; + uint32_t v_base_addr; + uint32_t file_offset; +} __attribute__((packed)); + +/* + * The firmware binary can be split into several modules. + */ + +#define SOF_MAN_MOD_ID_LEN 4 +#define SOF_MAN_MOD_NAME_LEN 8 +#define SOF_MAN_MOD_SHA256_LEN 32 +#define SOF_MAN_MOD_SHA384_LEN 48 +#define SOF_MAN_MOD_ID {'$', 'A', 'M', 'E'} + +/* + * Each module has an entry in the FW header. Used by ROM - Immutable. + */ +struct sof_man_module { + uint8_t struct_id[SOF_MAN_MOD_ID_LEN]; /* SOF_MAN_MOD_ID */ + uint8_t name[SOF_MAN_MOD_NAME_LEN]; + uint8_t uuid[16]; + struct sof_man_module_type type; + uint8_t hash[SOF_MAN_MOD_SHA256_LEN]; + uint32_t entry_point; + uint16_t cfg_offset; + uint16_t cfg_count; + uint32_t affinity_mask; + uint16_t instance_max_count; /* max number of instances */ + uint16_t instance_bss_size; /* instance (pages) */ + struct sof_man_segment_desc segment[3]; +} __attribute__((packed)); + +/* + * Each module has a configuration in the FW header. Used by ROM - Immutable. + */ +struct sof_man_mod_config { + uint32_t par[4]; /* module parameters */ + uint32_t is_pages; /* actual size of instance .bss (pages) */ + uint32_t cps; /* cycles per second */ + uint32_t ibs; /* input buffer size (bytes) */ + uint32_t obs; /* output buffer size (bytes) */ + uint32_t module_flags; /* flags, reserved for future use */ + uint32_t cpc; /* cycles per single run */ + uint32_t obls; /* output block size, reserved for future use */ +} __attribute__((packed)); + +/* + * FW Manifest Header + */ + +#define SOF_MAN_FW_HDR_FW_NAME_LEN 8 +#define SOF_MAN_FW_HDR_ID {'$', 'A', 'M', '1'} +#define SOF_MAN_FW_HDR_NAME "ADSPFW" +#define SOF_MAN_FW_HDR_FLAGS 0x0 +#define SOF_MAN_FW_HDR_FEATURES 0xffff + +/* + * The firmware has a standard header that is checked by the ROM on firmware + * loading. preload_page_count is used by DMA code loader and is entire + * image size on CNL. i.e. CNL: total size of the binary’s .text and .rodata + * Used by ROM - Immutable. + */ +struct sof_man_fw_header { + uint8_t header_id[4]; + uint32_t header_len; + uint8_t name[SOF_MAN_FW_HDR_FW_NAME_LEN]; + /* number of pages of preloaded image loaded by driver */ + uint32_t preload_page_count; + uint32_t fw_image_flags; + uint32_t feature_mask; + uint16_t major_version; + uint16_t minor_version; + uint16_t hotfix_version; + uint16_t build_version; + uint32_t num_module_entries; + uint32_t fw_compat; + uint32_t hw_buf_length; + /* target address for binary loading as offset in IMR - must be == base offset */ + uint32_t load_offset; +} __attribute__((packed)); + +/* + * Firmware manifest descriptor. This can contain N modules and N module + * configs. Used by ROM - Immutable. + */ +struct sof_man_fw_desc { + struct sof_man_fw_header header; + + /* Warning - hack for module arrays. For some unknown reason the we + * have a variable size array of struct man_module followed by a + * variable size array of struct mod_config. These should have been + * merged into a variable array of a parent structure. We have to hack + * around this in many places.... + * + * struct sof_man_module man_module[]; + * struct sof_man_mod_config mod_config[]; + */ + +} __attribute__((packed)); + +#define SOF_MAN_COMP_SHA256_LEN 32 +#define SOF_MAN_COMP_SHA384_LEN 48 + +/* + * Component Descriptor for manifest v1.8. Used by ROM - Immutable. + */ +struct sof_man_component_desc_v1_8 { + uint32_t reserved[2]; /* all 0 */ + uint32_t version; + uint8_t hash[SOF_MAN_COMP_SHA256_LEN]; + uint32_t base_offset; + uint32_t limit_offset; + uint32_t attributes[4]; +} __attribute__((packed)); + +/* + * Audio DSP extended metadata for manifest v1.8. Used by ROM - Immutable. + */ +struct sof_man_adsp_meta_file_ext_v1_8 { + uint32_t ext_type; /* always 17 for ADSP extension */ + uint32_t ext_len; + uint32_t imr_type; + uint8_t reserved[16]; /* all 0 */ + struct sof_man_component_desc_v1_8 comp_desc[1]; +} __attribute__((packed)); + +/* + * Component Descriptor for manifest v2.5. Used by ROM - Immutable. + */ +struct sof_man_component_desc_v2_5 { + uint32_t reserved[2]; /* all 0 */ + uint32_t version; + uint8_t hash[SOF_MAN_COMP_SHA384_LEN]; + uint32_t base_offset; + uint32_t limit_offset; + uint32_t attributes[4]; +} __attribute__((packed)); + +/* + * Audio DSP extended metadata for manifest v2.5. Used by ROM - Immutable. + */ +struct sof_man_adsp_meta_file_ext_v2_5 { + uint32_t ext_type; /* always 17 for ADSP extension */ + uint32_t ext_len; + uint32_t imr_type; + uint8_t reserved[16]; /* all 0 */ + struct sof_man_component_desc_v2_5 comp_desc[1]; +} __attribute__((packed)); + +/* + * Module Manifest for rimage module metadata. Not used by ROM. + */ +struct sof_man_module_manifest { + struct sof_man_module module; + uint32_t text_size; +}; + +/* + * Module offset in manifest. + */ +#define SOF_MAN_MODULE_OFFSET(index) \ + (sizeof(struct sof_man_fw_header) + \ + (index) * sizeof(struct sof_man_module)) + +#endif /* __RIMAGE_USER_MANIFEST_H__ */ diff --git a/tools/rimage/src/include/rimage/toml_utils.h b/tools/rimage/src/include/rimage/toml_utils.h new file mode 100644 index 000000000000..cd17bb4af28d --- /dev/null +++ b/tools/rimage/src/include/rimage/toml_utils.h @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski <karolx.trzcinski@linux.intel.com> + * Marc Herbert <marc.herbert@intel.com> + */ + +#ifndef __TOML_UTILS_H__ +#define __TOML_UTILS_H__ + +#include "toml.h" + +#include <stdint.h> +#include <stdio.h> +#include <stdarg.h> + +/** parser counter, used to assert nothing left unparsed in toml data */ +struct parse_ctx { + int key_cnt; /**< number of parsed key */ + int table_cnt; /**< number of parsed tables */ + int array_cnt; /**< number of parsed arrays */ +}; + +/* macros used to dump values after parsing */ +#define DUMP_KEY_FMT " %20s: " +#define DUMP(fmt, ...) fprintf(stdout, fmt "\n", ##__VA_ARGS__) +#define DUMP_KEY(key, fmt, ...) DUMP(DUMP_KEY_FMT fmt, key, ##__VA_ARGS__) + +void print_bytes(FILE *out, const uint8_t *arr, size_t len); + +#define DUMP_PRINTABLE_BYTES(name, var) _dump_printable_bytes(name, var, sizeof(var)) + +void _dump_printable_bytes(const char *name, const uint8_t *arr, size_t len); + +/** private parser error trace function */ +void vlog_err(const char *msg, va_list vl); + +/** parser error trace function, error code is returned to shorten client code */ +int log_err(int err_code, const char *msg, ...); + +/** log malloc error message for given key */ +int err_malloc(const char *key); + +/** log key not found error */ +int err_key_not_found(const char *key); + +/** error during parsing key value, possible detailed message */ +int err_key_parse(const char *key, const char *extra_msg, ...); + +/** initialize parser context before parsing */ +void parse_ctx_init(struct parse_ctx *ctx); + +/** check nothing left unparsed in given parsing context */ +int assert_everything_parsed(const toml_table_t *table, struct parse_ctx *ctx); + +/** + * Parse hex value from key in given toml table + * @param table toml table where key is specified + * @param ctx parsing context, key counter will be incremented after successful key parse + * @param key field name + * @param def is default value or -1 when value don't have default value + * @param error code, 0 when success + * @return default, parsed, or UINT32_MAX value for error cases + */ +uint32_t parse_uint32_hex_key(const toml_table_t *table, struct parse_ctx *ctx, + const char *key, int64_t def, int *error); + +/** + * Parse integer value from key in given toml table + * @param table toml table where key is specified + * @param ctx parsing context, key counter will be incremented after successful key parse + * @param key field name + * @param def is default value or -1 when value don't have default value + * @param error code, 0 when success + * @return default, parsed, or UINT32_MAX value for error cases + */ +uint32_t parse_uint32_key(const toml_table_t *table, struct parse_ctx *ctx, const char *key, + int64_t def, int *error); + +/** + * Parse string value from key in given toml table to uint8_t array. The + * destination is NOT a string because it is padded with zeros if and + * only if there is some capacity left. For string destinations use + * parse_str_key(). + * + * @param table toml table where key is specified + * @param ctx parsing context, key counter will be incremented after successful key parse + * @param key field name + * @param dst uint8_t[] destination + * @param capacity dst array size + * @param error code, 0 when success + */ +void parse_printable_key(const toml_table_t *table, struct parse_ctx *ctx, const char *key, + uint8_t *dst, int capacity, int *error); + +/** + * Parse string value from key in given toml table to given + * char[]. Destination is padded with zeros. As the only difference with + * parse_printable_key(), dst is guaranteed to be null-terminated when + * there is no error because the last destination byte is reserved for + * that. + * + * @param table toml table where key is specified + * @param ctx parsing context, key counter will be incremented after successful key parse + * @param key field name + * @param dst char[] destination + * @param capacity dst array size including null termination. + * @param error code, 0 when success + */ +void parse_str_key(const toml_table_t *table, struct parse_ctx *ctx, const char *key, + char *dst, int capacity, int *error); + +void parse_uuid(char *buf, uint8_t *uuid); + +/** version is stored as toml array with integer number, something like: + * "version = [1, 8]" + */ +int parse_version(toml_table_t *toml, int64_t version[2]); + +#endif /* __TOML_UTILS_H__ */ diff --git a/tools/rimage/src/manifest.c b/tools/rimage/src/manifest.c new file mode 100644 index 000000000000..19b73ee38e35 --- /dev/null +++ b/tools/rimage/src/manifest.c @@ -0,0 +1,1631 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2018-2022 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// Keyon Jie <yang.jie@linux.intel.com> +// Janusz Jankowski <janusz.jankowski@linux.intel.com> + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <time.h> +#include <sys/time.h> + +#include <rimage/sof/user/manifest.h> + +#include <rimage/rimage.h> +#include <rimage/css.h> +#include <rimage/cse.h> +#include <rimage/plat_auth.h> +#include <rimage/manifest.h> +#include <rimage/file_utils.h> +#include <rimage/misc_utils.h> +#include <rimage/hash.h> + +static int man_open_rom_file(struct image *image) +{ + uint32_t size; + int ret; + + ret = create_file_name(image->out_rom_file, sizeof(image->out_rom_file), image->out_file, + "rom"); + if (ret) + return ret; + + size = image->adsp->mem.zones[SOF_FW_BLK_TYPE_ROM].size; + + /* allocate ROM image */ + image->rom_image = calloc(size, 1); + if (!image->rom_image) + return -ENOMEM; + + /* open ROM outfile for writing */ + image->out_rom_fd = fopen(image->out_rom_file, "wb"); + if (!image->out_rom_fd) + return file_error("unable to open file for writing", image->out_rom_file); + + return 0; +} + +static int man_open_unsigned_file(struct image *image) +{ + int ret; + + ret = create_file_name(image->out_unsigned_file, sizeof(image->out_unsigned_file), + image->out_file, "uns"); + if (ret) + return ret; + + /* open unsigned FW outfile for writing */ + image->out_unsigned_fd = fopen(image->out_unsigned_file, "wb"); + if (!image->out_unsigned_fd) + return file_error("unable to open file for writing", image->out_unsigned_file); + + return 0; +} + +static int man_open_manifest_file(struct image *image) +{ + int ret; + + ret = create_file_name(image->out_man_file, sizeof(image->out_man_file), image->out_file, + "met"); + if (ret) + return ret; + + /* open manifest outfile for writing */ + image->out_man_fd = fopen(image->out_man_file, "wb"); + if (!image->out_man_fd) + return file_error("unable to open file for writing", image->out_man_file); + + return 0; +} + +static int man_init_image_v1_5(struct image *image) +{ + /* allocate image and copy template manifest */ + image->fw_image = calloc(image->adsp->image_size, 1); + if (!image->fw_image) + return -ENOMEM; + + memcpy(image->fw_image, image->adsp->man_v1_5, + sizeof(struct fw_image_manifest_v1_5)); + + return 0; +} + +static int man_init_image_v1_5_sue(struct image *image) +{ + /* allocate image and copy template manifest */ + image->fw_image = calloc(image->adsp->image_size, 1); + if (!image->fw_image) + return -ENOMEM; + + /* copy 1.5 sue manifest */ + memcpy(image->fw_image + MAN_DESC_OFFSET_V1_5_SUE, + image->adsp->man_v1_5_sue, + sizeof(struct fw_image_manifest_v1_5_sue)); + + return 0; +} + +static int man_init_image_v1_8(struct image *image) +{ + /* allocate image and copy template manifest */ + image->fw_image = calloc(image->adsp->image_size, 1); + if (!image->fw_image) + return -ENOMEM; + + memcpy(image->fw_image, image->adsp->man_v1_8, + sizeof(struct fw_image_manifest_v1_8)); + + return 0; +} + +static int man_init_image_v2_5(struct image *image) +{ + /* allocate image and copy template manifest */ + image->fw_image = calloc(image->adsp->image_size, 1); + if (!image->fw_image) + return -ENOMEM; + + memcpy(image->fw_image, image->adsp->man_v2_5, + sizeof(struct fw_image_manifest_v2_5)); + + return 0; +} + +/* write SRAM sections */ +static int man_copy_sram(struct image *image, const struct manifest_module *module, + const struct sof_man_segment_desc *segment, + const struct module_section *section) +{ + uint32_t offset, end; + int ret; + + assert(section->load_address >= segment->v_base_addr); + offset = segment->file_offset + section->load_address - segment->v_base_addr; + end = offset + section->size; + assert((uint64_t)offset + section->size <= image->adsp->image_size); + + ret = module_read_section(&module->file, section, image->fw_image + offset, + image->adsp->image_size - offset); + if (ret) + return ret; + + /* get module end offset ? */ + if (end > image->image_end) + image->image_end = end; + + fprintf(stdout, "\t0x%x\t0x%zx\t\t0x%x\t%s\t%s\n", section->load_address, section->size, + offset, section->type == MST_TEXT ? "TEXT" : "DATA", section->header->name); + + return 0; +} + +/** + * Write all linked sections + * + * @param image program global structure + * @param module modules manifest description + * @param section module section descriptor + * @return error code on error, 0 on success + */ +static int man_copy_elf_sections(struct image *image, struct manifest_module *module, + const struct sof_man_segment_desc *segment, + const struct module_section *section) +{ + int ret; + + while (section) { + ret = man_copy_sram(image, module, segment, section); + if (ret < 0) { + fprintf(stderr, "error: failed to write section %s\n", + section->header->name); + return ret; + } + + section = section->next_section; + } + + return 0; +} + +static int man_get_module_manifest(struct image *image, struct manifest_module *module, + struct sof_man_module *man_module) +{ + struct elf_section section; + struct sof_man_segment_desc *segment; + const struct sof_man_module_manifest *sof_mod; + int ret; + + fprintf(stdout, "Module Write: %s\n", module->file.elf.filename); + + /* load in module manifest data */ + ret = elf_section_read_by_name(&module->file.elf, ".module", §ion); + if (ret) { + fprintf(stderr, "error: can't read module manifest from '.module' section.\n"); + return ret; + } + + if (sizeof(*sof_mod) > section.header.data.size) { + fprintf(stderr, "error: Invalid module manifest in '.module' section.\n"); + ret = -ENODATA; + goto error; + } + sof_mod = section.data; + + /* configure man_module with sofmod data */ + memcpy(man_module->struct_id, "$AME", 4); + man_module->entry_point = sof_mod->module.entry_point; + memcpy(man_module->name, sof_mod->module.name, SOF_MAN_MOD_NAME_LEN); + memcpy(man_module->uuid, sof_mod->module.uuid, 16); + man_module->affinity_mask = sof_mod->module.affinity_mask; + man_module->type.auto_start = sof_mod->module.type.auto_start; + man_module->type.domain_dp = sof_mod->module.type.domain_dp; + man_module->type.domain_ll = sof_mod->module.type.domain_ll; + man_module->type.load_type = sof_mod->module.type.load_type; + + /* read out text_fixup_size from memory mapping */ + module->text_fixup_size = sof_mod->text_size; + + /* text segment */ + segment = &man_module->segment[SOF_MAN_SEGMENT_TEXT]; + segment->flags.r.contents = 1; + segment->flags.r.alloc = 1; + segment->flags.r.load = 1; + segment->flags.r.readonly = 1; + segment->flags.r.code = 1; + + /* data segment */ + segment = &man_module->segment[SOF_MAN_SEGMENT_RODATA]; + segment->flags.r.contents = 1; + segment->flags.r.alloc = 1; + segment->flags.r.load = 1; + segment->flags.r.readonly = 1; + segment->flags.r.data = 1; + segment->flags.r.type = 1; + + /* bss segment */ + segment = &man_module->segment[SOF_MAN_SEGMENT_BSS]; + segment->flags.r.alloc = 1; + segment->flags.r.type = 2; + + fprintf(stdout, " Entry point 0x%8.8x\n", man_module->entry_point); + +error: + elf_section_free(§ion); + return ret; +} + +static inline const char *segment_name(int i) +{ + switch (i) { + case SOF_MAN_SEGMENT_TEXT: + return "TEXT"; + case SOF_MAN_SEGMENT_RODATA: + return "DATA"; + case SOF_MAN_SEGMENT_BSS: + return "BSS"; + default: + return "NONE"; + } +} + +/* make sure no segments collide */ +static int man_module_validate(struct sof_man_module *man_module) +{ + uint32_t istart, iend; + uint32_t jstart, jend; + int i, j; + + for (i = 0; i < 3; i++) { + istart = man_module->segment[i].v_base_addr; + iend = istart + man_module->segment[i].flags.r.length * + MAN_PAGE_SIZE; + + for (j = 0; j < 3; j++) { + /* don't validate segment against itself */ + if (i == j) + continue; + + jstart = man_module->segment[j].v_base_addr; + jend = jstart + man_module->segment[j].flags.r.length * + MAN_PAGE_SIZE; + + if (jstart > istart && jstart < iend) + goto err; + + if (jend > istart && jend < iend) + goto err; + } + } + + /* success, no overlapping segments */ + return 0; + +err: + fprintf(stderr, "error: segment %s [0x%8.8x:0x%8.8x] overlaps", + segment_name(i), istart, iend); + fprintf(stderr, " with %s [0x%8.8x:0x%8.8x]\n", + segment_name(j), jstart, jend); + return -EINVAL; +} + +static int man_module_create(struct image *image, struct manifest_module *module, + struct sof_man_module *man_module) +{ + /* create module and segments */ + int err; + unsigned int pages; + const struct elf_section_header *bss; + + image->image_end = 0; + + err = man_get_module_manifest(image, module, man_module); + if (err < 0) + return err; + + /* stack size ??? convert sizes to PAGES */ + man_module->instance_bss_size = 1; + + /* max number of instances of this module ?? */ + man_module->instance_max_count = 1; + + module_print_zones(&module->file); + + /* main module */ + fprintf(stdout, "\tAddress\t\tSize\t\tFile\tType\tName\n"); + + /* text section is first */ + man_module->segment[SOF_MAN_SEGMENT_TEXT].file_offset = module->foffset; + man_module->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr = module->file.text.start; + + /* calculates those padding 0s by the start of next segment */ + /* file_size is already aligned to MAN_PAGE_SIZE */ + pages = module->file.text.file_size / MAN_PAGE_SIZE; + + if (module->text_fixup_size == 0) + module->text_fixup_size = module->file.text.file_size; + + /* check if text_file_size is bigger then text_fixup_size */ + if (module->file.text.file_size > module->text_fixup_size) { + fprintf(stderr, "error: too small text size assigned!\n"); + return -EINVAL; + } + + man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length = pages; + + /* Copy text sections content */ + err = man_copy_elf_sections(image, module, &man_module->segment[SOF_MAN_SEGMENT_TEXT], + module->file.text.first_section); + if (err) + return err; + + + /* data section */ + man_module->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr = module->file.data.start; + man_module->segment[SOF_MAN_SEGMENT_RODATA].file_offset = module->foffset + + module->text_fixup_size; + + /* file_size is already aligned to MAN_PAGE_SIZE */ + pages = module->file.data.file_size / MAN_PAGE_SIZE; + + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length = pages; + + /* Copy data sections content */ + err = man_copy_elf_sections(image, module, &man_module->segment[SOF_MAN_SEGMENT_RODATA], + module->file.data.first_section); + if (err) + return err; + + /* bss is last */ + + /* I do not understand why only the section named .bss was taken into account. Other + * sections of the same type were ignored (type = SHT_NOBITS, flags = SHF_ALLOC). I added + * the reading of the .bss section here, to not change the behavior of the program. + */ + bss = NULL; + + if (module->is_bootloader) { + /* Bootloader should not have .bss section. */ + fprintf(stdout, "info: ignore .bss section for bootloader module\n"); + } else { + err = elf_section_header_get_by_name(&module->file.elf, ".bss", &bss); + if (err) + fprintf(stderr, "warning: can't find '.bss' section in module %s.\n", + module->file.elf.filename); + + } + + man_module->segment[SOF_MAN_SEGMENT_BSS].file_offset = 0; + man_module->segment[SOF_MAN_SEGMENT_BSS].v_base_addr = 0; + pages = 0; + + if (bss) { + man_module->segment[SOF_MAN_SEGMENT_BSS].v_base_addr = + uncache_to_cache(&image->adsp->mem.alias, bss->data.vaddr); + + pages = DIV_ROUND_UP(bss->data.size, MAN_PAGE_SIZE); + } + + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.length = pages; + if (pages == 0) { + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.ul = 0; + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.type = SOF_MAN_SEGMENT_EMPTY; + } + + if (man_module_validate(man_module) < 0) + return -EINVAL; + + fprintf(stdout, "\n"); + + /* no need to update end for exec headers */ + if (module->exec_header) { + image->image_end = FILE_TEXT_OFFSET_V1_5_SUE; + goto out; + } + + /* round module end upto nearest page */ + if (image->image_end % MAN_PAGE_SIZE) { + image->image_end = (image->image_end / MAN_PAGE_SIZE) + 1; + image->image_end *= MAN_PAGE_SIZE; + } + +out: + fprintf(stdout, " Total pages text %d data %d bss %d module file limit: 0x%x\n\n", + man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length, + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length, + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.length, + image->image_end); + return 0; +} + +static int man_module_create_reloc(struct image *image, struct manifest_module *module, + struct sof_man_module *man_module) +{ + /* create module and segments */ + int err; + + image->image_end = 0; + + err = man_get_module_manifest(image, module, man_module); + if (err < 0) + return err; + + /* stack size ??? convert sizes to PAGES */ + man_module->instance_bss_size = 1; + + /* max number of instances of this module ?? */ + man_module->instance_max_count = 1; + + module_print_zones(&module->file); + + /* main module */ + /* text section is first */ + man_module->segment[SOF_MAN_SEGMENT_TEXT].file_offset = + module->foffset; + man_module->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr = 0; + man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length = 0; + + /* data section */ + man_module->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr = 0; + man_module->segment[SOF_MAN_SEGMENT_RODATA].file_offset = module->foffset; + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length = module->file.data.file_size / + MAN_PAGE_SIZE; + + /* bss is last */ + man_module->segment[SOF_MAN_SEGMENT_BSS].file_offset = 0; + man_module->segment[SOF_MAN_SEGMENT_BSS].v_base_addr = 0; + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.length = 0; + + fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\tType\n"); + + assert((module->file.elf.file_size + module->foffset) <= image->adsp->image_size); + err = module_read_whole_elf(&module->file, image->fw_image + module->foffset, + image->image_end - module->foffset); + if (err) + return err; + + fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8zx\t0x%x\t%s\n", 0, + 0, module->file.elf.file_size, 0, "DATA"); + + fprintf(stdout, "\n"); + image->image_end = module->foffset + module->file.elf.file_size; + + /* round module end up to nearest page */ + if (image->image_end % MAN_PAGE_SIZE) { + image->image_end = (image->image_end / MAN_PAGE_SIZE) + 1; + image->image_end *= MAN_PAGE_SIZE; + } + + fprintf(stdout, " Total pages text %d data %d bss %d module file limit: 0x%x\n\n", + man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length, + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length, + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.length, + image->image_end); + return 0; +} + +static int man_write_unsigned_mod(struct image *image, int meta_start_offset, + int meta_end_offset, size_t ext_file_size) +{ + int count; + + /* write metadata file for unsigned FW */ + count = fwrite(image->fw_image + meta_start_offset, + ext_file_size, 1, + image->out_man_fd); + + /* did the metadata/manifest write succeed ? */ + if (count != 1) + return file_error("failed to write meta", image->out_man_file); + + fclose(image->out_man_fd); + + /* now prepare the unsigned rimage */ + count = fwrite(image->fw_image + meta_end_offset, + image->image_end - meta_end_offset, + 1, image->out_unsigned_fd); + + /* did the unsigned FW write succeed ? */ + if (count != 1) + return file_error("failed to write firmware", image->out_unsigned_file); + fclose(image->out_unsigned_fd); + + return 0; +} + +static int man_write_fw_mod(struct image *image) +{ + int count; + + /* write manifest and signed image */ + count = fwrite(image->fw_image, image->image_end, 1, image->out_fd); + + /* did the image write succeed ? */ + if (count != 1) + return file_error("failed to write signed firmware", image->out_file); + + return 0; +} + +static int man_create_modules(struct image *image, struct sof_man_fw_desc *desc, + int file_text_offset) +{ + struct manifest_module *module; + struct sof_man_module *man_module; + int err; + int i = 0, offset = 0; + + /* if first module is executable then write before manifest */ + if (image->adsp->exec_boot_ldr) { + man_module = (void *)desc + SOF_MAN_MODULE_OFFSET(0); + module = &image->module[0]; + + fprintf(stdout, "Module: %s used as executable header\n", + module->file.elf.filename); + module->exec_header = 1; + + /* set module file offset */ + module->foffset = 0; + + err = man_module_create(image, module, man_module); + if (err < 0) + return err; + + /* setup man_modules for missing exec loader module */ + i = 1; + offset = 1; + } + + for (; i < image->num_modules; i++) { + man_module = (void *)desc + SOF_MAN_MODULE_OFFSET(i - offset); + + /* Some platforms dont have modules configuration in toml file */ + if (image->adsp->modules) { + /* Use manifest created using toml files as template */ + assert(i < image->adsp->modules->mod_man_count); + memcpy(man_module, &image->adsp->modules->mod_man[i], sizeof(*man_module)); + } + + module = &image->module[i]; + + if (i == 0) + module->foffset = file_text_offset; + else + module->foffset = image->image_end; + + if (image->reloc) + err = man_module_create_reloc(image, module, + man_module); + else + err = man_module_create(image, module, man_module); + + if (err < 0) + return err; + } + + return 0; +} + +static void man_create_modules_in_config(struct image *image, struct sof_man_fw_desc *desc) +{ + struct fw_image_manifest_module *modules; + struct sof_man_module *man_module; + void *cfg_start; + int i; + + modules = image->adsp->modules; + if (!modules) + return; + + /* skip modules passed as parameters. Their manifests have already been copied by the + * man_create_modules function. */ + for (i = image->num_modules; i < modules->mod_man_count; i++) { + man_module = (void *)desc + SOF_MAN_MODULE_OFFSET(i); + memcpy(man_module, &modules->mod_man[i], sizeof(*man_module)); + } + + /* We need to copy the configurations for all modules. */ + cfg_start = (void *)desc + SOF_MAN_MODULE_OFFSET(i); + memcpy(cfg_start, modules->mod_cfg, modules->mod_cfg_count * sizeof(struct sof_man_mod_config)); + + desc->header.num_module_entries = modules->mod_man_count; +} + +static int man_hash_modules(struct image *image, struct sof_man_fw_desc *desc) +{ + struct sof_man_module *man_module; + size_t mod_offset, mod_size; + int i, ret = 0; + + for (i = 0; i < image->num_modules; i++) { + man_module = (void *)desc + SOF_MAN_MODULE_OFFSET(i); + + if (image->adsp->exec_boot_ldr && i == 0) { + fprintf(stdout, " module: no need to hash %s\n as its exec header\n", + man_module->name); + continue; + } + + mod_offset = man_module->segment[SOF_MAN_SEGMENT_TEXT].file_offset; + mod_size = (man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length + + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length) * + MAN_PAGE_SIZE; + + assert((mod_offset + mod_size) <= image->adsp->image_size); + + ret = hash_sha256(image->fw_image + mod_offset, mod_size, man_module->hash, sizeof(man_module->hash)); + if (ret) + break; + } + + return ret; +} + +/* used by others */ +int man_write_fw_v1_5(struct image *image) +{ + struct sof_man_fw_desc *desc; + struct fw_image_manifest_v1_5 *m; + int ret; + + /* init image */ + ret = man_init_image_v1_5(image); + if (ret < 0) + goto err; + + /* open ROM image */ + ret = man_open_rom_file(image); + if (ret < 0) + goto err; + + /* open unsigned firmware */ + ret = man_open_unsigned_file(image); + if (ret < 0) + goto err; + + /* create the manifest */ + ret = man_open_manifest_file(image); + if (ret < 0) + goto err; + + /* create the module */ + m = image->fw_image; + desc = image->fw_image + MAN_DESC_OFFSET_V1_5; + + /* firmware and build version */ + m->desc.header.major_version = image->fw_ver_major; + m->desc.header.minor_version = image->fw_ver_minor; + m->desc.header.hotfix_version = image->fw_ver_micro; + m->desc.header.build_version = image->fw_ver_build; + + /* create each module */ + m->desc.header.num_module_entries = image->num_modules; + ret = man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_5); + if (ret) + goto err; + + fprintf(stdout, "Firmware completing manifest v1.5\n"); + + /* create structures from end of file to start of file */ + ri_css_v1_5_hdr_create(image); + + fprintf(stdout, "Firmware file size 0x%x page count %d\n", + FILE_TEXT_OFFSET_V1_5 - MAN_DESC_OFFSET_V1_5 + image->image_end, + desc->header.preload_page_count); + + /* calculate hash for each module */ + man_hash_modules(image, desc); + + /* sign manifest */ + ret = ri_manifest_sign_v1_5(image); + if (ret < 0) + goto err; + + /* write the firmware */ + ret = man_write_fw_mod(image); + if (ret < 0) + goto err; + + /* write the unsigned files*/ + ret = man_write_unsigned_mod(image, MAN_META_EXT_OFFSET_V1_5, + MAN_FW_DESC_OFFSET_V1_5, + sizeof(struct sof_man_adsp_meta_file_ext_v1_8)); + if (ret < 0) + goto err; + + fprintf(stdout, "Firmware manifest and signing completed !\n"); + return 0; + +err: + free(image->rom_image); + free(image->fw_image); + unlink(image->out_file); + unlink(image->out_rom_file); + return ret; +} + +/* used by others */ +int man_write_fw_v1_5_sue(struct image *image) +{ + struct fw_image_manifest_v1_5_sue *m; + uint32_t preload_size; + int ret; + + /* init image */ + ret = man_init_image_v1_5_sue(image); + if (ret < 0) + goto err; + + /* create the manifest */ + ret = man_open_manifest_file(image); + if (ret < 0) + goto err; + + /* create the module */ + m = image->fw_image + MAN_DESC_OFFSET_V1_5_SUE; + + /* firmware and build version */ + m->desc.header.major_version = image->fw_ver_major; + m->desc.header.minor_version = image->fw_ver_minor; + m->desc.header.hotfix_version = image->fw_ver_micro; + m->desc.header.build_version = image->fw_ver_build; + + /* create each module - subtract the boot loader exec header */ + m->desc.header.num_module_entries = image->num_modules - 1; + ret = man_create_modules(image, &m->desc, FILE_TEXT_OFFSET_V1_5_SUE); + if (ret) + goto err; + + fprintf(stdout, "Firmware completing manifest v1.5\n"); + + /* write preload page count */ + preload_size = image->image_end - MAN_DESC_OFFSET_V1_5_SUE; + preload_size += MAN_PAGE_SIZE - (preload_size % MAN_PAGE_SIZE); + m->desc.header.preload_page_count = preload_size / MAN_PAGE_SIZE; + + fprintf(stdout, "Firmware file size 0x%x page count %d\n", + FILE_TEXT_OFFSET_V1_5_SUE - MAN_DESC_OFFSET_V1_5_SUE + + image->image_end, m->desc.header.preload_page_count); + + /* calculate hash for each module */ + man_hash_modules(image, &m->desc); + + /* write the firmware */ + ret = man_write_fw_mod(image); + if (ret < 0) + goto err; + + fprintf(stdout, "Firmware manifest and signing completed !\n"); + return 0; + +err: + free(image->fw_image); + unlink(image->out_file); + return ret; +} + +/* used by others */ +int man_write_fw_v1_8(struct image *image) +{ + struct sof_man_fw_desc *desc; + struct fw_image_manifest_v1_8 *m; + int ret; + + /* init image */ + ret = man_init_image_v1_8(image); + if (ret < 0) + goto err; + + /* open ROM image */ + ret = man_open_rom_file(image); + if (ret < 0) + goto err; + + /* open unsigned firmware */ + ret = man_open_unsigned_file(image); + if (ret < 0) + goto err; + + /* create the manifest */ + ret = man_open_manifest_file(image); + if (ret < 0) + goto err; + + /* create the module */ + m = image->fw_image; + desc = image->fw_image + MAN_DESC_OFFSET_V1_8; + + /* firmware and build version */ + m->css.version.major_version = image->fw_ver_major; + m->css.version.minor_version = image->fw_ver_minor; + m->css.version.build_version = image->fw_ver_build; + m->desc.header.major_version = image->fw_ver_major; + m->desc.header.minor_version = image->fw_ver_minor; + m->desc.header.hotfix_version = image->fw_ver_micro; + m->desc.header.build_version = image->fw_ver_build; + + /* create each module */ + m->desc.header.num_module_entries = image->num_modules; + ret = man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_8); + if (ret) + goto err; + + fprintf(stdout, "Firmware completing manifest v1.8\n"); + + /* create structures from end of file to start of file */ + ri_adsp_meta_data_create_v1_8(image, MAN_META_EXT_OFFSET_V1_8, + MAN_FW_DESC_OFFSET_V1_8); + ri_plat_ext_data_create(image); + ri_css_v1_8_hdr_create(image); + ri_cse_create(image); + + fprintf(stdout, "Firmware file size 0x%x page count %d\n", + FILE_TEXT_OFFSET_V1_8 - MAN_DESC_OFFSET_V1_8 + image->image_end, + desc->header.preload_page_count); + + /* calculate hash for each module */ + man_hash_modules(image, desc); + + /* calculate hash for ADSP meta data extension - 0x480 to end */ + /* image_end is updated every time a section is added */ + assert(image->image_end > MAN_FW_DESC_OFFSET_V1_8); + ret = hash_sha256(image->fw_image + MAN_FW_DESC_OFFSET_V1_8, + image->image_end - MAN_FW_DESC_OFFSET_V1_8, + m->adsp_file_ext.comp_desc[0].hash, + sizeof(m->adsp_file_ext.comp_desc[0].hash)); + if (ret) + goto err; + + /* calculate hash for platform auth data - repeated in hash 2 and 4 */ + assert(image->image_end > (MAN_FW_DESC_OFFSET_V1_8 + + sizeof(struct sof_man_adsp_meta_file_ext_v1_8))); + + ret = hash_sha256(image->fw_image + MAN_FW_DESC_OFFSET_V1_8, + image->image_end - MAN_FW_DESC_OFFSET_V1_8, + m->signed_pkg.module[0].hash, + sizeof(m->signed_pkg.module[0].hash)); + if (ret) + goto err; + + /* hash values in reverse order */ + bytes_swap(m->signed_pkg.module[0].hash, sizeof(m->signed_pkg.module[0].hash)); + + /* Copy module hash to partition_info */ + assert(sizeof(m->partition_info.module[0].hash) == sizeof(m->signed_pkg.module[0].hash)); + memcpy(m->partition_info.module[0].hash, m->signed_pkg.module[0].hash, + sizeof(m->partition_info.module[0].hash)); + + /* sign manifest */ + ret = ri_manifest_sign_v1_8(image); + if (ret < 0) + goto err; + + /* write the firmware */ + ret = man_write_fw_mod(image); + if (ret < 0) + goto err; + + /* write the unsigned files*/ + ret = man_write_unsigned_mod(image, MAN_META_EXT_OFFSET_V1_8, + MAN_FW_DESC_OFFSET_V1_8, + sizeof(struct sof_man_adsp_meta_file_ext_v1_8)); + if (ret < 0) + goto err; + + fprintf(stdout, "Firmware manifest and signing completed !\n"); + return 0; + +err: + free(image->rom_image); + free(image->fw_image); + unlink(image->out_file); + unlink(image->out_rom_file); + return ret; +} + +/* used to sign with MEU */ +int man_write_fw_meu_v1_5(struct image *image) +{ + const int meta_start_offset = image->meu_offset - + sizeof(struct sof_man_adsp_meta_file_ext_v1_8) - MAN_EXT_PADDING; + struct sof_man_adsp_meta_file_ext_v1_8 *meta; + struct sof_man_fw_desc *desc; + uint32_t preload_size; + int ret; + + /* allocate image */ + image->fw_image = calloc(image->adsp->image_size, 1); + if (!image->fw_image) { + ret = -ENOMEM; + goto err; + } + + /* open unsigned firmware */ + ret = man_open_unsigned_file(image); + if (ret < 0) + goto err; + + /* create the manifest */ + ret = man_open_manifest_file(image); + if (ret < 0) + goto err; + + /* create the module */ + meta = image->fw_image + meta_start_offset; + desc = image->fw_image + MAN_DESC_OFFSET_V1_5; + + /* copy data */ + memcpy(desc, &image->adsp->man_v1_5->desc, + sizeof(struct sof_man_fw_desc)); + + /* firmware and build version */ + desc->header.major_version = image->fw_ver_major; + desc->header.minor_version = image->fw_ver_minor; + desc->header.hotfix_version = image->fw_ver_micro; + desc->header.build_version = image->fw_ver_build; + + /* create each module */ + desc->header.num_module_entries = image->num_modules; + ret = man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_5); + if (ret) + goto err; + + fprintf(stdout, "Firmware completing manifest v1.5\n"); + + /* create structures from end of file to start of file */ + ri_adsp_meta_data_create_v1_8(image, meta_start_offset, + image->meu_offset); + + /* write preload page count */ + preload_size = meta->comp_desc[0].limit_offset - MAN_DESC_OFFSET_V1_5; + preload_size += MAN_PAGE_SIZE - (preload_size % MAN_PAGE_SIZE); + desc->header.preload_page_count = preload_size / MAN_PAGE_SIZE; + + /* calculate hash for each module */ + man_hash_modules(image, desc); + + /* calculate hash for ADSP meta data extension */ + assert(image->meu_offset < image->image_end); + ret = hash_sha256(image->fw_image + image->meu_offset, image->image_end - image->meu_offset, + meta->comp_desc[0].hash, sizeof(meta->comp_desc[0].hash)); + if (ret) + goto err; + + /* write the unsigned files */ + ret = man_write_unsigned_mod(image, meta_start_offset, + image->meu_offset, + sizeof(struct sof_man_adsp_meta_file_ext_v1_8)); + if (ret < 0) + goto err; + + fprintf(stdout, "Firmware manifest completed!\n"); + return 0; + +err: + free(image->fw_image); + unlink(image->out_file); + return ret; +} + +/* used to sign with MEU */ +int man_write_fw_meu_v1_8(struct image *image) +{ + const int meta_start_offset = image->meu_offset - + sizeof(struct sof_man_adsp_meta_file_ext_v1_8) - MAN_EXT_PADDING; + struct sof_man_adsp_meta_file_ext_v1_8 *meta; + struct sof_man_fw_desc *desc; + uint32_t preload_size; + int ret; + + /* allocate image */ + image->fw_image = calloc(image->adsp->image_size, 1); + if (!image->fw_image) { + ret = -ENOMEM; + goto err; + } + + /* open unsigned firmware */ + ret = man_open_unsigned_file(image); + if (ret < 0) + goto err; + + /* create the manifest */ + ret = man_open_manifest_file(image); + if (ret < 0) + goto err; + + /* create the module */ + meta = image->fw_image + meta_start_offset; + desc = image->fw_image + MAN_DESC_OFFSET_V1_8; + + /* copy data */ + memcpy(meta, &image->adsp->man_v1_8->adsp_file_ext, + sizeof(struct sof_man_adsp_meta_file_ext_v1_8)); + memcpy(desc, &image->adsp->man_v1_8->desc, + sizeof(struct sof_man_fw_desc)); + + /* firmware and build version */ + desc->header.major_version = image->fw_ver_major; + desc->header.minor_version = image->fw_ver_minor; + desc->header.hotfix_version = image->fw_ver_micro; + desc->header.build_version = image->fw_ver_build; + + /* create each module */ + desc->header.num_module_entries = image->num_modules; + ret = man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_8); + if (ret) + goto err; + + fprintf(stdout, "Firmware completing manifest v1.8\n"); + + /* create structures from end of file to start of file */ + ri_adsp_meta_data_create_v1_8(image, meta_start_offset, + image->meu_offset); + + /* write preload page count */ + preload_size = meta->comp_desc[0].limit_offset - MAN_DESC_OFFSET_V1_8; + preload_size += MAN_PAGE_SIZE - (preload_size % MAN_PAGE_SIZE); + desc->header.preload_page_count = preload_size / MAN_PAGE_SIZE; + + /* calculate hash for each module */ + man_hash_modules(image, desc); + + /* calculate hash for ADSP meta data extension */ + assert(image->meu_offset < image->image_end); + ret = hash_sha256(image->fw_image + image->meu_offset, image->image_end - image->meu_offset, + meta->comp_desc[0].hash, sizeof(meta->comp_desc[0].hash)); + if (ret) + goto err; + + /* write the unsigned files */ + ret = man_write_unsigned_mod(image, meta_start_offset, + image->meu_offset, + sizeof(struct sof_man_adsp_meta_file_ext_v1_8)); + if (ret < 0) + goto err; + + fprintf(stdout, "Firmware manifest completed!\n"); + return 0; + +err: + free(image->fw_image); + unlink(image->out_file); + return ret; +} + +/* used to sign with MEU */ +int man_write_fw_meu_v2_5(struct image *image) +{ + const int meta_start_offset = image->meu_offset - + sizeof(struct sof_man_adsp_meta_file_ext_v2_5) - MAN_EXT_PADDING; + struct sof_man_adsp_meta_file_ext_v2_5 *meta; + struct sof_man_fw_desc *desc; + uint32_t preload_size; + int ret; + + /* allocate image */ + image->fw_image = calloc(image->adsp->image_size, 1); + if (!image->fw_image) { + ret = -ENOMEM; + goto err; + } + + /* open unsigned firmware */ + ret = man_open_unsigned_file(image); + if (ret < 0) + goto err; + + /* create the manifest */ + ret = man_open_manifest_file(image); + if (ret < 0) + goto err; + + /* create the module */ + meta = image->fw_image + meta_start_offset; + desc = image->fw_image + MAN_DESC_OFFSET_V1_8; + + /* copy data */ + memcpy(meta, &image->adsp->man_v2_5->adsp_file_ext, + sizeof(struct sof_man_adsp_meta_file_ext_v2_5)); + memcpy(desc, &image->adsp->man_v2_5->desc, + sizeof(struct sof_man_fw_desc)); + + /* firmware and build version */ + desc->header.major_version = image->fw_ver_major; + desc->header.minor_version = image->fw_ver_minor; + desc->header.hotfix_version = image->fw_ver_micro; + desc->header.build_version = image->fw_ver_build; + + /* create each module */ + desc->header.num_module_entries = image->num_modules; + ret = man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_8); + if (ret) + goto err; + + /* platform config defines some modules except bringup & base modules */ + man_create_modules_in_config(image, desc); + + fprintf(stdout, "Firmware completing manifest v2.5\n"); + + /* create structures from end of file to start of file */ + ri_adsp_meta_data_create_v2_5(image, meta_start_offset, + image->meu_offset); + + /* write preload page count */ + preload_size = meta->comp_desc[0].limit_offset - MAN_DESC_OFFSET_V1_8; + preload_size += MAN_PAGE_SIZE - (preload_size % MAN_PAGE_SIZE); + desc->header.preload_page_count = preload_size / MAN_PAGE_SIZE; + + /* calculate hash for each module */ + man_hash_modules(image, desc); + + /* calculate hash for ADSP meta data extension */ + assert(image->meu_offset < image->image_end); + ret = hash_sha384(image->fw_image + image->meu_offset, image->image_end - image->meu_offset, + meta->comp_desc[0].hash, sizeof(meta->comp_desc[0].hash)); + if (ret) + goto err; + + /* write the unsigned files */ + ret = man_write_unsigned_mod(image, meta_start_offset, + image->meu_offset, + sizeof(struct sof_man_adsp_meta_file_ext_v2_5)); + if (ret < 0) + goto err; + + fprintf(stdout, "Firmware manifest completed!\n"); + return 0; + +err: + free(image->fw_image); + unlink(image->out_file); + return ret; +} + +/* used by others */ +int man_write_fw_v2_5(struct image *image) +{ + struct sof_man_fw_desc *desc; + struct fw_image_manifest_v2_5 *m; + int ret; + + /* init image */ + ret = man_init_image_v2_5(image); + if (ret < 0) + goto err; + + /* use default meu offset for TGL if not provided */ + if (!image->meu_offset) + image->meu_offset = MAN_FW_DESC_OFFSET_V2_5 - 0x10; + + /* open ROM image */ + ret = man_open_rom_file(image); + if (ret < 0) + goto err; + + /* open unsigned firmware */ + ret = man_open_unsigned_file(image); + if (ret < 0) + goto err; + + /* create the manifest */ + ret = man_open_manifest_file(image); + if (ret < 0) + goto err; + + /* create the module */ + m = image->fw_image; + desc = image->fw_image + MAN_DESC_OFFSET_V1_8; + + /* firmware and build version */ + m->css.version.major_version = image->fw_ver_major; + m->css.version.minor_version = image->fw_ver_minor; + m->css.version.build_version = image->fw_ver_build; + m->desc.header.major_version = image->fw_ver_major; + m->desc.header.minor_version = image->fw_ver_minor; + m->desc.header.hotfix_version = image->fw_ver_micro; + m->desc.header.build_version = image->fw_ver_build; + + /* create each module */ + m->desc.header.num_module_entries = image->num_modules; + ret = man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_8); + if (ret) + goto err; + + /* platform config defines some modules except bringup & base modules */ + man_create_modules_in_config(image, desc); + + fprintf(stdout, "Firmware completing manifest v2.5\n"); + + /* create structures from end of file to start of file */ + ri_adsp_meta_data_create_v2_5(image, MAN_META_EXT_OFFSET_V2_5, + image->meu_offset); + ri_plat_ext_data_create_v2_5(image); + ri_css_v2_5_hdr_create(image); + ri_cse_create_v2_5(image); + + fprintf(stdout, "Firmware file size 0x%x page count %d\n", + FILE_TEXT_OFFSET_V1_8 - MAN_DESC_OFFSET_V1_8 + image->image_end, + desc->header.preload_page_count); + + /* calculate hash for each module */ + man_hash_modules(image, desc); + + /* calculate hash inside ADSP meta data extension for padding to end */ + assert(image->meu_offset < image->image_end); + ret = hash_sha384(image->fw_image + image->meu_offset, image->image_end - image->meu_offset, + m->adsp_file_ext.comp_desc[0].hash, + sizeof(m->adsp_file_ext.comp_desc[0].hash)); + if (ret) + goto err; + + /* mue writes 0xff to 16 bytes of padding */ + memset(m->reserved, 0xff, 16); + + /* calculate hash inside ext info 16 of sof_man_adsp_meta_file_ext_v2_5 */ + assert((MAN_META_EXT_OFFSET_V2_5 + sizeof(struct sof_man_adsp_meta_file_ext_v2_5)) < + image->image_end); + + ret = hash_sha384(image->fw_image + MAN_META_EXT_OFFSET_V2_5, + sizeof(struct sof_man_adsp_meta_file_ext_v2_5), + m->signed_pkg.module[0].hash, sizeof(m->signed_pkg.module[0].hash)); + if (ret) + goto err; + + /* hash values in reverse order */ + bytes_swap(m->signed_pkg.module[0].hash, sizeof(m->signed_pkg.module[0].hash)); + + /* sign manifest */ + ret = ri_manifest_sign_v2_5(image); + if (ret < 0) + goto err; + +#if 0 + /* calculate hash - SHA384 on CAVS2_5+ */ + module_sha384_create(image); + module_sha_update(image, image->fw_image, + sizeof(struct CsePartitionDirHeader_v2_5) + + sizeof(struct CsePartitionDirEntry) * 3); + module_sha_update(image, image->fw_image + 0x4c0, image->image_end - 0x4c0); + module_sha_complete(image, hash); + + /* hash values in reverse order */ + for (i = 0; i < SOF_MAN_MOD_SHA384_LEN; i++) { + m->info_0x16.hash[i] = + hash[SOF_MAN_MOD_SHA384_LEN - 1 - i]; + } +#endif + /* write the firmware */ + ret = man_write_fw_mod(image); + if (ret < 0) + goto err; + + /* write the unsigned files*/ + ret = man_write_unsigned_mod(image, MAN_META_EXT_OFFSET_V2_5, + MAN_FW_DESC_OFFSET_V2_5, + sizeof(struct sof_man_adsp_meta_file_ext_v2_5)); + if (ret < 0) + goto err; + + fprintf(stdout, "Firmware manifest and signing completed !\n"); + return 0; + +err: + free(image->rom_image); + free(image->fw_image); + unlink(image->out_file); + unlink(image->out_rom_file); + return ret; +} + +static int man_init_image_ace_v1_5(struct image *image) +{ + /* allocate image and copy template manifest */ + image->fw_image = calloc(image->adsp->image_size, 1); + if (!image->fw_image) + return -ENOMEM; + + memcpy(image->fw_image, image->adsp->man_ace_v1_5, + sizeof(struct fw_image_manifest_ace_v1_5)); + + return 0; +} + +int man_write_fw_ace_v1_5(struct image *image) +{ + struct hash_context hash; + struct sof_man_fw_desc *desc; + struct fw_image_manifest_ace_v1_5 *m; + int ret; + + /* init image */ + ret = man_init_image_ace_v1_5(image); + if (ret < 0) + goto err; + + /* use default meu offset for TGL if not provided */ + if (!image->meu_offset) + image->meu_offset = MAN_FW_DESC_OFFSET_ACE_V1_5 - 0x10; + + /* open ROM image */ + ret = man_open_rom_file(image); + if (ret < 0) + goto err; + + /* open unsigned firmware */ + ret = man_open_unsigned_file(image); + if (ret < 0) + goto err; + + /* create the manifest */ + ret = man_open_manifest_file(image); + if (ret < 0) + goto err; + + /* create the module */ + m = image->fw_image; + desc = image->fw_image + MAN_DESC_OFFSET_V1_8; + + /* firmware and build version */ + m->css.version.major_version = image->fw_ver_major; + m->css.version.minor_version = image->fw_ver_minor; + m->css.version.build_version = image->fw_ver_build; + m->desc.header.major_version = image->fw_ver_major; + m->desc.header.minor_version = image->fw_ver_minor; + m->desc.header.hotfix_version = image->fw_ver_micro; + m->desc.header.build_version = image->fw_ver_build; + + m->desc.header.feature_mask = 0x2; // -> should be feature mask - to fix + m->desc.header.fw_image_flags = 0x2; // -> should be feature mask - to fix + m->desc.header.fw_compat = 0x100000; // -> PUT PROPER STRUCT + + /* create each module */ + m->desc.header.num_module_entries = image->num_modules; + ret = man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_8); + if (ret) + goto err; + + /* platform config defines some modules except bringup & base modules */ + man_create_modules_in_config(image, desc); + + fprintf(stdout, "Firmware completing manifest v2.5\n"); + + /* create structures from end of file to start of file */ + ri_adsp_meta_data_create_v2_5(image, MAN_META_EXT_OFFSET_ACE_V1_5, + image->meu_offset); + ri_plat_ext_data_create_ace_v1_5(image); + ri_css_v2_5_hdr_create(image); + ri_cse_create_ace_v1_5(image); + + fprintf(stdout, "Firmware file size 0x%x page count %d\n", + FILE_TEXT_OFFSET_V1_8 - MAN_DESC_OFFSET_V1_8 + image->image_end, + desc->header.preload_page_count); + + /* calculate hash for each module */ + man_hash_modules(image, desc); + + /* calculate hash inside ADSP meta data extension for padding to end */ + assert(image->meu_offset < image->image_end); + ret = hash_sha384(image->fw_image + image->meu_offset, image->image_end - image->meu_offset, + m->adsp_file_ext.comp_desc[0].hash, + sizeof(m->adsp_file_ext.comp_desc[0].hash)); + if (ret) + goto err; + + /* mue writes 0xff to 16 bytes of padding */ + memset(m->reserved, 0xff, 16); + + /* calculate hash inside ext info 16 of sof_man_adsp_meta_file_ext_v2_5 */ + assert((MAN_META_EXT_OFFSET_ACE_V1_5 + sizeof(struct sof_man_adsp_meta_file_ext_v2_5)) < + image->image_end); + + ret = hash_sha384(image->fw_image + MAN_META_EXT_OFFSET_ACE_V1_5, + sizeof(struct sof_man_adsp_meta_file_ext_v2_5), + m->signed_pkg.module[0].hash, sizeof(m->signed_pkg.module[0].hash)); + if (ret) + goto err; + + /* hash values in reverse order */ + bytes_swap(m->signed_pkg.module[0].hash, sizeof(m->signed_pkg.module[0].hash)); + + /* calculate hash - SHA384 on CAVS2_5+ */ + hash_sha384_init(&hash); + hash_update(&hash, image->fw_image, + sizeof(struct CsePartitionDirHeader_v2_5) + + sizeof(struct CsePartitionDirEntry) * 3); + + hash_update(&hash, image->fw_image + 0x4c0, image->image_end - 0x4c0); + hash_finalize(&hash); + + /* hash values in reverse order */ + ret = hash_get_digest(&hash, m->info_0x16.hash, sizeof(m->info_0x16.hash)); + if (ret < 0) + goto err; + bytes_swap(m->info_0x16.hash, sizeof(m->info_0x16.hash)); + + /* sign manifest */ + ret = ri_manifest_sign_ace_v1_5(image); + if (ret < 0) + goto err; + + /* write the firmware */ + ret = man_write_fw_mod(image); + if (ret < 0) + goto err; + + /* write the unsigned files*/ + ret = man_write_unsigned_mod(image, MAN_META_EXT_OFFSET_ACE_V1_5, + MAN_FW_DESC_OFFSET_ACE_V1_5, + sizeof(struct sof_man_adsp_meta_file_ext_v2_5)); + if (ret < 0) + goto err; + + fprintf(stdout, "Firmware manifest and signing completed !\n"); + return 0; + +err: + free(image->rom_image); + free(image->fw_image); + unlink(image->out_file); + unlink(image->out_rom_file); + return ret; +} + +int verify_image(struct image *image) +{ + FILE *in_file; + int ret; + void *buffer; + size_t size, read, i; + + /* is verify supported for target ? */ + if (!image->adsp->verify_firmware) { + fprintf(stderr, "error: verify not supported for target\n"); + return -EINVAL; + } + + /* open image for reading */ + in_file = fopen(image->verify_file, "rb"); + if (!in_file) + return file_error("unable to open file for reading", image->verify_file); + + /* get file size */ + ret = get_file_size(in_file, image->verify_file, &size); + if (ret < 0) { + goto out; + } + + /* allocate buffer for parsing */ + buffer = malloc(size); + if (!buffer) { + ret = -ENOMEM; + goto out; + } + + /* find start of fw image and verify */ + read = fread(buffer, 1, size, in_file); + if (read != size) { + ret = file_error("unable to read whole file", image->verify_file); + goto out; + } + for (i = 0; i < size; i += sizeof(uint32_t)) { + /* find CSE header marker "$CPD" */ + if (*(uint32_t *)(buffer + i) == CSE_HEADER_MAKER) { + image->fw_image = buffer + i; + ret = image->adsp->verify_firmware(image); + goto out; + } + } + + /* no header found */ + fprintf(stderr, "error: could not find valid CSE header $CPD in %s\n", + image->verify_file); +out: + fclose(in_file); + return 0; +} + + +int resign_image(struct image *image) +{ + int key_size, key_file_size; + void *buffer = NULL; + size_t size, read; + FILE *in_file; + int ret, i; + + /* open image for reading */ + in_file = fopen(image->in_file, "rb"); + if (!in_file) + return file_error("unable to open file for reading", image->in_file); + + /* get file size */ + ret = get_file_size(in_file, image->in_file, &size); + if (ret < 0) { + goto out; + } + + /* allocate buffer for parsing */ + buffer = malloc(size); + if (!buffer) { + ret = -ENOMEM; + goto out; + } + + /* read file into buffer */ + read = fread(buffer, 1, size, in_file); + if (read != size) { + ret = file_error("unable to read whole file", image->in_file); + goto out; + } + + fclose(in_file); + + for (i = 0; i < size; i += sizeof(uint32_t)) { + /* find CSE header marker "$CPD" */ + if (*(uint32_t *)(buffer + i) == CSE_HEADER_MAKER) { + image->fw_image = buffer + i; + break; + } + } + + if (i >= size) { + fprintf(stderr, "error: didn't found header marker %d\n", i); + ret = -EINVAL; + goto out; + } + + image->image_end = size; + + /* check that key size matches */ + if (image->adsp->man_v2_5) { + key_size = 384; + } else { + key_size = 256; + } + + key_file_size = get_key_size(image); + + if (key_file_size > key_size) { + fprintf(stderr, "error: key size %d is longer than original key %d\n", + key_file_size, key_size); + ret = -EINVAL; + goto out; + } + + /* resign */ + if (image->adsp->man_v1_5) + ret = ri_manifest_sign_v1_5(image); + else if (image->adsp->man_v1_8) + ret = ri_manifest_sign_v1_8(image); + else if (image->adsp->man_v2_5) + ret = ri_manifest_sign_v2_5(image); + else + ret = -EINVAL; + + if (ret < 0) { + fprintf(stderr, "error: unable to sign image\n"); + goto out; + } + + /* open outfile for writing */ + unlink(image->out_file); + image->out_fd = fopen(image->out_file, "wb"); + if (!image->out_fd) { + ret = file_error("unable to open file for writting", image->out_file); + goto out; + } + + man_write_fw_mod(image); + +out: + free(buffer); + return ret; +} diff --git a/tools/rimage/src/misc_utils.c b/tools/rimage/src/misc_utils.c new file mode 100644 index 000000000000..2c0146f5bdd9 --- /dev/null +++ b/tools/rimage/src/misc_utils.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2018-2023 Intel Corporation. All rights reserved. + * + * Author: Adrian Warecki <adrian.warecki@intel.com> + */ + +#include <stdio.h> +#include <rimage/misc_utils.h> + +void bytes_swap(uint8_t *ptr, uint32_t size) +{ + uint8_t tmp; + uint32_t index; + + for (index = 0; index < (size / 2); index++) { + tmp = ptr[index]; + ptr[index] = ptr[size - 1 - index]; + ptr[size - 1 - index] = tmp; + } +} + +void print_enum(unsigned long value, const struct name_val *values) +{ + while (values->name) { + if (values->value == value) { + fprintf(stdout, "%s\n", values->name); + return; + } + + values++; + } + + printf("Unknown: 0x%lx\n", value); +} + +void print_flags(unsigned long value, const struct name_val *flags) +{ + while (flags->name) { + if (value & flags->value) { + fprintf(stdout, "%s ", flags->name); + value &= ~flags->value; + } + + flags++; + } + + if (value) + fprintf(stdout, "+ 0x%lx", value); + printf("\n"); +} diff --git a/tools/rimage/src/module.c b/tools/rimage/src/module.c new file mode 100644 index 000000000000..0fb4de075de7 --- /dev/null +++ b/tools/rimage/src/module.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Adrian Warecki <adrian.warecki@intel.com> + */ + +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <assert.h> + +#include <rimage/module.h> +#include <rimage/elf_file.h> +#include <rimage/file_utils.h> +#include <rimage/rimage.h> + + +int module_read_section(const struct module *module, const struct module_section *section, + void *buffer, const size_t size) +{ + return elf_section_read_content(&module->elf, section->header, buffer, size); +} + +int module_write_section(const struct module *module, const struct module_section *section, + const int padding, FILE *out_file, const char *filename) +{ + int ret; + struct elf_section section_data; + size_t count; + char padding_buf[4]; + + ret = elf_section_read(&module->elf, section->header, §ion_data); + if (ret) + return ret; + + /* write out section data */ + count = fwrite(section_data.data, section->size, 1, out_file); + if (count != 1) { + ret = file_error("cant write section", filename); + goto out; + } + + /* write padding data */ + if (padding) { + assert(padding <= sizeof(padding_buf)); + + memset(padding_buf, 0, padding); + count = fwrite(padding_buf, padding, 1, out_file); + if (count != 1) { + ret = file_error("cant write padding", filename); + goto out; + } + } + +out: + elf_section_free(§ion_data); + return ret; +} + +int module_read_whole_elf(const struct module *module, void *buffer, size_t size) +{ + int ret; + size_t count; + + if (module->elf.file_size > size) { + fprintf(stderr, "error: Output buffer too small.\n"); + return -ENOSPC; + } + + /* read in file data */ + ret = fseek(module->elf.file, 0, SEEK_SET); + if (ret) + return file_error("can't seek set", module->elf.filename); + + count = fread(buffer, module->elf.file_size, 1, module->elf.file); + if (count != 1) + return file_error("can't read data", module->elf.filename); + + return ret; +} + +int module_write_whole_elf(const struct module *module, FILE *out_file, const char *filename) +{ + int ret; + char *buffer; + size_t count; + + /* alloc data data */ + buffer = calloc(1, module->elf.file_size); + if (!buffer) + return -ENOMEM; + + ret = module_read_whole_elf(module, buffer, module->elf.file_size); + if (ret) + goto out; + + /* write out section data */ + count = fwrite(buffer, module->elf.file_size, 1, out_file); + if (count != 1) { + ret = file_error("can't write data", "");// TODO: image->out_file); + goto out; + } + +out: + free(buffer); + return ret; +} + +void module_print_zones(const struct module *module) +{ + fprintf(stdout, "\n\tTotals\tStart\t\tEnd\t\tSize"); + + fprintf(stdout, "\n\tTEXT\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->text.start, module->text.end, + module->text.end - module->text.start); + fprintf(stdout, "\tDATA\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->data.start, module->data.end, + module->data.end - module->data.start); + fprintf(stdout, "\tBSS\t0x%8.8x\t0x%8.8x\t0x%x\n\n", + module->bss.start, module->bss.end, + module->bss.end - module->bss.start); +} + +/** + * Print a list of valid program headers + * + * @param module pointer to a module structure + */ +static void module_print_programs(const struct module *module) +{ + const Elf32_Phdr *header; + int i; + + /* check each program */ + for (i = 0; i < module->elf.header.phnum; i++) { + header = &module->elf.programs[i]; + + if (header->filesz == 0 || header->type != PT_LOAD) + continue; + + fprintf(stdout, "%s program-%d:\n", module->elf.filename, i); + elf_program_header_print(header); + } +} + +/** + * Goes through program headers array to find the physical address based on the virtual address. + * + * @param elf elf file structure + * @param vaddr virtual address + * @return physical address when success, virtual address on error + */ +static uint32_t find_physical_address(struct elf_file *file, size_t vaddr) +{ + uint16_t i; + const Elf32_Phdr *prog; + + for (i = 0; i < file->programs_count; i++) { + prog = &file->programs[i]; + + if (prog->type != PT_LOAD) + continue; + + if (vaddr >= prog->vaddr && vaddr < (prog->vaddr + file->programs[i].memsz)) + return file->programs[i].paddr + vaddr - prog->vaddr; + } + + return vaddr; +} + +unsigned long uncache_to_cache(const struct memory_alias *alias, unsigned long address) +{ + return (address & ~alias->mask) | alias->cached; +} + +/** + * Checks if the section is placed in the rom memory address space + * + * @param config Memory configuration structure + * @param section section to be checked + * @return true if section is placed in rom memory address space + */ +static bool section_is_rom(const struct memory_config *config, + const struct elf_section_header *section) +{ + uint32_t sect_start, sect_end; + uint32_t rom_start, rom_end; + + sect_start = section->data.vaddr; + sect_end = sect_start + section->data.size; + + rom_start = config->zones[SOF_FW_BLK_TYPE_ROM].base; + rom_end = rom_start + config->zones[SOF_FW_BLK_TYPE_ROM].size; + + if (sect_end <= rom_start || sect_start >= rom_end) + return false; + if (sect_start >= rom_start && sect_end <= rom_end) + return true; + + fprintf(stderr, "Warning! Section %s partially overlaps with rom memory.\n", section->name); + return false; +} + +/** + * Initialize module_sections_info structure + * + * @param info Pointer to a module_sections_info structure + */ +static void sections_info_init(struct module_sections_info *info) +{ + memset(info, 0, sizeof(*info)); + + info->start = UINT32_MAX; +} + +/** + * Adds section to module_sections_info structure + * + * @param info Pointer to a module_sections_info structure + * @param address section address + * @param size section size + */ +static void sections_info_add(struct module_sections_info *info, const uint32_t address, + const size_t size) +{ + const uint32_t end = address + size; + + if (address < info->start) + info->start = address; + + if (end > info->end) + info->end = end; + + info->size += size; + info->count++; +} + +/** + * Calculates file size after adding all sections + * + * @param info Pointer to a module_sections_info structure + */ +static void sections_info_finalize(struct module_sections_info *info) +{ + info->file_size = info->end - info->start; + + /* file sizes round up to nearest page */ + info->file_size = (info->file_size + MAN_PAGE_SIZE - 1) & ~(MAN_PAGE_SIZE - 1); +} + +/** + * Checks the section header (type and flags) to determine the section type. + * + * @param section section header + * @return enum module_section_type + */ +static enum module_section_type get_section_type(const struct elf_section_header *section) +{ + switch (section->data.type) { + case SHT_INIT_ARRAY: + /* fall through */ + case SHT_PROGBITS: + /* text or data */ + return (section->data.flags & SHF_EXECINSTR) ? MST_TEXT : MST_DATA; + + case SHT_NOBITS: + /* bss or heap */ + return MST_BSS; + + case SHT_NOTE: + return MST_NOTE; + + default: + return MST_UNKNOWN; + } +} + +void module_parse_sections(struct module *module, const struct memory_config *mem_cfg, bool verbose) +{ + const uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); + uint16_t i; + + struct module_section *out_section = module->sections; + + fprintf(stdout, " Found %d sections, listing valid sections...\n", + module->elf.sections_count); + + fprintf(stdout, "\tNo\tLMA\t\tVMA\t\tEnd\t\tSize\tType\tName\n"); + + /* parse each section */ + for (i = 0; i < module->elf.sections_count; i++) { + const struct elf_section_header *sect = &module->elf.sections[i]; + struct module_sections_info *info = NULL; + + /* only write valid sections */ + if (!(sect->data.flags & valid)) + continue; + + /* Comment from fix_elf_addrs.py: + * The sof-derived linker scripts currently emit some zero-length sections + * at address zero. This is benign, and the linker is happy + * + * So we gleefully skip them. */ + if (sect->data.size == 0) + continue; + + out_section->header = sect; + out_section->size = sect->data.size; + out_section->type = get_section_type(sect); + out_section->rom = section_is_rom(mem_cfg, sect); + out_section->address = sect->data.vaddr; + out_section->load_address = find_physical_address(&module->elf, sect->data.vaddr); + + /* Don't convert ROM addresses, ROM sections aren't included in the output image */ + if (!out_section->rom) { + /* Walk the sections in the ELF file, changing the VMA/LMA of each uncached section + * to the equivalent address in the cached area of memory. */ + out_section->address = uncache_to_cache(&mem_cfg->alias, + out_section->address); + out_section->load_address = uncache_to_cache(&mem_cfg->alias, + out_section->load_address); + } + + fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t0x%8.8zx\t0x%zx", i, + out_section->load_address, out_section->address, + out_section->address + out_section->size, out_section->size); + + + switch (out_section->type) { + case MST_DATA: + info = &module->data; + fprintf(stdout, "\tDATA"); + break; + + case MST_TEXT: + info = &module->text; + fprintf(stdout, "\tTEXT"); + break; + + case MST_BSS: + info = &module->bss; + fprintf(stdout, "\tBSS"); + break; + + case MST_NOTE: + fprintf(stdout, "\tNOTE"); + break; + + default: + break; + } + + if (out_section->rom) { + /* ROM sections aren't included in the output image */ + fprintf(stdout, " ROM"); + } else { + /* Add section to list */ + if (info) { + sections_info_add(info, out_section->load_address, out_section->size); + out_section->next_section = info->first_section; + info->first_section = out_section; + } + } + + module->num_sections++; + out_section++; + + /* section name */ + fprintf(stdout, "\t%s\n", sect->name); + + if (verbose) { + fprintf(stdout, "%s section-%d:\n", module->elf.filename, i); + elf_section_header_print(sect); + } + } + + sections_info_finalize(&module->text); + sections_info_finalize(&module->data); + sections_info_finalize(&module->bss); + + size_t fw_size = module->data.size + module->text.size; + + fprintf(stdout, " module: input size %zd (0x%zx) bytes %d sections\n", + fw_size, fw_size, module->num_sections); + fprintf(stdout, " module: text %zu (0x%zx) bytes\n" + "\tdata %zu (0x%zx) bytes\n" + "\tbss %zu (0x%zx) bytes\n\n", + module->text.size, module->text.size, + module->data.size, module->data.size, + module->bss.size, module->bss.size); +} + +int module_open(struct module *module, const char *filename, const bool verbose) +{ + int ret; + + memset(module, 0, sizeof(*module)); + + ret = elf_open(&module->elf, filename); + if (ret) + return ret; + + if (verbose) { + fprintf(stdout, "%s elf header:\n", module->elf.filename); + elf_header_print(&module->elf); + module_print_programs(module); + } + + module->sections = calloc(module->elf.sections_count, sizeof(struct module_section)); + if (!module->sections) { + elf_free(&module->elf); + return -ENOMEM; + } + + sections_info_init(&module->data); + sections_info_init(&module->bss); + sections_info_init(&module->text); + + return 0; +} + +void module_close(struct module *module) +{ + elf_free(&module->elf); +} + +/** + * Checks if the contents of the section overlaps + * + * @param a first section to check + * @param b second section to check + * @return true if space of a sections overlap + */ +static bool section_check_overlap(const struct module_section *a, const struct module_section *b) +{ + uint32_t a_start = a->address; + uint32_t a_end = a_start + a->size; + + uint32_t b_start = b->address; + uint32_t b_end = b_start + b->size; + + /* is section start overlapping ? */ + return (a_start >= b_start && a_start < b_end) || + /* is section end overlapping ? */ + (a_end > b_start && a_end <= b_end); +} + +/** + * Checks if the contents of the modules overlaps + * + * @param mod first module to check + * @param mod2 second module to check + * @return error code + */ +static int module_check_overlap(const struct module *mod, const struct module *mod2) +{ + unsigned int i, j; + + /* for each section from first module */ + for (i = 0; i < mod->num_sections; i++) { + /* and for each section from second module */ + for (j = 0; j < mod2->num_sections; j++) { + const struct module_section *section = &mod->sections[i]; + const struct module_section *section2 = &mod2->sections[j]; + + /* don't compare section with itself */ + if (section == section2) + continue; + + /* check section overlapping */ + if (section_check_overlap(section, section2)) { + + fprintf(stderr, "error: Detected overlapping sections:\n"); + fprintf(stderr, "\t[0x%x : 0x%zx] %s from %s\n", section->address, + section->address + section->size - 1, + section->header->name, mod->elf.filename); + fprintf(stderr, "\t[0x%x : 0x%zx] %s from %s\n", section2->address, + section2->address + section2->size - 1, + section2->header->name, mod2->elf.filename); + + return -EINVAL; + } + } + } + + return 0; +} + +int modules_validate(const struct image *image) +{ + int i, j, ret; + + for (i = 0; i < image->num_modules; i++) { + for (j = 0; j < image->num_modules; j++) { + ret = module_check_overlap(&image->module[i].file, &image->module[j].file); + if (ret) + return ret; + } + } + + return 0; +} diff --git a/tools/rimage/src/pkcs1_5.c b/tools/rimage/src/pkcs1_5.c new file mode 100644 index 000000000000..de063ee03bec --- /dev/null +++ b/tools/rimage/src/pkcs1_5.c @@ -0,0 +1,970 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2017 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// Keyon Jie <yang.jie@linux.intel.com> + +#include <openssl/pem.h> +#include <openssl/ssl.h> +#include <openssl/rsa.h> +#include <openssl/evp.h> +#include <openssl/bio.h> +#include <openssl/sha.h> +#include <openssl/objects.h> +#include <openssl/bn.h> +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include <openssl/core_names.h> +#endif +#include <stdio.h> +#include <errno.h> +#include <string.h> + +#include <rimage/rimage.h> +#include <rimage/css.h> +#include <rimage/manifest.h> +#include <rimage/misc_utils.h> +#include <rimage/file_utils.h> +#include <rimage/hash.h> + +#define DEBUG_PKCS 0 + +enum manver { + V15 = 0, + V18 = 1, + V25 = 2, + VACE15 = 3 +}; + +static int rimage_read_key(EVP_PKEY **privkey, struct image *image) +{ + char path[256]; + FILE *fp; + + /* requires private key */ + if (!image->key_name) { + fprintf(stderr, "error: no private key set \n"); + return -EINVAL; + } + + /* create new key */ + *privkey = EVP_PKEY_new(); + if (!(*privkey)) + return -ENOMEM; + + /* load in RSA private key from PEM file */ + memset(path, 0, sizeof(path)); + strncpy(path, image->key_name, sizeof(path) - 1); + + fprintf(stdout, " %s: read key '%s'\n", __func__, path); + fp = fopen(path, "rb"); + if (!fp) + return file_error("unable to open file for reading", path); + + PEM_read_PrivateKey(fp, privkey, NULL, NULL); + fclose(fp); + + return 0; +} + +/* + * Here we have different implementations of following functionality + * (based on different openssl versions): + * + * rimage_check_key + * + * rimage_set_modexp + * + * rimage_sign + * + * rimage_verify + * + * rimage_get_key_size + * +*/ + +#if OPENSSL_VERSION_NUMBER < 0x30000000L +static int rimage_check_key(EVP_PKEY *privkey) +{ + RSA *priv_rsa = NULL; + + priv_rsa = EVP_PKEY_get1_RSA(privkey); + + return RSA_check_key(priv_rsa); +} +#else +static int rimage_check_key(EVP_PKEY *privkey) +{ + EVP_PKEY_CTX *ctx; + int ret = 0; + + ctx = EVP_PKEY_CTX_new(privkey, NULL /* no engine */); + if (!ctx) + return -EINVAL; + + ret = EVP_PKEY_private_check(ctx); + + EVP_PKEY_CTX_free(ctx); + + return ret; +} +#endif + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static void rimage_set_modexp(EVP_PKEY *privkey, unsigned char *mod, unsigned char *exp) +{ + RSA *priv_rsa = NULL; + const BIGNUM *n; + const BIGNUM *e; + + priv_rsa = EVP_PKEY_get1_RSA(privkey); + + n = priv_rsa->n; + e = priv_rsa->e; + + BN_bn2bin(n, mod); + BN_bn2bin(e, exp); +} +#elif OPENSSL_VERSION_NUMBER < 0x30000000L +static void rimage_set_modexp(EVP_PKEY *privkey, unsigned char *mod, unsigned char *exp) +{ + const BIGNUM *n; + const BIGNUM *e; + const BIGNUM *d; + RSA *priv_rsa = NULL; + + priv_rsa = EVP_PKEY_get1_RSA(privkey); + + RSA_get0_key(priv_rsa, &n, &e, &d); + + BN_bn2bin(n, mod); + BN_bn2bin(e, exp); +} +#else +static void rimage_set_modexp(EVP_PKEY *privkey, unsigned char *mod, unsigned char *exp) +{ + BIGNUM *n = NULL; + BIGNUM *e = NULL; + + EVP_PKEY_get_bn_param(privkey, OSSL_PKEY_PARAM_RSA_N, &n); + EVP_PKEY_get_bn_param(privkey, OSSL_PKEY_PARAM_RSA_E, &e); + + BN_bn2bin(n, mod); + BN_bn2bin(e, exp); +} +#endif + +#if OPENSSL_VERSION_NUMBER < 0x30000000L +static int rimage_sign(EVP_PKEY *privkey, enum manver ver, struct hash_context *digest, + unsigned char *signature) +{ + unsigned char sig[MAN_RSA_SIGNATURE_LEN_2_5]; + unsigned int siglen = MAN_RSA_SIGNATURE_LEN; + RSA *priv_rsa = NULL; + int ret; + + priv_rsa = EVP_PKEY_get1_RSA(privkey); + + switch (ver) { + case V15: + /* fallthrough */ + case V18: + ret = RSA_sign(NID_sha256, digest->digest, digest->digest_length, + signature, &siglen, priv_rsa); + break; + case V25: + /* fallthrough */ + case VACE15: + ret = RSA_padding_add_PKCS1_PSS(priv_rsa, sig, digest->digest, digest->algo, + /* salt length */ 32); + if (ret > 0) + ret = RSA_private_encrypt(RSA_size(priv_rsa), sig, signature, priv_rsa, + RSA_NO_PADDING); + break; + default: + return -EINVAL; + } + + return ret; +} +#else +static int rimage_sign(EVP_PKEY *privkey, enum manver ver, + struct hash_context *digest, unsigned char *signature) +{ + EVP_PKEY_CTX *ctx = NULL; + size_t siglen = MAN_RSA_SIGNATURE_LEN; + int ret; + + ctx = EVP_PKEY_CTX_new(privkey, NULL /* no engine */); + if (!ctx) + return -ENOMEM; + + ret = EVP_PKEY_sign_init(ctx); + if (ret <= 0) + goto out; + + if (ver == V25 || ver == VACE15) { + ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING); + if (ret <= 0) { + fprintf(stderr, "error: failed to set rsa padding\n"); + goto out; + } + + ret = EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, 32); + if (ret <= 0) { + fprintf(stderr, "error: failed to set saltlen\n"); + goto out; + } + + siglen = MAN_RSA_SIGNATURE_LEN_2_5; + } + + ret = EVP_PKEY_CTX_set_signature_md(ctx, digest->algo); + if (ret <= 0) { + fprintf(stderr, "error: failed to set signature algorithm\n"); + goto out; + } + + ret = EVP_PKEY_sign(ctx, signature, &siglen, digest->digest, digest->digest_length); + if (ret <= 0) { + fprintf(stderr, "error: failed to sign manifest\n"); + goto out; + } + +out: + EVP_PKEY_CTX_free(ctx); + + return ret; +} +#endif + +#if OPENSSL_VERSION_NUMBER < 0x30000000L +static int rimage_verify(EVP_PKEY *privkey, enum manver ver, struct hash_context *digest, + unsigned char *signature) +{ + unsigned char sig[MAN_RSA_SIGNATURE_LEN_2_5]; + unsigned int siglen = MAN_RSA_SIGNATURE_LEN; + RSA *priv_rsa = NULL; + char err_buf[256]; + int ret; + + priv_rsa = EVP_PKEY_get1_RSA(privkey); + + switch (ver) { + case V15: + /* fallthrough */ + case V18: + ret = RSA_verify(NID_sha256, digest->digest, digest->digest_length, signature, + siglen, priv_rsa); + + if (ret <= 0) { + ERR_error_string(ERR_get_error(), err_buf); + fprintf(stderr, "error: verify %s\n", err_buf); + } + break; + case V25: + /* fallthrough */ + case VACE15: + /* decrypt signature */ + ret = RSA_public_decrypt(RSA_size(priv_rsa), signature, sig, priv_rsa, + RSA_NO_PADDING); + if (ret <= 0) { + ERR_error_string(ERR_get_error(), err_buf); + fprintf(stderr, "error: verify decrypt %s\n", err_buf); + return ret; + } + + ret = RSA_verify_PKCS1_PSS(priv_rsa, digest->digest, digest->algo, sig, 32); + if (ret <= 0) { + ERR_error_string(ERR_get_error(), err_buf); + fprintf(stderr, "error: verify %s\n", err_buf); + } + break; + default: + return -EINVAL; + } + + return ret; +} +#else +static int rimage_verify(EVP_PKEY *privkey, enum manver ver,struct hash_context *digest, + unsigned char *signature) +{ + EVP_PKEY_CTX *ctx = NULL; + size_t siglen = MAN_RSA_SIGNATURE_LEN; + char err_buf[256]; + int ret; + + ctx = EVP_PKEY_CTX_new(privkey, NULL /* no engine */); + if (!ctx) + return -ENOMEM; + + ret = EVP_PKEY_verify_init(ctx); + if (ret <= 0) + goto out; + + ret = EVP_PKEY_CTX_set_signature_md(ctx, digest->algo); + if (ret <= 0) { + ERR_error_string(ERR_get_error(), err_buf); + fprintf(stderr, "error: set signature %s\n", err_buf); + goto out; + } + + switch (ver) { + case V15: /* fallthrough */ + case V18: + break; + + case V25: /* fallthrough */ + case VACE15: + ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING); + if (ret <= 0) + goto out; + + ret = EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, 32); + if (ret <= 0) + goto out; + + siglen = MAN_RSA_SIGNATURE_LEN_2_5; + break; + default: + return -EINVAL; + } + + ret = EVP_PKEY_verify(ctx, signature, siglen, digest->digest, digest->digest_length); + if (ret <= 0) { + ERR_error_string(ERR_get_error(), err_buf); + fprintf(stderr, "error: verify %s\n", err_buf); + } + +out: + EVP_PKEY_CTX_free(ctx); + + return ret; +} +#endif + +#if OPENSSL_VERSION_NUMBER < 0x30000000L +static int rimage_get_key_size(EVP_PKEY *privkey) +{ + RSA *priv_rsa = NULL; + int key_length; + + priv_rsa = EVP_PKEY_get1_RSA(privkey); + key_length = RSA_size(priv_rsa); + + RSA_free(priv_rsa); + + return key_length; +} +#else +static int rimage_get_key_size(EVP_PKEY *privkey) +{ + return EVP_PKEY_get_size(privkey); +} +#endif + +/* + * RSA signature of manifest. The signature is an PKCS + * #1-v1_5 of the entire manifest structure, including all + * extensions, and excluding the last 3 fields of the + * manifest header (Public Key, Exponent and Signature). + */ + +int pkcs_v1_5_sign_man_v1_5(struct image *image, + struct fw_image_manifest_v1_5 *man, + void *ptr1, unsigned int size1) +{ + EVP_PKEY *privkey; + struct hash_context digest; + unsigned char mod[MAN_RSA_KEY_MODULUS_LEN]; + int ret = -EINVAL, i; + +#if DEBUG_PKCS + fprintf(stdout, "offsets 0x%lx size 0x%x\n", + ptr1 - (void *)man, size1); +#endif + + ret = rimage_read_key(&privkey, image); + if (ret < 0) + return ret; + + if (rimage_check_key(privkey) > 0) { + fprintf(stdout, " pkcs: RSA private key is valid.\n"); + } else { + fprintf(stderr, "error: validating RSA private key.\n"); + return -EINVAL; + } + + /* calculate the digest */ + hash_sha256_init(&digest); + hash_update(&digest, ptr1, size1); + ret = hash_finalize(&digest); + if (ret) + goto err; + + fprintf(stdout, " pkcs: digest for manifest is "); + hash_print(&digest); + + /* sign the manifest */ + ret = rimage_sign(privkey, V15, &digest, (unsigned char *)man->css_header.signature); + if (ret <= 0) { + fprintf(stderr, "error: failed to sign manifest\n"); + goto err; + } + + /* copy public key modulus and exponent to manifest */ + rimage_set_modexp(privkey, mod, (unsigned char *)man->css_header.exponent); + + /* modulus is reveresd */ + for (i = 0; i < MAN_RSA_KEY_MODULUS_LEN; i++) + man->css_header.modulus[i] + = mod[MAN_RSA_KEY_MODULUS_LEN - (1 + i)]; + + /* signature is reveresd, swap it */ + bytes_swap(man->css_header.signature, + sizeof(man->css_header.signature)); + +err: + EVP_PKEY_free(privkey); + return ret; +} + +/* + * RSA signature of manifest. The signature is an PKCS + * #1-v1_5 of the entire manifest structure, including all + * extensions, and excluding the last 3 fields of the + * manifest header (Public Key, Exponent and Signature). + */ + +int pkcs_v1_5_sign_man_v1_8(struct image *image, + struct fw_image_manifest_v1_8 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2) +{ + EVP_PKEY *privkey; + struct hash_context digest; + unsigned char mod[MAN_RSA_KEY_MODULUS_LEN]; + int ret = -EINVAL, i; + +#if DEBUG_PKCS + fprintf(stdout, "offsets 0x%lx size 0x%x offset 0x%lx size 0x%x\n", + ptr1 - (void *)man, size1, ptr2 - (void *)man, size2); +#endif + + ret = rimage_read_key(&privkey, image); + if (ret < 0) + return ret; + + /* validate RSA private key */ + if (rimage_check_key(privkey) > 0) { + fprintf(stdout, " pkcs: RSA private key is valid.\n"); + } else { + fprintf(stderr, "error: validating RSA private key.\n"); + return -EINVAL; + } + + /* calculate the digest */ + hash_sha256_init(&digest); + hash_update(&digest, ptr1, size1); + hash_update(&digest, ptr2, size2); + ret = hash_finalize(&digest); + if (ret) + goto err; + + fprintf(stdout, " pkcs: digest for manifest is "); + hash_print(&digest); + + /* sign the manifest */ + ret = rimage_sign(privkey, V18, &digest, (unsigned char *)man->css.signature); + if (ret <= 0) { + fprintf(stderr, "error: failed to sign manifest\n"); + goto err; + } + + /* copy public key modulus and exponent to manifest */ + rimage_set_modexp(privkey, mod, (unsigned char *)man->css.exponent); + + /* modulus is reveresd */ + for (i = 0; i < MAN_RSA_KEY_MODULUS_LEN; i++) + man->css.modulus[i] = mod[MAN_RSA_KEY_MODULUS_LEN - (1 + i)]; + + /* signature is reveresd, swap it */ + bytes_swap(man->css.signature, sizeof(man->css.signature)); + +err: + EVP_PKEY_free(privkey); + return ret; +} + +int pkcs_v1_5_sign_man_v2_5(struct image *image, + struct fw_image_manifest_v2_5 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2) +{ + EVP_PKEY *privkey; + struct hash_context digest; + unsigned char mod[MAN_RSA_KEY_MODULUS_LEN_2_5]; + int ret = -EINVAL, i; + +#if DEBUG_PKCS + fprintf(stdout, "offsets 0x%lx size 0x%x offset 0x%lx size 0x%x\n", + ptr1 - (void *)man, size1, ptr2 - (void *)man, size2); +#endif + + ret = rimage_read_key(&privkey, image); + if (ret < 0) + return ret; + + /* validate RSA private key */ + if (rimage_check_key(privkey) > 0) { + fprintf(stdout, " pkcs: RSA private key is valid.\n"); + } else { + fprintf(stderr, "error: validating RSA private key.\n"); + return -EINVAL; + } + + /* calculate the digest - SHA384 on CAVS2_5+ */ + hash_sha384_init(&digest); + hash_update(&digest, ptr1, size1); + hash_update(&digest, ptr2, size2); + ret = hash_finalize(&digest); + if (ret) + goto err; + + fprintf(stdout, " pkcs: digest for manifest is "); + hash_print(&digest); + + /* sign the manifest */ + ret = rimage_sign(privkey, V25, &digest, (unsigned char *)man->css.signature); + if (ret <= 0) { + fprintf(stderr, "error: failed to sign manifest\n"); + goto err; + } + + /* copy public key modulus and exponent to manifest */ + rimage_set_modexp(privkey, mod, (unsigned char *)man->css.exponent); + + /* modulus is reversed */ + for (i = 0; i < MAN_RSA_KEY_MODULUS_LEN_2_5; i++) + man->css.modulus[i] = mod[MAN_RSA_KEY_MODULUS_LEN_2_5 - (1 + i)]; + + /* signature is reversed, swap it */ + bytes_swap(man->css.signature, sizeof(man->css.signature)); + +err: + EVP_PKEY_free(privkey); + return ret; +} + +int pkcs_v1_5_sign_man_ace_v1_5(struct image *image, + struct fw_image_manifest_ace_v1_5 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2) +{ + EVP_PKEY *privkey; + struct hash_context digest; + unsigned char mod[MAN_RSA_KEY_MODULUS_LEN_2_5]; + int ret = -EINVAL, i; + +#if DEBUG_PKCS + fprintf(stdout, "offsets 0x%lx size 0x%x offset 0x%lx size 0x%x\n", + ptr1 - (void *)man, size1, ptr2 - (void *)man, size2); +#endif + + ret = rimage_read_key(&privkey, image); + if (ret < 0) + return ret; + + /* validate RSA private key */ + if (rimage_check_key(privkey) > 0) { + fprintf(stdout, " pkcs: RSA private key is valid.\n"); + } else { + fprintf(stderr, "error: validating RSA private key.\n"); + return -EINVAL; + } + + /* calculate the digest - SHA384 on CAVS2_5+ */ + hash_sha384_init(&digest); + hash_update(&digest, ptr1, size1); + hash_update(&digest, ptr2, size2); + ret = hash_finalize(&digest); + if (ret) + goto err; + + fprintf(stdout, " pkcs: digest for manifest is "); + hash_print(&digest); + + /* sign the manifest */ + ret = rimage_sign(privkey, VACE15, &digest, (unsigned char *)man->css.signature); + if (ret <= 0) { + fprintf(stderr, "error: failed to sign manifest\n"); + goto err; + } + + /* copy public key modulus and exponent to manifest */ + rimage_set_modexp(privkey, mod, (unsigned char *)man->css.exponent); + + /* modulus is reversed */ + for (i = 0; i < MAN_RSA_KEY_MODULUS_LEN_2_5; i++) + man->css.modulus[i] = mod[MAN_RSA_KEY_MODULUS_LEN_2_5 - (1 + i)]; + + /* signature is reversed, swap it */ + bytes_swap(man->css.signature, sizeof(man->css.signature)); + +err: + EVP_PKEY_free(privkey); + return ret; +} + +int ri_manifest_sign_v1_5(struct image *image) +{ + struct fw_image_manifest_v1_5 *man = image->fw_image; + + /* excluding the manifest header */ + char *const data1 = (char *)man + sizeof(struct fw_image_manifest_v1_5); + unsigned const size1 = image->image_end - sizeof(*man); + + return pkcs_v1_5_sign_man_v1_5(image, man, data1, size1); +} + +int ri_manifest_sign_v1_8(struct image *image) +{ + struct fw_image_manifest_v1_8 *man = image->fw_image; + + char *const data1 = (char *)man + MAN_CSS_HDR_OFFSET; + unsigned const size1 = + sizeof(struct css_header_v1_8) - + (MAN_RSA_KEY_MODULUS_LEN + MAN_RSA_KEY_EXPONENT_LEN + + MAN_RSA_SIGNATURE_LEN); + + char *const data2 = (char *)man + MAN_SIG_PKG_OFFSET_V1_8; + unsigned const size2 = + (man->css.size - man->css.header_len) * sizeof(uint32_t); + + return pkcs_v1_5_sign_man_v1_8(image, man, data1, size1, data2, size2); +} + +int ri_manifest_sign_v2_5(struct image *image) +{ + struct fw_image_manifest_v2_5 *man = image->fw_image; + + char *const data1 = (char *)man + MAN_CSS_HDR_OFFSET_2_5; + unsigned const size1 = + sizeof(struct css_header_v2_5) - + (MAN_RSA_KEY_MODULUS_LEN_2_5 + MAN_RSA_KEY_EXPONENT_LEN + + MAN_RSA_SIGNATURE_LEN_2_5); + + char *const data2 = (char *)man + MAN_SIG_PKG_OFFSET_V2_5; + unsigned const size2 = + (man->css.size - man->css.header_len) * sizeof(uint32_t); + + return pkcs_v1_5_sign_man_v2_5(image, man, data1, size1, data2, size2); +} + +int ri_manifest_sign_ace_v1_5(struct image *image) +{ + struct fw_image_manifest_ace_v1_5 *man = image->fw_image; + + char *const data1 = (char *)man + MAN_CSS_HDR_OFFSET_2_5; + unsigned const size1 = + sizeof(struct css_header_v2_5) - + (MAN_RSA_KEY_MODULUS_LEN_2_5 + MAN_RSA_KEY_EXPONENT_LEN + + MAN_RSA_SIGNATURE_LEN_2_5); + + char *const data2 = (char *)man + MAN_SIG_PKG_OFFSET_V2_5; + unsigned const size2 = + (man->css.size - man->css.header_len) * sizeof(uint32_t); + + return pkcs_v1_5_sign_man_ace_v1_5(image, man, data1, size1, data2, size2); +} + +/* + * RSA verify of manifest. The signature is an PKCS + * #1-v1_5 of the entire manifest structure, including all + * extensions, and excluding the last 3 fields of the + * manifest header (Public Key, Exponent and Signature). + */ + +int pkcs_v1_5_verify_man_v1_5(struct image *image, + struct fw_image_manifest_v1_5 *man, + void *ptr1, unsigned int size1) +{ + EVP_PKEY *privkey; + struct hash_context digest; + int ret = -EINVAL; + +#if DEBUG_PKCS + fprintf(stdout, "offsets 0x%lx size 0x%x\n", + ptr1 - (void *)man, size1); +#endif + + ret = rimage_read_key(&privkey, image); + if (ret < 0) + return ret; + + /* validate RSA private key */ + if (rimage_check_key(privkey) > 0) { + fprintf(stdout, " pkcs: RSA private key is valid.\n"); + } else { + fprintf(stderr, "error: validating RSA private key.\n"); + return -EINVAL; + } + + /* calculate the digest */ + hash_sha256_init(&digest); + hash_update(&digest, ptr1, size1); + ret = hash_finalize(&digest); + if (ret) + goto err; + + fprintf(stdout, " pkcs: digest for manifest is "); + hash_print(&digest); + + /* signature is reversed, swap it */ + bytes_swap(man->css_header.signature, + sizeof(man->css_header.signature)); + + /* verify */ + ret = rimage_verify(privkey, V15, &digest, (unsigned char *)man->css_header.signature); + if (ret <= 0) + fprintf(stderr, "error: failed to verify manifest\n"); + else + fprintf(stdout, "pkcs: signature is valid !\n"); + +err: + EVP_PKEY_free(privkey); + return ret; +} + +/* + * RSA verify of manifest. The signature is an PKCS + * #1-v1_5 of the entire manifest structure, including all + * extensions, and excluding the last 3 fields of the + * manifest header (Public Key, Exponent and Signature). + */ + +int pkcs_v1_5_verify_man_v1_8(struct image *image, + struct fw_image_manifest_v1_8 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2) +{ + EVP_PKEY *privkey; + struct hash_context digest; + int ret = -EINVAL; + +#if DEBUG_PKCS + fprintf(stdout, "offsets 0x%lx size 0x%x offset 0x%lx size 0x%x\n", + ptr1 - (void *)man, size1, ptr2 - (void *)man, size2); +#endif + + ret = rimage_read_key(&privkey, image); + if (ret < 0) + return ret; + + /* validate RSA private key */ + if (rimage_check_key(privkey) > 0) { + fprintf(stdout, " pkcs: RSA private key is valid.\n"); + } else { + fprintf(stderr, "error: validating RSA private key.\n"); + return -EINVAL; + } + + /* calculate the digest */ + hash_sha256_init(&digest); + hash_update(&digest, ptr1, size1); + hash_update(&digest, ptr2, size2); + ret = hash_finalize(&digest); + if (ret) + goto err; + + fprintf(stdout, " pkcs: digest for manifest is "); + hash_print(&digest); + + /* signature is reveresd, swap it */ + bytes_swap(man->css.signature, sizeof(man->css.signature)); + + /* verify */ + ret = rimage_verify(privkey, V18, &digest, (unsigned char *)man->css.signature); + if (ret <= 0) + fprintf(stderr, "error: failed to verify manifest\n"); + else + fprintf(stdout, "pkcs: signature is valid !\n"); + +err: + EVP_PKEY_free(privkey); + return ret; +} + +/* + * RSA signature of manifest. The signature is an RSA PSS + * of the entire manifest structure, including all + * extensions, and excluding the last 3 fields of the + * manifest header (Public Key, Exponent and Signature). + */ + +int pkcs_v1_5_verify_man_v2_5(struct image *image, + struct fw_image_manifest_v2_5 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2) +{ + EVP_PKEY *privkey; + struct hash_context digest; + int ret = -EINVAL; + +#if DEBUG_PKCS + fprintf(stdout, "offsets 0x%lx size 0x%x offset 0x%lx size 0x%x\n", + ptr1 - (void *)man, size1, ptr2 - (void *)man, size2); +#endif + + ret = rimage_read_key(&privkey, image); + if (ret < 0) + return ret; + + /* validate RSA private key */ + if (rimage_check_key(privkey) > 0) { + fprintf(stdout, " pkcs: RSA private key is valid.\n"); + } else { + fprintf(stderr, "error: validating RSA private key.\n"); + return -EINVAL; + } + + /* calculate the digest - SHA384 on CAVS2_5+ */ + hash_sha384_init(&digest); + hash_update(&digest, ptr1, size1); + hash_update(&digest, ptr2, size2); + ret = hash_finalize(&digest); + if (ret) + goto err; + + fprintf(stdout, " pkcs: digest for manifest is "); + hash_print(&digest); + + /* signature is reversed, swap it */ + bytes_swap(man->css.signature, sizeof(man->css.signature)); + + /* verify */ + ret = rimage_verify(privkey, V25, &digest, (unsigned char *)man->css.signature); + + if (ret <= 0) + fprintf(stderr, "error: failed to verify manifest\n"); + else + fprintf(stdout, "pkcs: signature is valid !\n"); + +err: + EVP_PKEY_free(privkey); + return ret; +} + +int pkcs_v1_5_verify_man_ace_v1_5(struct image *image, + struct fw_image_manifest_ace_v1_5 *man, + void *ptr1, unsigned int size1, void *ptr2, + unsigned int size2) +{ + EVP_PKEY *privkey; + struct hash_context digest; + int ret = -EINVAL; + +#if DEBUG_PKCS + fprintf(stdout, "offsets 0x%lx size 0x%x offset 0x%lx size 0x%x\n", + ptr1 - (void *)man, size1, ptr2 - (void *)man, size2); +#endif + + ret = rimage_read_key(&privkey, image); + if (ret < 0) + return ret; + + /* validate RSA private key */ + if (rimage_check_key(privkey) > 0) { + fprintf(stdout, " pkcs: RSA private key is valid.\n"); + } else { + fprintf(stderr, "error: validating RSA private key.\n"); + return -EINVAL; + } + + /* calculate the digest - SHA384 on CAVS2_5+ */ + hash_sha384_init(&digest); + hash_update(&digest, ptr1, size1); + hash_update(&digest, ptr2, size2); + ret = hash_finalize(&digest); + if (ret) + goto err; + + fprintf(stdout, " pkcs: digest for manifest is "); + hash_print(&digest); + + /* signature is reversed, swap it */ + bytes_swap(man->css.signature, sizeof(man->css.signature)); + + /* verify */ + ret = rimage_verify(privkey, VACE15, &digest, (unsigned char *)man->css.signature); + if (ret <= 0) + fprintf(stderr, "error: failed to verify manifest\n"); + else + fprintf(stdout, "pkcs: signature is valid !\n"); + +err: + EVP_PKEY_free(privkey); + return ret; +} + +int ri_manifest_verify_v1_5(struct image *image) +{ + struct fw_image_manifest_v1_5 *man = image->fw_image; + + char *const data1 = (char *)man + MAN_CSS_MAN_SIZE_V1_5; + unsigned const size1 = image->image_end - sizeof(*man); + + return pkcs_v1_5_verify_man_v1_5(image, man, data1, size1); +} + +int ri_manifest_verify_v1_8(struct image *image) +{ + struct fw_image_manifest_v1_8 *man = image->fw_image; + + char *const data1 = (char *)man + MAN_CSS_HDR_OFFSET; + unsigned const size1 = + sizeof(struct css_header_v1_8) - + (MAN_RSA_KEY_MODULUS_LEN + MAN_RSA_KEY_EXPONENT_LEN + + MAN_RSA_SIGNATURE_LEN); + + char *const data2 = (char *)man + MAN_SIG_PKG_OFFSET_V1_8; + unsigned const size2 = + (man->css.size - man->css.header_len) * sizeof(uint32_t); + + return pkcs_v1_5_verify_man_v1_8(image, man, data1, size1, data2, size2); +} + +int ri_manifest_verify_v2_5(struct image *image) +{ + struct fw_image_manifest_v2_5 *man = image->fw_image; + + char *const data1 = (char *)man + MAN_CSS_HDR_OFFSET_2_5; + unsigned const size1 = + sizeof(struct css_header_v2_5) - + (MAN_RSA_KEY_MODULUS_LEN_2_5 + MAN_RSA_KEY_EXPONENT_LEN + + MAN_RSA_SIGNATURE_LEN_2_5); + + char *const data2 = (char *)man + MAN_SIG_PKG_OFFSET_V2_5; + unsigned const size2 = + (man->css.size - man->css.header_len) * sizeof(uint32_t); + + return pkcs_v1_5_verify_man_v2_5(image, man, data1, size1, data2, size2); +} + +int get_key_size(struct image *image) +{ + EVP_PKEY *privkey; + int key_len; + int ret; + + ret = rimage_read_key(&privkey, image); + if (ret < 0) + return ret; + + key_len = rimage_get_key_size(privkey); + + EVP_PKEY_free(privkey); + + return key_len; +} diff --git a/tools/rimage/src/plat_auth.c b/tools/rimage/src/plat_auth.c new file mode 100644 index 000000000000..321d1712d0e4 --- /dev/null +++ b/tools/rimage/src/plat_auth.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2017 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// Keyon Jie <yang.jie@linux.intel.com> + +#include <rimage/rimage.h> +#include <rimage/manifest.h> +#include <rimage/plat_auth.h> + +void ri_adsp_meta_data_create_v1_8(struct image *image, int meta_start_offset, + int meta_end_offset) +{ + struct sof_man_adsp_meta_file_ext_v1_8 *meta = + image->fw_image + meta_start_offset; + + fprintf(stdout, " meta: completing ADSP manifest\n"); + + meta->comp_desc[0].limit_offset = MAN_DESC_OFFSET_V1_8 + + image->image_end - meta_end_offset; + + fprintf(stdout, " meta: limit is 0x%x\n", + meta->comp_desc[0].limit_offset); + /* now hash the AdspFwBinaryDesc -> EOF */ +} + +void ri_adsp_meta_data_create_v2_5(struct image *image, int meta_start_offset, + int meta_end_offset) +{ + struct sof_man_adsp_meta_file_ext_v2_5 *meta = + image->fw_image + meta_start_offset; + + fprintf(stdout, " meta: completing ADSP manifest\n"); + + meta->comp_desc[0].limit_offset = MAN_DESC_OFFSET_V1_8 + + image->image_end - meta_end_offset; + + fprintf(stdout, " meta: limit is 0x%x\n", + meta->comp_desc[0].limit_offset); + /* now hash the AdspFwBinaryDesc -> EOF */ +} + +void ri_plat_ext_data_create(struct image *image) +{ + struct partition_info_ext *part = image->fw_image + + MAN_PART_INFO_OFFSET_V1_8; + struct sof_man_adsp_meta_file_ext_v1_8 *meta = + image->fw_image + MAN_META_EXT_OFFSET_V1_8; + struct sof_man_fw_desc *desc = image->fw_image + MAN_DESC_OFFSET_V1_8; + + fprintf(stdout, " auth: completing authentication manifest\n"); + + part->length = meta->comp_desc[0].limit_offset - MAN_DESC_OFFSET_V1_8; + part->length += MAN_PAGE_SIZE - (part->length % MAN_PAGE_SIZE); + + /* do this here atm */ + desc->header.preload_page_count = part->length / MAN_PAGE_SIZE; +} + +void ri_plat_ext_data_create_v2_5(struct image *image) +{ + struct sof_man_adsp_meta_file_ext_v2_5 *meta = + image->fw_image + MAN_META_EXT_OFFSET_V2_5; + struct sof_man_fw_desc *desc = image->fw_image + MAN_DESC_OFFSET_V1_8; + struct info_ext_0x16 *ext = image->fw_image + MAN_PART_INFO_OFFSET_V2_5; + uint32_t size; + + fprintf(stdout, " auth: completing authentication manifest\n"); + + size = meta->comp_desc[0].limit_offset - MAN_DESC_OFFSET_V1_8; + size += MAN_PAGE_SIZE - (size % MAN_PAGE_SIZE); + + /* do this here atm */ + desc->header.preload_page_count = size / MAN_PAGE_SIZE; + ext->size = image->image_end; +} + +void ri_plat_ext_data_create_ace_v1_5(struct image *image) +{ + struct sof_man_adsp_meta_file_ext_v2_5 *meta = + image->fw_image + MAN_META_EXT_OFFSET_ACE_V1_5; + struct sof_man_fw_desc *desc = image->fw_image + MAN_DESC_OFFSET_V1_8; + struct info_ext_0x16 *ext = image->fw_image + MAN_PART_INFO_OFFSET_ACE_V1_5; + uint32_t size; + + fprintf(stdout, " auth: completing authentication manifest\n"); + + size = meta->comp_desc[0].limit_offset - MAN_DESC_OFFSET_V1_8; + size += MAN_PAGE_SIZE - (size % MAN_PAGE_SIZE); + + desc->header.preload_page_count = size / MAN_PAGE_SIZE; + ext->size = image->image_end; +} diff --git a/tools/rimage/src/rimage.c b/tools/rimage/src/rimage.c new file mode 100644 index 000000000000..735075c130cc --- /dev/null +++ b/tools/rimage/src/rimage.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2015 Intel Corporation. All rights reserved. + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdbool.h> + +#include <rimage/adsp_config.h> +#include <rimage/ext_manifest_gen.h> +#include <rimage/rimage.h> +#include <rimage/manifest.h> +#include <rimage/file_utils.h> + + +static void usage(char *name) +{ + fprintf(stdout, "%s:\t -c adsp_desc -o outfile -k [key] ELF files\n", + name); + fprintf(stdout, "%s:\t -c adsp_desc -y infile -k [key]\n", + name); + fprintf(stdout, "\t -v enable verbose output\n"); + fprintf(stdout, "\t -r enable relocatable ELF files\n"); + fprintf(stdout, "\t -s MEU signing offset, disables rimage signing\n"); + fprintf(stdout, "\t -i set IMR type\n"); + fprintf(stdout, "\t -f firmware version = major.minor.micro\n"); + fprintf(stdout, "\t -b build version\n"); + fprintf(stdout, "\t -e build extended manifest\n"); + fprintf(stdout, "\t -l build loadable modules image (don't treat the first module as a bootloader)\n"); + fprintf(stdout, "\t -y verify signed file\n"); + fprintf(stdout, "\t -q resign binary\n"); + fprintf(stdout, "\t -p set PV bit\n"); +} + +int main(int argc, char *argv[]) +{ + struct image image; + struct adsp *heap_adsp; + const char *adsp_config = NULL; + int opt, ret, i, first_non_opt; + int use_ext_man = 0; + unsigned int pv_bit = 0; + bool imr_type_override = false; + + memset(&image, 0, sizeof(image)); + + image.imr_type = MAN_DEFAULT_IMR_TYPE; + + while ((opt = getopt(argc, argv, "ho:va:s:k:ri:f:b:ec:y:q:pl")) != -1) { + switch (opt) { + case 'o': + image.out_file = optarg; + break; + case 'v': + image.verbose = 1; + break; + case 's': + image.meu_offset = atoi(optarg); + break; + case 'a': + image.abi = atoi(optarg); + break; + case 'k': + image.key_name = optarg; + break; + case 'r': + image.reloc = 1; + break; + case 'i': + image.imr_type = atoi(optarg); + imr_type_override = true; + break; + case 'f': + image.fw_ver_string = optarg; + break; + case 'b': + image.fw_ver_build_string = optarg; + break; + case 'e': + use_ext_man = 1; + break; + case 'c': + adsp_config = optarg; + break; + case 'y': + image.verify_file = optarg; + break; + case 'h': + usage(argv[0]); + return 0; + case 'q': + image.in_file = optarg; + break; + case 'p': + pv_bit = 1; + break; + case 'l': + image.loadable_module = true; + break; + default: + /* getopt's default error message is good enough */ + return 1; + } + } + + first_non_opt = optind; + + /* we must have config */ + if (!adsp_config) { + usage(argv[0]); + fprintf(stderr, "error: must have adsp desc\n"); + return -EINVAL; + } + + /* requires private key */ + if (!image.key_name) { + fprintf(stderr, "error: requires private key\n"); + return -EINVAL; + } + + /* make sure we have an outfile if not verifying */ + if ((!image.out_file && !image.verify_file)) { + usage(argv[0]); + return -EINVAL; + } + + /* firmware version: major.minor.micro */ + if (image.fw_ver_string) { + ret = sscanf(image.fw_ver_string, "%hu.%hu.%hu", + &image.fw_ver_major, + &image.fw_ver_minor, + &image.fw_ver_micro); + + if (ret != 3) { + fprintf(stderr, + "error: cannot parse firmware version major.minor.micro\n"); + return -EINVAL; + } + } + + /* firmware build id */ + if (image.fw_ver_build_string) { + ret = sscanf(image.fw_ver_build_string, "%hu", + &image.fw_ver_build); + + if (ret != 1) { + fprintf(stderr, + "error: cannot parse build version\n"); + return -EINVAL; + } + } + /* find machine */ + heap_adsp = malloc(sizeof(struct adsp)); + if (!heap_adsp) { + fprintf(stderr, "error: memory allocation for adsp struct failed\n"); + return -ENOMEM; + } + image.adsp = heap_adsp; + memset(heap_adsp, 0, sizeof(*heap_adsp)); + ret = adsp_parse_config(adsp_config, &image); + if (ret < 0) + goto out; + + /* verify mode ? */ + if (image.verify_file) { + ret = verify_image(&image); + goto out; + } + + if (image.in_file) { + fprintf(stdout, "going to re-sign\n"); + ret = resign_image(&image); + goto out; + } + + /* set IMR Type and the PV bit in found machine definition */ + if (image.adsp->man_v1_8) { + if (imr_type_override) + image.adsp->man_v1_8->adsp_file_ext.imr_type = image.imr_type; + image.adsp->man_v1_8->css.reserved0 = pv_bit; + } + + if (image.adsp->man_v2_5) { + if (imr_type_override) + image.adsp->man_v2_5->adsp_file_ext.imr_type = image.imr_type; + image.adsp->man_v2_5->css.reserved0 = pv_bit; + } + + if (image.adsp->man_ace_v1_5) { + if (imr_type_override) + image.adsp->man_ace_v1_5->adsp_file_ext.imr_type = image.imr_type; + image.adsp->man_ace_v1_5->css.reserved0 = pv_bit; + } + + /* parse input ELF files */ + image.num_modules = argc - first_non_opt; + + if (image.num_modules <= 0) { + fprintf(stderr, + "error: requires at least one ELF input module\n"); + ret = -EINVAL; + goto out; + } + + /* Some platforms dont have modules configuration in toml file */ + if (image.adsp->modules && image.num_modules > image.adsp->modules->mod_man_count) { + fprintf(stderr, "error: Each ELF input module requires entry in toml file.\n"); + ret = -EINVAL; + goto out; + } + + /* getopt reorders argv[] */ + for (opt = first_non_opt; opt < argc; opt++) { + i = opt - first_non_opt; + fprintf(stdout, "\nModule Reading %s\n", argv[opt]); + ret = module_open(&image.module[i].file, argv[opt], image.verbose); + if (ret < 0) + goto out; + + module_parse_sections(&image.module[i].file, &image.adsp->mem, image.verbose); + + /* When there is more than one module, then first one is bootloader. + * Does not apply to building a image of a loadable module. */ + image.module[i].is_bootloader = image.num_modules > 1 && i == 0 && + !image.loadable_module; + } + + /* validate all modules */ + ret = modules_validate(&image); + if (ret < 0) + goto out; + + /* open outfile for writing */ + unlink(image.out_file); + image.out_fd = fopen(image.out_file, "wb"); + if (!image.out_fd) { + ret = file_error("unable to open file for writing", image.out_file); + goto out; + } + + /* process and write output */ + if (image.meu_offset) { + assert(image.adsp->write_firmware_meu); + ret = image.adsp->write_firmware_meu(&image); + } else { + assert(image.adsp->write_firmware); + ret = image.adsp->write_firmware(&image); + } + if (ret) + goto out; + + /* build extended manifest */ + if (use_ext_man) { + if (image.adsp->write_firmware_ext_man) + ret = image.adsp->write_firmware_ext_man(&image); + else + ret = ext_man_write(&image); + + if (ret < 0) { + fprintf(stderr, "error: unable to write extended manifest, %d\n", + ret); + goto out; + } + } + +out: + /* free memory */ + adsp_free(heap_adsp); + + /* close files */ + if (image.out_fd) + fclose(image.out_fd); + + /* Free loaded modules */ + for (i = 0; i < image.num_modules; i++) { + module_close(&image.module[i].file); + } + + return ret; +} diff --git a/tools/rimage/src/toml_utils.c b/tools/rimage/src/toml_utils.c new file mode 100644 index 000000000000..128286d7194b --- /dev/null +++ b/tools/rimage/src/toml_utils.c @@ -0,0 +1,341 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski <karolx.trzcinski@linux.intel.com> + * Marc Herbert <marc.herbert@intel.com> + */ + +#include "toml.h" +#include <rimage/toml_utils.h> +#include <rimage/cavs/cavs_ext_manifest.h> + +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <stdarg.h> + +void print_bytes(FILE *out, const uint8_t *arr, size_t len) +{ + for (const uint8_t *pos = arr; pos < arr + len; pos++) { + char c = *pos; + + if (isprint(c)) + fputc(c, out); + else + fprintf(out, "\\x%.2x", c); + } +} + +#define DUMP_PRINTABLE_BYTES(name, var) _dump_printable_bytes(name, var, sizeof(var)) + +void _dump_printable_bytes(const char *name, const uint8_t *arr, size_t len) +{ + printf(DUMP_KEY_FMT, name); + print_bytes(stdout, arr, len); + printf("\n"); +} + +/** private parser error trace function */ +void vlog_err(const char *msg, va_list vl) +{ + vfprintf(stderr, msg, vl); +} + +/** parser error trace function, error code is returned to shorten client code */ +int log_err(int err_code, const char *msg, ...) +{ + va_list vl; + + va_start(vl, msg); + vlog_err(msg, vl); + va_end(vl); + return err_code; +} + +/** log malloc error message for given key */ +int err_malloc(const char *key) +{ + return log_err(-ENOMEM, "error: malloc failed during parsing key '%s'\n", key); +} + +/** log key not found error */ +int err_key_not_found(const char *key) +{ + return log_err(-EINVAL, "error: '%s' not found\n", key); +} + +/** error during parsing key value, possible detailed message */ +int err_key_parse(const char *key, const char *extra_msg, ...) +{ + int ret = -EINVAL; + va_list vl; + + if (extra_msg) { + log_err(ret, "error: key '%s' parsing error, ", key); + va_start(vl, extra_msg); + vlog_err(extra_msg, vl); + va_end(vl); + return log_err(ret, "\n"); + } else { + return log_err(ret, "error: key '%s' parsing error\n", key); + } +} + +/** initialize parser context before parsing */ +void parse_ctx_init(struct parse_ctx *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); +} + +/** check nothing left unparsed in given parsing context */ +int assert_everything_parsed(const toml_table_t *table, struct parse_ctx *ctx) +{ + const char *key = toml_table_key(table); + int ret = 0; + + /* toml_table_key returns NULL for global context */ + if (!key) + key = "toml"; + + /* from number of parsed fields subtract fields count in given table */ + ctx->key_cnt = toml_table_nkval(table) - ctx->key_cnt; + ctx->array_cnt = toml_table_narr(table) - ctx->array_cnt; + ctx->table_cnt = toml_table_ntab(table) - ctx->table_cnt; + + /* when any field left unparsed, then raise error */ + if (ctx->key_cnt != 0) + ret = log_err(-EINVAL, "error: %d unparsed keys left in '%s'\n", ctx->key_cnt, key); + if (ctx->array_cnt != 0) + ret = log_err(-EINVAL, "error: %d unparsed arrays left in '%s'\n", ctx->array_cnt, + key); + if (ctx->table_cnt != 0) + ret = log_err(-EINVAL, "error: %d unparsed tables left in '%s'\n", ctx->table_cnt, + key); + return ret; +} + +/** + * Parse hex value from key in given toml table + * @param table toml table where key is specified + * @param ctx parsing context, key counter will be incremented after successful key parse + * @param key field name + * @param def is default value or -1 when value don't have default value + * @param error code, 0 when success + * @return default, parsed, or UINT32_MAX value for error cases + */ +uint32_t parse_uint32_hex_key(const toml_table_t *table, struct parse_ctx *ctx, + const char *key, int64_t def, int *error) +{ + toml_raw_t raw; + char *temp_s; + uint32_t val; + int ret; + + /* look for key in given table, assign def value when key not found */ + raw = toml_raw_in(table, key); + if (!raw) { + if (def < 0 || def > UINT32_MAX) { + *error = err_key_not_found(key); + return UINT32_MAX; + } else { + *error = 0; + return (uint32_t)def; + } + } + /* there is not build-in support for hex numbers in toml, so read then as string */ + ret = toml_rtos(raw, &temp_s); + if (ret < 0) { + *error = err_key_parse(key, NULL); + return UINT32_MAX; + } + val = strtoul(temp_s, 0, 0); + + free(temp_s); + /* assert parsing success and value is within uint32_t range */ + if (errno < 0) { + *error = err_key_parse(key, "can't convert hex value"); + return UINT32_MAX; + } + + /* set success error code and increment parsed key counter */ + *error = 0; + ++ctx->key_cnt; + return (uint32_t)val; +} + +/** + * Parse integer value from key in given toml table + * @param table toml table where key is specified + * @param ctx parsing context, key counter will be incremented after successful key parse + * @param key field name + * @param def is default value or -1 when value don't have default value + * @param error code, 0 when success + * @return default, parsed, or UINT32_MAX value for error cases + */ +uint32_t parse_uint32_key(const toml_table_t *table, struct parse_ctx *ctx, const char *key, + int64_t def, int *error) +{ + toml_raw_t raw; + int64_t val; + int ret; + + /* look for key in given table, assign def value when key not found */ + raw = toml_raw_in(table, key); + if (!raw) { + if (def < 0 || def > UINT32_MAX) { + *error = err_key_not_found(key); + return UINT32_MAX; + } else { + *error = 0; + return (uint32_t)def; + } + } + /* there is build-in support for integer numbers in toml, so use lib function */ + ret = toml_rtoi(raw, &val); + if (ret < 0) { + *error = err_key_parse(key, "can't convert to integer value"); + return UINT32_MAX; + } + /* assert value is within uint32_t range */ + if (val < 0 || val > UINT32_MAX) { + *error = log_err(-ERANGE, "key %s out of uint32_t range", key); + return UINT32_MAX; + } + /* set success error code and increment parsed key counter */ + *error = 0; + ++ctx->key_cnt; + return (uint32_t)val; +} + +/** + * Parse string value from key in given toml table to uint8_t array. The + * destination is NOT a string because it is padded with zeros if and + * only if there is some capacity left. For string destinations use + * parse_str_key(). + * + * @param table toml table where key is specified + * @param ctx parsing context, key counter will be incremented after successful key parse + * @param key field name + * @param dst uint8_t[] destination + * @param capacity dst array size + * @param error code, 0 when success + */ +void parse_printable_key(const toml_table_t *table, struct parse_ctx *ctx, const char *key, + uint8_t *dst, int capacity, int *error) +{ + toml_raw_t raw; + char *temp_s; + int len; + int ret; + + /* look for key in given table */ + raw = toml_raw_in(table, key); + if (!raw) { + *error = err_key_not_found(key); + return; + } + /* read string from toml, theres malloc inside toml_rtos() */ + ret = toml_rtos(raw, &temp_s); + if (ret < 0) { + *error = err_key_parse(key, NULL); + return; + } + + len = strlen(temp_s); + if (len > capacity) { + if (len > 20) { + static const char ellipsis[] = "..."; + const size_t el_len = sizeof(ellipsis); + + strncpy(temp_s + 20 - el_len, ellipsis, el_len); + } + + *error = log_err(-EINVAL, "Too long input '%s' for key '%s' (%d > %d) characters\n", + temp_s, key, len, capacity); + free(temp_s); + return; + } + + /* copy string to dst, pad with zeros the space left if any */ + strncpy((char *)dst, temp_s, capacity); + free(temp_s); + /* update parsing context */ + ++ctx->key_cnt; + *error = 0; +} + +/** + * Parse string value from key in given toml table to given + * char[]. Destination is padded with zeros. As the only difference with + * parse_printable_key(), dst is guaranteed to be null-terminated when + * there is no error because the last destination byte is reserved for + * that. + * + * @param table toml table where key is specified + * @param ctx parsing context, key counter will be incremented after successful key parse + * @param key field name + * @param dst char[] destination + * @param capacity dst array size including null termination. + * @param error code, 0 when success + */ +void parse_str_key(const toml_table_t *table, struct parse_ctx *ctx, const char *key, + char *dst, int capacity, int *error) +{ + parse_printable_key(table, ctx, key, (uint8_t *)dst, capacity - 1, error); + if (*error) /* return immediately to help forensics */ + return; + dst[capacity - 1] = 0; +} + +void parse_uuid(char *buf, uint8_t *uuid) +{ + struct uuid_t id; + uint32_t d[10]; + + sscanf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", &id.d0, &d[0], + &d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7], &d[8], &d[9]); + id.d1 = (uint16_t)d[0]; + id.d2 = (uint16_t)d[1]; + id.d3 = (uint8_t)d[2]; + id.d4 = (uint8_t)d[3]; + id.d5 = (uint8_t)d[4]; + id.d6 = (uint8_t)d[5]; + id.d7 = (uint8_t)d[6]; + id.d8 = (uint8_t)d[7]; + id.d9 = (uint8_t)d[8]; + id.d10 = (uint8_t)d[9]; + + memcpy(uuid, &id, sizeof(id)); +} + +/** version is stored as toml array with integer number, something like: + * "version = [1, 8]" + */ +int parse_version(toml_table_t *toml, int64_t version[2]) +{ + toml_array_t *arr; + toml_raw_t raw; + int ret; + int i; + + /* check "version" key */ + arr = toml_array_in(toml, "version"); + if (!arr) + return err_key_not_found("version"); + if (toml_array_type(arr) != 'i' || toml_array_nelem(arr) != 2 || + toml_array_kind(arr) != 'v') + return err_key_parse("version", "wrong array type or length != 2"); + + /* parse "version" array elements */ + for (i = 0; i < 2; ++i) { + raw = toml_raw_at(arr, i); + if (raw == 0) + return err_key_parse("version", NULL); + ret = toml_rtoi(raw, &version[i]); + if (ret < 0) + return err_key_parse("version", "can't convert element to integer"); + } + return 0; +} diff --git a/tools/rimage/tomlc99 b/tools/rimage/tomlc99 new file mode 160000 index 000000000000..e3a03f5ec7d8 --- /dev/null +++ b/tools/rimage/tomlc99 @@ -0,0 +1 @@ +Subproject commit e3a03f5ec7d8d33be705c5ce8a632d998ce9b4d1 diff --git a/tools/testbench/CMakeLists.txt b/tools/testbench/CMakeLists.txt index f68f6418399f..3d4e622c08bf 100644 --- a/tools/testbench/CMakeLists.txt +++ b/tools/testbench/CMakeLists.txt @@ -27,6 +27,7 @@ set(sof_binary_directory "${PROJECT_BINARY_DIR}/sof_ep/build") set(config_h ${sof_binary_directory}/library_autoconfig.h) target_include_directories(testbench PRIVATE "${sof_source_directory}/src/platform/library/include") +target_include_directories(testbench PRIVATE "${sof_source_directory}/src/audio") # Configuration time, make copy configure_file(${default_asoc_h} ${CMAKE_CURRENT_BINARY_DIR}/include/alsa/sound/asoc.h) diff --git a/tools/testbench/common_test.c b/tools/testbench/common_test.c index c80b94d503e2..221d6ba93d5c 100644 --- a/tools/testbench/common_test.c +++ b/tools/testbench/common_test.c @@ -264,15 +264,15 @@ int tb_pipeline_params(struct testbench_prm *tp, struct ipc *ipc, struct pipelin /* print debug messages */ void debug_print(char *message) { - if (debug) + if (host_trace_level >= LOG_LEVEL_DEBUG) printf("debug: %s", message); } /* enable trace in testbench */ -void tb_enable_trace(bool enable) +void tb_enable_trace(unsigned int log_level) { - test_bench_trace = enable; - if (enable) + host_trace_level = log_level; + if (host_trace_level) debug_print("trace print enabled\n"); else debug_print("trace print disabled\n"); diff --git a/tools/testbench/include/testbench/trace.h b/tools/testbench/include/testbench/trace.h index 73c50d43853d..66e63e217adf 100644 --- a/tools/testbench/include/testbench/trace.h +++ b/tools/testbench/include/testbench/trace.h @@ -11,6 +11,6 @@ #ifndef _TRACE_H #define _TRACE_H -void tb_enable_trace(bool enable); +void tb_enable_trace(unsigned int log_level); #endif diff --git a/tools/testbench/testbench.c b/tools/testbench/testbench.c index f4302765408f..889aba1c0209 100644 --- a/tools/testbench/testbench.c +++ b/tools/testbench/testbench.c @@ -317,9 +317,9 @@ static int parse_input_args(int argc, char **argv, struct testbench_prm *tp) tp->channels_out = atoi(optarg); break; - /* enable debug prints */ + /* set debug log level */ case 'd': - debug = 1; + host_trace_level = atoi(optarg); break; /* number of pipeline copy() iterations */ @@ -734,7 +734,6 @@ int main(int argc, char **argv) int i, err; /* initialize input and output sample rates, files, etc. */ - debug = 0; tp.total_cycles = 0; tp.fs_in = 0; tp.fs_out = 0; @@ -795,9 +794,10 @@ int main(int argc, char **argv) } if (tp.quiet) - tb_enable_trace(false); /* reduce trace output */ + tb_enable_trace(0); /* reduce trace output */ else - tb_enable_trace(true); + tb_enable_trace(1); + /* initialize ipc and scheduler */ if (tb_setup(sof_get(), &tp) < 0) { diff --git a/tools/topology/topology1/CMakeLists.txt b/tools/topology/topology1/CMakeLists.txt index 028c924abaad..53b4404941b9 100644 --- a/tools/topology/topology1/CMakeLists.txt +++ b/tools/topology/topology1/CMakeLists.txt @@ -56,6 +56,7 @@ set(TPLGS "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l2-rt1316-l01-rt714-l3\;-DPLATFORM=rpl\;-DUAJ_LINK=2\;-DAMP_1_LINK=0\;-DAMP_2_LINK=1\;-DEXT_AMP_REF\;-DMIC_LINK=3" "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l2-rt1316-l01\;-DPLATFORM=rpl\;-DUAJ_LINK=2\;-DAMP_1_LINK=0\;-DAMP_2_LINK=1\;-DEXT_AMP_REF\;-DNO_LOCAL_MIC" "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l0-rt1316-l12-rt714-l3\;-DPLATFORM=rpl\;-DUAJ_LINK=0\;-DAMP_1_LINK=1\;-DAMP_2_LINK=2\;-DEXT_AMP_REF\;-DMIC_LINK=3" + "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l0-rt1316-l12\;-DPLATFORM=rpl\;-DUAJ_LINK=0\;-DAMP_1_LINK=1\;-DAMP_2_LINK=2\;-DEXT_AMP_REF\;-DNO_LOCAL_MIC" "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l0-rt1318-l12-rt714-l3\;-DPLATFORM=rpl\;-DUAJ_LINK=0\;-DAMP_1_LINK=1\;-DAMP_2_LINK=2\;-DEXT_AMP_REF\;-DMIC_LINK=3" "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l0-rt1318-l12\;-DPLATFORM=rpl\;-DUAJ_LINK=0\;-DAMP_1_LINK=1\;-DAMP_2_LINK=2\;-DEXT_AMP_REF\;-DNO_LOCAL_MIC" "sof-tgl-rt711-rt1308\;sof-tgl-rt711-rt1308-2ch\;-DCHANNELS=2\;-DEXT_AMP\;-DDMICPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_48khz.m4\;-DDMIC16KPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_16khz.m4\;-DPLATFORM=tgl" @@ -78,37 +79,35 @@ set(TPLGS "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt1316-l12-rt714-l0\;-DPLATFORM=rpl\;-DNOJACK\;-DAMP_1_LINK=1\;-DAMP_2_LINK=2\;-DEXT_AMP_REF\;-DMIC_LINK=0" ## end SoundWire NOJACK topologies - "sof-ehl-rt5660\;sof-ehl-rt5660\;-DHDMI=1" - "sof-ehl-rt5660\;sof-ehl-rt5660-nohdmi" "sof-tgl-max98357a-rt5682\;sof-tgl-max98357a-rt5682\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DPLATFORM=tgl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1" - "sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2" - "sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682-rtnr\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2\;-DCHANNELS=2\;-DRTNR" + "sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682-rtnr\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2\;-DCHANNELS=2\;-DRTNR\;-DDYNAMIC=1" "sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682-waves\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2\;-DWAVES" - "sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682-2way\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2\;-D2CH_2WAY" + "sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682-2way\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2\;-D2CH_2WAY\;-DDYNAMIC=1" "sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682-waves-2way\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2\;-D2CH_2WAY\;-DWAVES" - "sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682-4ch\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2\;-D4CH_PASSTHROUGH" - "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682\;-DCODEC=MAX98360A\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DSPK_MIC_PERIOD_US=10000" + "sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682-4ch\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2\;-D4CH_PASSTHROUGH\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682\;-DCODEC=MAX98360A\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DSPK_MIC_PERIOD_US=10000\;-DDYNAMIC=1" "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-waves\;-DCODEC=MAX98360A\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DWAVES" "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-waves-spk-only\;-DCODEC=MAX98360A\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DWAVES\;-DWAVES_SPK_ONLY" - "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-2way\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-D2CH_2WAY\;-DBT_OFFLOAD" - "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-2way-pdm1\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DDMIC_DAI_LINK_16k_PDM=STEREO_PDM1\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-D2CH_2WAY\;-DBT_OFFLOAD" - "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-4ch\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-D4CH_PASSTHROUGH\;-DBT_OFFLOAD" - "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-rtnr\;-DCODEC=MAX98360A\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DCHANNELS=2\;-DRTNR" - "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-rtnr-google-aec\;-DCODEC=MAX98360A\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DCHANNELS=2\;-DGOOGLE_RTC_AUDIO_PROCESSING\;-DRTNR\;-DNOHOTWORD\;-DNO16KDMIC" + "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-2way\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-D2CH_2WAY\;-DBT_OFFLOAD\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-2way-pdm1\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DDMIC_DAI_LINK_16k_PDM=STEREO_PDM1\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-D2CH_2WAY\;-DBT_OFFLOAD\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-4ch\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-D4CH_PASSTHROUGH\;-DBT_OFFLOAD\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-rtnr\;-DCODEC=MAX98360A\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DCHANNELS=2\;-DRTNR\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682-rtnr-google-aec\;-DCODEC=MAX98360A\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DCHANNELS=2\;-DGOOGLE_RTC_AUDIO_PROCESSING\;-DRTNR\;-DNOHOTWORD\;-DNO16KDMIC\;-DDYNAMIC=1" "sof-tgl-max98357a-rt5682\;sof-tgl-max98357a-rt5682-pdm1\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DDMIC_DAI_LINK_16k_PDM=STEREO_PDM1\;-DPLATFORM=tgl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1" "sof-tgl-max98357a-rt5682\;sof-tgl-max98357a-rt5682-pdm1-google-aec\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DDMIC_DAI_LINK_16k_PDM=STEREO_PDM1\;-DPLATFORM=tgl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DCHANNELS=2\;-DGOOGLE_RTC_AUDIO_PROCESSING" "sof-tgl-max98357a-rt5682\;sof-tgl-max98357a-rt5682-pdm1-drceq\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DDMIC_DAI_LINK_16k_PDM=STEREO_PDM1\;-DPLATFORM=tgl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DDRC_EQ" "sof-tgl-max98357a-rt5682\;sof-tgl-rt1011-rt5682\;-DCODEC=RT1011\;-DFMT=s24le\;-DPLATFORM=tgl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1" "sof-tgl-max98357a-rt5682\;sof-tgl-max98357a-rt5682-rtnr\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DPLATFORM=tgl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DCHANNELS=2\;-DRTNR" - "sof-tgl-max98357a-rt5682\;sof-adl-max98390-rt5682\;-DCODEC=MAX98390\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DBT_OFFLOAD" - "sof-tgl-max98357a-rt5682\;sof-adl-max98390-rt5682-rtnr\;-DCODEC=MAX98390\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DCHANNELS=2\;-DRTNR\;-DNOHOTWORD\;-DDMICPROC=rtnr\;-DNO16KDMIC\;-DDMIC_48k_CORE_ID=1" - "sof-tgl-max98357a-rt5682\;sof-adl-max98390-rt5682-google-aec\;-DCODEC=MAX98390\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DCHANNELS=2\;-DGOOGLE_RTC_AUDIO_PROCESSING\;-DNOHOTWORD\;-DNO16KDMIC" - "sof-tgl-max98357a-rt5682\;sof-adl-max98390-rt5682-rtnr-google-aec\;-DCODEC=MAX98390\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DCHANNELS=2\;-DGOOGLE_RTC_AUDIO_PROCESSING\;-DRTNR\;-DNOHOTWORD\;-DNO16KDMIC\;-DSPK_MIC_PERIOD_US=10000" - "sof-tgl-max98357a-rt5682\;sof-adl-max98390-ssp2-rt5682-ssp0\;-DCODEC=MAX98390\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2" - "sof-tgl-max98357a-rt5682\;sof-adl-rt5682\;-DNO_AMP\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682" - "sof-tgl-max98357a-rt5682\;sof-adl-rt1019-rt5682\;-DCODEC=RT1019\;-DFMT=s24le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DSPK_MIC_PERIOD_US=10000\;-DBT_OFFLOAD" + "sof-tgl-max98357a-rt5682\;sof-adl-max98390-rt5682\;-DCODEC=MAX98390\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-max98390-rt5682-rtnr\;-DCODEC=MAX98390\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DCHANNELS=2\;-DRTNR\;-DNOHOTWORD\;-DDMICPROC=rtnr\;-DNO16KDMIC\;-DDMIC_48k_CORE_ID=1\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-max98390-rt5682-google-aec\;-DCODEC=MAX98390\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DCHANNELS=2\;-DGOOGLE_RTC_AUDIO_PROCESSING\;-DNOHOTWORD\;-DNO16KDMIC\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-max98390-rt5682-rtnr-google-aec\;-DCODEC=MAX98390\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DCHANNELS=2\;-DGOOGLE_RTC_AUDIO_PROCESSING\;-DRTNR\;-DNOHOTWORD\;-DNO16KDMIC\;-DSPK_MIC_PERIOD_US=10000\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-max98390-ssp2-rt5682-ssp0\;-DCODEC=MAX98390\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=2\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-rt5682\;-DNO_AMP\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DDYNAMIC=1" + "sof-tgl-max98357a-rt5682\;sof-adl-rt1019-rt5682\;-DCODEC=RT1019\;-DFMT=s24le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DSPK_MIC_PERIOD_US=10000\;-DBT_OFFLOAD\;-DDYNAMIC=1" "sof-tgl-max98357a-rt5682\;sof-adl-rt1019-rt5682-waves\;-DCODEC=RT1019\;-DFMT=s24le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DWAVES\;-DBT_OFFLOAD" - "sof-tgl-max98357a-rt5682\;sof-adl-cs35l41\;-DCODEC=CS35L41\;-DFMT=s24le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_ssp_amp\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DNO_HEADPHONE" + "sof-tgl-max98357a-rt5682\;sof-adl-cs35l41\;-DCODEC=CS35L41\;-DFMT=s24le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_ssp_amp\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DNO_HEADPHONE\;-DDYNAMIC=1" "sof-tgl-max98357a-rt5682\;sof-adl-cs35l41-waves\;-DCODEC=CS35L41\;-DFMT=s24le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_ssp_amp\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DNO_HEADPHONE\;-DWAVES\;-DNOHOTWORD\;-DNO16KDMIC" "sof-tgl-max98357a-rt5682\;sof-adl-cs35l41-google-aec-waves\;-DCODEC=CS35L41\;-DFMT=s24le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_ssp_amp\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DNO_HEADPHONE\;-DGOOGLE_RTC_AUDIO_PROCESSING\;-DWAVES\;-DNOHOTWORD\;-DNO16KDMIC\;-DSPK_MIC_PERIOD_US=10000" "sof-tgl-max98357a-rt5682\;sof-adl-max98360a-da7219\;-DUSE_DA7219\;-DCODEC=MAX98360A\;-DFMT=s32le\;-DPLATFORM=adl\;-DLINUX_MACHINE_DRIVER=sof_rt5682\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DSPK_MIC_PERIOD_US=10000\;-DNOHOTWORD\;-DNO16KDMIC" @@ -118,15 +117,15 @@ set(TPLGS "sof-tgl-max98373-rt5682\;sof-tgl-max98373-rt5682-xperi\;-DAMP_SSP=1\;-DINCLUDE_IIR_EQ=1" "sof-tgl-max98373-rt5682\;sof-tgl-rt5682-ssp0-max98373-ssp2\;-DAMP_SSP=2" "sof-tgl-max98373-rt5682\;sof-tgl-rt5682-ssp0-max98373-ssp2-xperi\;-DAMP_SSP=2\;-DINCLUDE_IIR_EQ=1" - "sof-adl-nau8825\;sof-adl-nau8825\;-DNO_AMP\;-DBT_OFFLOAD" - "sof-adl-nau8825\;sof-adl-max98373-nau8825\;-DAMP_SSP=1\;-DSMART_AMP\;-DBT_OFFLOAD\;-DNOHOTWORD\;-DNO16KDMIC" + "sof-adl-nau8825\;sof-adl-nau8825\;-DNO_AMP\;-DBT_OFFLOAD\;-DDYNAMIC=1" + "sof-adl-nau8825\;sof-adl-max98373-nau8825\;-DAMP_SSP=1\;-DSMART_AMP\;-DBT_OFFLOAD\;-DNOHOTWORD\;-DNO16KDMIC\;-DDYNAMIC=1" "sof-adl-nau8825\;sof-adl-max98373-nau8825-dts\;-DAMP_SSP=1\;-DSMART_AMP\;-DBT_OFFLOAD\;-DNOHOTWORD\;-DNO16KDMIC\;-DDTS=`DTS'" - "sof-adl-nau8825\;sof-adl-max98360a-nau8825\;-DCODEC=MAX98360A\;-DFMT=s16le\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DSPK_MIC_PERIOD_US=10000" - "sof-adl-nau8825\;sof-adl-rt1019-nau8825\;-DCODEC=RT1019P\;-DFMT=s16le\;-DAMP_SSP=2\;-DSPK_MIC_PERIOD_US=10000" - "sof-adl-nau8825\;sof-adl-rt1015-nau8825\;-DCODEC=RT1015P\;-DFMT=s32le\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DSPK_MIC_PERIOD_US=10000" - "sof-adl-nau8825\;sof-adl-nau8318-nau8825\;-DCODEC=NAU8318\;-DFMT=s16le\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DSPK_MIC_PERIOD_US=10000" + "sof-adl-nau8825\;sof-adl-max98360a-nau8825\;-DCODEC=MAX98360A\;-DFMT=s16le\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DSPK_MIC_PERIOD_US=10000\;-DDYNAMIC=1" + "sof-adl-nau8825\;sof-adl-rt1019-nau8825\;-DCODEC=RT1019P\;-DFMT=s16le\;-DAMP_SSP=2\;-DSPK_MIC_PERIOD_US=10000\;-DDYNAMIC=1" + "sof-adl-nau8825\;sof-adl-rt1015-nau8825\;-DCODEC=RT1015P\;-DFMT=s32le\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DSPK_MIC_PERIOD_US=10000\;-DDYNAMIC=1" + "sof-adl-nau8825\;sof-adl-nau8318-nau8825\;-DCODEC=NAU8318\;-DFMT=s16le\;-DAMP_SSP=1\;-DBT_OFFLOAD\;-DSPK_MIC_PERIOD_US=10000\;-DDYNAMIC=1" "sof-tgl-sdw-max98373-rt5682\;sof-tgl-sdw-max98373-rt5682\;-DCHANNELS=4\;-DPLATFORM=tgl" - "sof-tgl-sdw-max98373-rt5682\;sof-adl-sdw-max98373-rt5682\;-DCHANNELS=4\;-DPLATFORM=adl" + "sof-tgl-sdw-max98373-rt5682\;sof-adl-sdw-max98373-rt5682\;-DCHANNELS=4\;-DPLATFORM=adl\;-DDYNAMIC=1" "sof-smart-amplifier-nocodec\;sof-smart-amplifier-nocodec" "sof-glk-es8336\;sof-tgl-es8336\;-DPLATFORM=tgl\;-DSSP_NUM=0\;-DCHANNELS=2" diff --git a/tools/topology/topology1/kernel_dependent/v5.19/CMakeLists.txt b/tools/topology/topology1/kernel_dependent/v5.19/CMakeLists.txt index 2556c26914e9..46fcfb0b4f85 100644 --- a/tools/topology/topology1/kernel_dependent/v5.19/CMakeLists.txt +++ b/tools/topology/topology1/kernel_dependent/v5.19/CMakeLists.txt @@ -26,6 +26,7 @@ set(TPLGS_UP "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l2-rt1316-l01-rt714-l3\;-DHEADSET_DEEP_BUFFER\;-DDYNAMIC=1\;-DPLATFORM=rpl\;-DUAJ_LINK=2\;-DAMP_1_LINK=0\;-DAMP_2_LINK=1\;-DEXT_AMP_REF\;-DMIC_LINK=3" "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l2-rt1316-l01\;-DHEADSET_DEEP_BUFFER\;-DDYNAMIC=1\;-DPLATFORM=rpl\;-DUAJ_LINK=2\;-DAMP_1_LINK=0\;-DAMP_2_LINK=1\;-DEXT_AMP_REF\;-DNO_LOCAL_MIC" "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l0-rt1316-l12-rt714-l3\;-DHEADSET_DEEP_BUFFER\;-DDYNAMIC=1\;-DPLATFORM=rpl\;-DUAJ_LINK=0\;-DAMP_1_LINK=1\;-DAMP_2_LINK=2\;-DEXT_AMP_REF\;-DMIC_LINK=3" + "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l0-rt1316-l12\;-DHEADSET_DEEP_BUFFER\;-DDYNAMIC=1\;-DPLATFORM=rpl\;-DUAJ_LINK=0\;-DAMP_1_LINK=1\;-DAMP_2_LINK=2\;-DEXT_AMP_REF\;-DNO_LOCAL_MIC" "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l0-rt1318-l12-rt714-l3\;-DHEADSET_DEEP_BUFFER\;-DDYNAMIC=1\;-DPLATFORM=rpl\;-DUAJ_LINK=0\;-DAMP_1_LINK=1\;-DAMP_2_LINK=2\;-DEXT_AMP_REF\;-DMIC_LINK=3" "sof-icl-rt711-rt1308-rt715-hdmi\;sof-rpl-rt711-l0-rt1318-l12\;-DHEADSET_DEEP_BUFFER\;-DDYNAMIC=1\;-DPLATFORM=rpl\;-DUAJ_LINK=0\;-DAMP_1_LINK=1\;-DAMP_2_LINK=2\;-DEXT_AMP_REF\;-DNO_LOCAL_MIC" "sof-tgl-rt711-rt1308\;sof-tgl-rt711-rt1308-2ch\;-DHEADSET_DEEP_BUFFER\;-DDYNAMIC=1\;-DCHANNELS=2\;-DEXT_AMP\;-DDMICPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_48khz.m4\;-DDMIC16KPROC_FILTER1=eq_iir_coef_highpass_40hz_20db_16khz.m4\;-DPLATFORM=tgl" diff --git a/tools/topology/topology1/sof-cavs-nocodec.m4 b/tools/topology/topology1/sof-cavs-nocodec.m4 index d5c3e2ed147f..ba5f741f26e2 100644 --- a/tools/topology/topology1/sof-cavs-nocodec.m4 +++ b/tools/topology/topology1/sof-cavs-nocodec.m4 @@ -101,17 +101,19 @@ dnl time_domain, sched_comp) # Volume switch capture pipeline 2 on PCM 0 using max 2 channels of PIPE_BITS. # Set 1000us deadline on core SSP0_CORE_ID with priority 0 -PIPELINE_PCM_ADD(sof/pipe-volume-switch-capture.m4, +ifdef(`DISABLE_SSP0',, + `PIPELINE_PCM_ADD(sof/pipe-volume-switch-capture.m4, 2, 0, 2, PIPE_BITS, 1000, 0, SSP0_CORE_ID, - 48000, 48000, 48000) + 48000, 48000, 48000)') # Volume switch capture pipeline 4 on PCM 1 using max 2 channels of PIPE_BITS. # Set 1000us deadline on core SSP1_CORE_ID with priority 0 -PIPELINE_PCM_ADD(sof/pipe-volume-switch-capture.m4, +ifdef(`DISABLE_SSP1',, + `PIPELINE_PCM_ADD(sof/pipe-volume-switch-capture.m4, 4, 1, 2, PIPE_BITS, 1000, 0, SSP1_CORE_ID, - 48000, 48000, 48000) + 48000, 48000, 48000)') # Volume switch capture pipeline 6 on PCM 2 using max 2 channels of PIPE_BITS. # Set 1000us deadline with priority 0 on core SSP2_CORE_ID @@ -132,19 +134,21 @@ dnl deadline, priority, core, time_domain) # playback DAI is SSP0 using 2 periods # Buffers use DAI_BITS format, 1000us deadline with priority 0 on core SSP0_CORE_ID # The 'NOT_USED_IGNORED' is due to dependencies and is adjusted later with an explicit dapm line. -DAI_ADD(sof/pipe-mixer-volume-dai-playback.m4, +ifdef(`DISABLE_SSP0',, + `DAI_ADD(sof/pipe-mixer-volume-dai-playback.m4, 1, SSP, SSP0_IDX, NoCodec-0, NOT_USED_IGNORED, 2, DAI_BITS, - 1000, 0, SSP0_CORE_ID, SCHEDULE_TIME_DOMAIN_TIMER, 2, 48000) + 1000, 0, SSP0_CORE_ID, SCHEDULE_TIME_DOMAIN_TIMER, 2, 48000)') # Low Latency playback pipeline 1 on PCM 0 using max 2 channels of PIPE_BITS. # Set 1000us deadline on core SSP0_CORE_ID with priority 0 -PIPELINE_PCM_ADD(sof/pipe-host-volume-playback.m4, +ifdef(`DISABLE_SSP0',, + `PIPELINE_PCM_ADD(sof/pipe-host-volume-playback.m4, 7, 0, 2, PIPE_BITS, 1000, 0, SSP0_CORE_ID, 48000, 48000, 48000, SCHEDULE_TIME_DOMAIN_TIMER, - PIPELINE_PLAYBACK_SCHED_COMP_1) + PIPELINE_PLAYBACK_SCHED_COMP_1)') # Deep buffer playback pipeline 11 on PCM 3 using max 2 channels of PIPE_BITS. # Set 1000us deadline on core SSP0_CORE_ID with priority 0. @@ -158,33 +162,37 @@ PIPELINE_PCM_ADD(sof/pipe-host-volume-playback.m4, # capture DAI is SSP0 using 2 periods # Buffers use DAI_BITS format, 1000us deadline with priority 0 on core SSP0_IDX -DAI_ADD(sof/pipe-dai-capture.m4, +ifdef(`DISABLE_SSP0',, + `DAI_ADD(sof/pipe-dai-capture.m4, 2, SSP, SSP0_IDX, NoCodec-0, PIPELINE_SINK_2, 2, DAI_BITS, - 1000, 0, SSP0_CORE_ID, SCHEDULE_TIME_DOMAIN_TIMER) + 1000, 0, SSP0_CORE_ID, SCHEDULE_TIME_DOMAIN_TIMER)') # playback DAI is SSP1 using 2 periods # Buffers use DAI_BITS format, 1000us deadline with priority 0 on core SSP1_CORE_ID -DAI_ADD(sof/pipe-mixer-volume-dai-playback.m4, +ifdef(`DISABLE_SSP1',, + `DAI_ADD(sof/pipe-mixer-volume-dai-playback.m4, 3, SSP, SSP1_IDX, NoCodec-1, NOT_USED_IGNORED, 2, DAI_BITS, - 1000, 0, SSP1_CORE_ID, SCHEDULE_TIME_DOMAIN_TIMER, 2, 48000) + 1000, 0, SSP1_CORE_ID, SCHEDULE_TIME_DOMAIN_TIMER, 2, 48000)') # Low Latency playback pipeline 8 on PCM 1 using max 2 channels of PIPE_BITS. # Set 1000us deadline on core SSP1_CORE_ID with priority 0 -PIPELINE_PCM_ADD(sof/pipe-host-volume-playback.m4, +ifdef(`DISABLE_SSP1',, + `PIPELINE_PCM_ADD(sof/pipe-host-volume-playback.m4, 8, 1, 2, PIPE_BITS, 1000, 0, SSP1_CORE_ID, 48000, 48000, 48000, SCHEDULE_TIME_DOMAIN_TIMER, - PIPELINE_PLAYBACK_SCHED_COMP_3) + PIPELINE_PLAYBACK_SCHED_COMP_3)') # capture DAI is SSP1 using 2 periods # Buffers use DAI_BITS format, 1000us deadline with priority 0 on core SSP1_CORE_ID -DAI_ADD(sof/pipe-dai-capture.m4, +ifdef(`DISABLE_SSP1',, + `DAI_ADD(sof/pipe-dai-capture.m4, 4, SSP, SSP1_IDX, NoCodec-1, PIPELINE_SINK_4, 2, DAI_BITS, - 1000, 0, SSP1_CORE_ID, SCHEDULE_TIME_DOMAIN_TIMER) + 1000, 0, SSP1_CORE_ID, SCHEDULE_TIME_DOMAIN_TIMER)') # playback DAI is SSP2 using 2 periods # Buffers use DAI_BITS format, 1000us deadline with priority 0 on core SSP2_CORE_ID @@ -214,8 +222,8 @@ SectionGraph."mixer-host" { lines [ # connect mixer dai pipelines to PCM pipelines - dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_7) - dapm(PIPELINE_MIXER_3, PIPELINE_SOURCE_8) + ifdef(`DISABLE_SSP0',,`dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_7)') + ifdef(`DISABLE_SSP1',, `dapm(PIPELINE_MIXER_3, PIPELINE_SOURCE_8)') dapm(PIPELINE_MIXER_5, PIPELINE_SOURCE_9) ] } diff --git a/tools/topology/topology1/sof-cml-demux-rt5682.m4 b/tools/topology/topology1/sof-cml-demux-rt5682.m4 deleted file mode 100644 index ff131dfb75b5..000000000000 --- a/tools/topology/topology1/sof-cml-demux-rt5682.m4 +++ /dev/null @@ -1,228 +0,0 @@ -# -# Topology for Cometlake with rt5682 codec. -# - -# Include topology builder -include(`utils.m4') -include(`dai.m4') -include(`pipeline.m4') -include(`ssp.m4') -include(`muxdemux.m4') -include(`hda.m4') - -# Include TLV library -include(`common/tlv.m4') - -# Include Token library -include(`sof/tokens.m4') - -# Include platform specific DSP configuration -include(`platform/intel/'PLATFORM`.m4') - -DEBUG_START - -dnl Configure demux -dnl name, pipeline_id, routing_matrix_rows -dnl Diagonal 1's in routing matrix mean that every input channel is -dnl copied to corresponding output channels in all output streams. -dnl I.e. row index is the input channel, 1 means it is copied to -dnl corresponding output channel (column index), 0 means it is discarded. -dnl There's a separate matrix for all outputs. -define(matrix1, `ROUTE_MATRIX(1, - `BITS_TO_BYTE(1, 0, 0 ,0 ,0 ,0 ,0 ,0)', - `BITS_TO_BYTE(0, 1, 0 ,0 ,0 ,0 ,0 ,0)', - `BITS_TO_BYTE(0, 0, 1 ,0 ,0 ,0 ,0 ,0)', - `BITS_TO_BYTE(0, 0, 0 ,1 ,0 ,0 ,0 ,0)', - `BITS_TO_BYTE(0, 0, 0 ,0 ,1 ,0 ,0 ,0)', - `BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,1 ,0 ,0)', - `BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,1 ,0)', - `BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,1)')') - -define(matrix2, `ROUTE_MATRIX(5, - `BITS_TO_BYTE(1, 0, 0 ,0 ,0 ,0 ,0 ,0)', - `BITS_TO_BYTE(0, 1, 0 ,0 ,0 ,0 ,0 ,0)', - `BITS_TO_BYTE(0, 0, 1 ,0 ,0 ,0 ,0 ,0)', - `BITS_TO_BYTE(0, 0, 0 ,1 ,0 ,0 ,0 ,0)', - `BITS_TO_BYTE(0, 0, 0 ,0 ,1 ,0 ,0 ,0)', - `BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,1 ,0 ,0)', - `BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,1 ,0)', - `BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,1)')') - -dnl name, num_streams, route_matrix list -MUXDEMUX_CONFIG(demux_priv_1, 2, LIST_NONEWLINE(`', `matrix1,', `matrix2')) - -# -# Define the pipelines -# -# PCM0 ----> demux ----> SSP(SSP_INDEX) -# PCM0 <---- volume <----- SSP(SSP_INDEX) -# PCM1 ----> volume -----> DMIC01 (dmic0 capture) -# PCM2 ----> volume -----> iDisp1 -# PCM3 ----> volume -----> iDisp2 -# PCM4 ----> volume -----> iDisp3 -# PCM5 <---- demux -# - -dnl PIPELINE_PCM_ADD(pipeline, -dnl pipe id, pcm, max channels, format, -dnl period, priority, core, -dnl pcm_min_rate, pcm_max_rate, pipeline_rate, -dnl time_domain, sched_comp) - -# Demux pipeline 1 on PCM 0 using max 2 channels of s24le. -# Set 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-demux-playback.m4, - 1, 0, 2, s24le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s24le. -# Set 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4, - 2, 0, 2, s24le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Passthrough capture pipeline 3 on PCM 1 using max 4 channels. -# Set 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, - 3, 1, 4, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency playback pipeline 4 on PCM 2 using max 2 channels of s32le. -# Set 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 4, 2, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency playback pipeline 5 on PCM 3 using max 2 channels of s32le. -# Set 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 7, 3, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency playback pipeline 6 on PCM 4 using max 2 channels of s32le. -# Set 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 6, 4, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# -# DAIs configuration -# - -dnl DAI_ADD(pipeline, -dnl pipe id, dai type, dai_index, dai_be, -dnl buffer, periods, format, -dnl deadline, priority, core, time_domain) - -# playback DAI is SSP(SPP_INDEX) using 2 periods -# Buffers use s24le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 1, SSP, SSP_INDEX, SSP_NAME, - PIPELINE_SOURCE_1, 2, s24le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# capture DAI is SSP(SSP_INDEX) using 2 periods -# Buffers use s24le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-capture.m4, - 2, SSP,SSP_INDEX, SSP_NAME, - PIPELINE_SINK_2, 2, s24le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# Capture pipeline 5 on PCM 5 using max 2 channels of s32le. -PIPELINE_PCM_ADD(sof/pipe-passthrough-capture-sched.m4, - 5, 5, 2, s32le, - 1000, 1, 0, - 48000, 48000, 48000, - SCHEDULE_TIME_DOMAIN_TIMER) - -# Connect demux to capture -SectionGraph."PIPE_CAP" { - index "0" - - lines [ - # demux to capture - dapm(PIPELINE_SINK_5, PIPELINE_DEMUX_1) - ] -} - -# Connect virtual capture to dai -SectionGraph."PIPE_CAP_VIRT" { - index "5" - - lines [ - # mux to capture - dapm(ECHO REF 5, `SSP'SSP_INDEX`.IN') - ] -} - -# capture DAI is DMIC01 using 2 periods -# Buffers use s32le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-capture.m4, - 3, DMIC, 0, dmic01, - PIPELINE_SINK_3, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp1 using 2 periods -# Buffers use s32le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 4, HDA, 0, iDisp1, - PIPELINE_SOURCE_4, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp2 using 2 periods -# Buffers use s32le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 7, HDA, 1, iDisp2, - PIPELINE_SOURCE_7, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp3 using 2 periods -# Buffers use s32le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 6, HDA, 2, iDisp3, - PIPELINE_SOURCE_6, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# PCM Low Latency, id 0 -dnl PCM_PLAYBACK_ADD(name, pcm_id, playback) -PCM_DUPLEX_ADD(Port1, 0, PIPELINE_PCM_1, PIPELINE_PCM_2) -PCM_CAPTURE_ADD(DMIC, 1, PIPELINE_PCM_3) -PCM_PLAYBACK_ADD(HDMI1, 2, PIPELINE_PCM_4) -PCM_PLAYBACK_ADD(HDMI2, 3, PIPELINE_PCM_7) -PCM_PLAYBACK_ADD(HDMI3, 4, PIPELINE_PCM_6) -PCM_CAPTURE_ADD(EchoRef, 5, PIPELINE_PCM_5) - -# -# BE configurations - overrides config in ACPI if present -# - -#SSP SSP_INDEX (ID: 0) -DAI_CONFIG(SSP, SSP_INDEX, 0, SSP_NAME, - SSP_CONFIG(I2S, SSP_CLOCK(mclk, SSP_MCLK_RATE, codec_mclk_in), - SSP_CLOCK(bclk, 2400000, codec_slave), - SSP_CLOCK(fsync, 48000, codec_slave), - SSP_TDM(2, 25, 3, 3), - SSP_CONFIG_DATA(SSP, SSP_INDEX, 24))) - -# dmic01 (ID: 1) -DAI_CONFIG(DMIC, 0, 1, dmic01, - DMIC_CONFIG(1, 2400000, 4800000, 40, 60, 48000, - DMIC_WORD_LENGTH(s32le), 400, DMIC, 0, - PDM_CONFIG(DMIC, 0, FOUR_CH_PDM0_PDM1))) - -# 3 HDMI/DP outputs (ID: 3,4,5) -DAI_CONFIG(HDA, 0, 3, iDisp1, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 0, 48000, 2))) -DAI_CONFIG(HDA, 1, 4, iDisp2, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 1, 48000, 2))) -DAI_CONFIG(HDA, 2, 5, iDisp3, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 2, 48000, 2))) - - -DEBUG_END diff --git a/tools/topology/topology1/sof-cml-rt5682-kwd.m4 b/tools/topology/topology1/sof-cml-rt5682-kwd.m4 deleted file mode 100644 index f05ed9913ae4..000000000000 --- a/tools/topology/topology1/sof-cml-rt5682-kwd.m4 +++ /dev/null @@ -1,235 +0,0 @@ -# -# Topology for Cometlake with rt5682 codec and Keyword Detect. -# - -# Include topology builder -include(`utils.m4') -include(`dai.m4') -include(`pipeline.m4') -include(`ssp.m4') -include(`hda.m4') - -# Include TLV library -include(`common/tlv.m4') - -# Include Token library -include(`sof/tokens.m4') - -include(`abi.h') -# Include Platform specific DSP configuration -include(`platform/intel/'PLATFORM`.m4') - -define(KWD_PIPE_SCH_DEADLINE_US, 5000) - -DEBUG_START - -# if XPROC is not defined, define with default pipe -ifdef(`HSMICPROC', , `define(HSMICPROC, volume)') -ifdef(`HSEARPROC', , `define(HSEARPROC, volume)') -ifdef(`DMICPROC', , `define(DMICPROC, passthrough)') -ifdef(`DMIC16KPROC', , `define(DMIC16KPROC, passthrough)') - -# FIXME: Using DMIC16kHz instead of DMIC16k, otherwise M4 does not return. -define(DMIC_16k_PCM_NAME, DMIC16kHz) - -# -# Define the pipelines -# -# PCM0 <---> volume <----> SSP(SSP_INDEX, BE link 0) -# PCM1 <---- DMICPROC <--- DMIC01 (dmic0 capture, , BE link 1) -# PCM2 ----> volume -----> iDisp1 (HDMI/DP playback, BE link 3) -# PCM3 ----> volume -----> iDisp2 (HDMI/DP playback, BE link 4) -# PCM4 ----> volume -----> iDisp3 (HDMI/DP playback, BE link 5) -# PCM8 <-------(pipe 8) <------------+- KPBM 0 <----- DMIC1 (dmic16k, BE link 2) -# | -# Detector <--- selector (pipe 9) <---+ -# - -dnl PIPELINE_PCM_ADD(pipeline, -dnl pipe id, pcm, max channels, format, -dnl period, priority, core, -dnl pcm_min_rate, pcm_max_rate, pipeline_rate, -dnl time_domain, sched_comp) - -# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s24le. -# Schedule 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 1, 0, 2, s24le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s24le. -# Schedule 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4, - 2, 0, 2, s24le, - 1000, 0, 0, - 48000, 48000, 48000) - -# DMICPROC capture pipeline 3 on PCM 1 using max 4 channels. -# Schedule 1000us deadline with priority 0 on core 0 -ifdef(`DMICPROC_FILTER1', `define(PIPELINE_FILTER1, DMICPROC_FILTER1)') -ifdef(`DMICPROC_FILTER2', `define(PIPELINE_FILTER2, DMICPROC_FILTER2)') - -PIPELINE_PCM_ADD(sof/pipe-DMICPROC-capture.m4, - 3, 1, 4, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -undefine(`PIPELINE_FILTER1') -undefine(`PIPELINE_FILTER2') - -# Low Latency playback pipeline 4 on PCM 2 using max 2 channels of s32le. -# Schedule 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 4, 2, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency playback pipeline 5 on PCM 3 using max 2 channels of s32le. -# Schedule 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 5, 3, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency playback pipeline 6 on PCM 4 using max 2 channels of s32le. -# Schedule 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 6, 4, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# -# DAIs configuration -# - -dnl DAI_ADD(pipeline, -dnl pipe id, dai type, dai_index, dai_be, -dnl buffer, periods, format, -dnl deadline, priority, core, time_domain) - -# playback DAI is SSP(SPP_INDEX) using 2 periods -# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 1, SSP, SSP_INDEX, SSP_NAME, - PIPELINE_SOURCE_1, 2, s24le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# capture DAI is SSP(SSP_INDEX) using 2 periods -# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-capture.m4, - 2, SSP,SSP_INDEX, SSP_NAME, - PIPELINE_SINK_2, 2, s24le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# capture DAI is DMIC01 using 2 periods -# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-capture.m4, - 3, DMIC, 0, dmic01, - PIPELINE_SINK_3, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp1 using 2 periods -# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 4, HDA, 0, iDisp1, - PIPELINE_SOURCE_4, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp2 using 2 periods -# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 5, HDA, 1, iDisp2, - PIPELINE_SOURCE_5, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp3 using 2 periods -# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 6, HDA, 2, iDisp3, - PIPELINE_SOURCE_6, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# -# KWD configuration -# - -# Passthrough capture pipeline 7 on PCM 7 using max 2 channels. -# Schedule 20000us deadline with priority 0 on core 0 -PIPELINE_PCM_DAI_ADD(sof/pipe-kfbm-capture.m4, - 8, 8, 2, s24le, - KWD_PIPE_SCH_DEADLINE_US, 0, 0, DMIC, 1, s32le, 3, - 16000, 16000, 16000) - -# capture DAI is DMIC 1 using 3 periods -# Buffers use s32le format, with 320 frame per 20000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-capture.m4, - 8, DMIC, 1, dmic16k, - PIPELINE_SINK_8, 3, s32le, - KWD_PIPE_SCH_DEADLINE_US, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# PCM Low Latency, id 0 -dnl PCM_PLAYBACK_ADD(name, pcm_id, playback) -PCM_DUPLEX_ADD(Port1, 0, PIPELINE_PCM_1, PIPELINE_PCM_2) -PCM_CAPTURE_ADD(DMIC, 1, PIPELINE_PCM_3) -PCM_PLAYBACK_ADD(HDMI1, 2, PIPELINE_PCM_4) -PCM_PLAYBACK_ADD(HDMI2, 3, PIPELINE_PCM_5) -PCM_PLAYBACK_ADD(HDMI3, 4, PIPELINE_PCM_6) - -# keyword detector pipe -dnl PIPELINE_PCM_ADD(pipeline, -dnl pipe id, pcm, max channels, format, -dnl period, priority, core, -dnl pcm_min_rate, pcm_max_rate, pipeline_rate, -dnl time_domain, sched_comp, dynamic) -PIPELINE_PCM_ADD(sof/pipe-detect.m4, - 9, 1, 2, s24le, - KWD_PIPE_SCH_DEADLINE_US, 1, 0, - 16000, 16000, 16000, - SCHEDULE_TIME_DOMAIN_TIMER, - PIPELINE_SCHED_COMP_8) - -# Connect pipelines together -SectionGraph."pipe-sof-cml-keyword-detect" { - index "0" - - lines [ - # keyword detect - dapm(PIPELINE_SINK_9, PIPELINE_SOURCE_8) - dapm(PIPELINE_PCM_8, PIPELINE_DETECT_9) - ] -} - -# -# BE configurations - overrides config in ACPI if present -# - -#SSP SSP_INDEX (ID: 0) -DAI_CONFIG(SSP, SSP_INDEX, 0, SSP_NAME, - SSP_CONFIG(I2S, SSP_CLOCK(mclk, SSP_MCLK_RATE, codec_mclk_in), - SSP_CLOCK(bclk, 2400000, codec_slave), - SSP_CLOCK(fsync, 48000, codec_slave), - SSP_TDM(2, 25, 3, 3), - SSP_CONFIG_DATA(SSP, SSP_INDEX, 24))) - -# dmic01 (ID: 1) -DAI_CONFIG(DMIC, 0, 1, dmic01, - DMIC_CONFIG(1, 2400000, 4800000, 40, 60, 48000, - DMIC_WORD_LENGTH(s32le), 400, DMIC, 0, - PDM_CONFIG(DMIC, 0, FOUR_CH_PDM0_PDM1))) - -# dmic16k (ID: 2) -DAI_CONFIG(DMIC, 1, 2, dmic16k, - DMIC_CONFIG(1, 2400000, 4800000, 40, 60, 16000, - DMIC_WORD_LENGTH(s32le), 400, DMIC, 1, - PDM_CONFIG(DMIC, 1, STEREO_PDM0))) - -# 3 HDMI/DP outputs (ID: 3,4,5) -DAI_CONFIG(HDA, 0, 3, iDisp1, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 0, 48000, 2))) -DAI_CONFIG(HDA, 1, 4, iDisp2, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 1, 48000, 2))) -DAI_CONFIG(HDA, 2, 5, iDisp3, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 2, 48000, 2))) - -DEBUG_END diff --git a/tools/topology/topology1/sof-cml-rt5682.m4 b/tools/topology/topology1/sof-cml-rt5682.m4 deleted file mode 100644 index ac928383ea08..000000000000 --- a/tools/topology/topology1/sof-cml-rt5682.m4 +++ /dev/null @@ -1,212 +0,0 @@ -# -# Topology for Cometlake with rt5682 codec. -# - -# Include topology builder -include(`utils.m4') -include(`dai.m4') -include(`pipeline.m4') -include(`ssp.m4') -include(`hda.m4') - -# Include TLV library -include(`common/tlv.m4') - -# Include Token library -include(`sof/tokens.m4') - -# Include Platform specific DSP configuration -include(`platform/intel/'PLATFORM`.m4') - -DEBUG_START - -# if XPROC is not defined, define with default pipe -ifdef(`HSMICPROC', , `define(HSMICPROC, volume)') -ifdef(`HSEARPROC', , `define(HSEARPROC, volume)') -ifdef(`DMICPROC', , `define(DMICPROC, passthrough)') -ifdef(`DMIC16KPROC', , `define(DMIC16KPROC, passthrough)') - -# -# Define the pipelines -# -`# PCM0 ---> 'HSEARPROC` ----> SSP(SSP_INDEX, BE link 0)' -`# PCM0 <--- 'HSMICPROC` <---- SSP(SSP_INDEX, BE link 0)' -`# PCM1 <--- 'DMICPROC` <----- DMIC01 (dmic0 capture, , BE link 1)' -# PCM2 ----> volume -----> iDisp1 (HDMI/DP playback, BE link 3) -# PCM3 ----> volume -----> iDisp2 (HDMI/DP playback, BE link 4) -# PCM4 ----> volume -----> iDisp3 (HDMI/DP playback, BE link 5) -`# PCM8 <---- 'DMIC16KPROC` <----- DMIC16k (dmic16k, BE link 2)' -# - -dnl PIPELINE_PCM_ADD(pipeline, -dnl pipe id, pcm, max channels, format, -dnl period, priority, core, -dnl pcm_min_rate, pcm_max_rate, pipeline_rate, -dnl time_domain, sched_comp) - -# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s24le. -# 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-`HSEARPROC'-playback.m4, - 1, 0, 2, s24le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s24le. -# 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-`HSMICPROC'-capture.m4, - 2, 0, 2, s24le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Passthrough capture pipeline 3 on PCM 1 using max 4 channels. -# 1000us deadline with priority 0 on core 0 -ifdef(`DMICPROC_FILTER1', `define(PIPELINE_FILTER1, DMICPROC_FILTER1)', `undefine(`PIPELINE_FILTER1')') -ifdef(`DMICPROC_FILTER2', `define(PIPELINE_FILTER2, DMICPROC_FILTER2)', `undefine(`PIPELINE_FILTER2')') -define(`PGA_NAME', Dmic0) - -PIPELINE_PCM_ADD(sof/pipe-`DMICPROC'-capture.m4, - 3, 1, 4, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -undefine(`PGA_NAME') -undefine(`PIPELINE_FILTER1') -undefine(`PIPELINE_FILTER2') - -# Low Latency playback pipeline 4 on PCM 2 using max 2 channels of s32le. -# 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 4, 2, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency playback pipeline 5 on PCM 3 using max 2 channels of s32le. -# 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 5, 3, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency playback pipeline 6 on PCM 4 using max 2 channels of s32le. -# 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 6, 4, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Passthrough capture pipeline 7 on PCM 5 using max 2 channels. -# Schedule 1000us deadline with priority 0 on core 0 -ifdef(`DMIC16KPROC_FILTER1', `define(PIPELINE_FILTER1, DMIC16KPROC_FILTER1)', `undefine(`PIPELINE_FILTER1')') -ifdef(`DMIC16KPROC_FILTER2', `define(PIPELINE_FILTER2, DMIC16KPROC_FILTER2)', `undefine(`PIPELINE_FILTER2')') -define(`PGA_NAME', Dmic1) - -PIPELINE_PCM_ADD(sof/pipe-`DMIC16KPROC'-capture-16khz.m4, - 8, 8, 2, s24le, - 1000, 0, 0, - 16000, 16000, 16000) - -undefine(`PGA_NAME') -undefine(`PIPELINE_FILTER1') -undefine(`PIPELINE_FILTER2') - -# -# DAIs configuration -# - -dnl DAI_ADD(pipeline, -dnl pipe id, dai type, dai_index, dai_be, -dnl buffer, periods, format, -dnl deadline, priority, core, time_domain) - -# playback DAI is SSP(SPP_INDEX) using 2 periods -# Buffers use s24le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 1, SSP, SSP_INDEX, SSP_NAME, - PIPELINE_SOURCE_1, 2, s24le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# capture DAI is SSP(SSP_INDEX) using 2 periods -# Buffers use s24le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-capture.m4, - 2, SSP,SSP_INDEX, SSP_NAME, - PIPELINE_SINK_2, 2, s24le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# capture DAI is DMIC01 using 2 periods -# Buffers use s32le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-capture.m4, - 3, DMIC, 0, dmic01, - PIPELINE_SINK_3, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp1 using 2 periods -# Buffers use s32le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 4, HDA, 0, iDisp1, - PIPELINE_SOURCE_4, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp2 using 2 periods -# Buffers use s32le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 5, HDA, 1, iDisp2, - PIPELINE_SOURCE_5, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp3 using 2 periods -# Buffers use s32le format, 1000us deadline with priority 0 on core 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 6, HDA, 2, iDisp3, - PIPELINE_SOURCE_6, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# capture DAI is DMIC16k using 2 periods -# Buffers use s32le format, with 16 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-capture.m4, - 8, DMIC, 1, dmic16k, - PIPELINE_SINK_8, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - - -# PCM Low Latency, id 0 -dnl PCM_PLAYBACK_ADD(name, pcm_id, playback) -PCM_DUPLEX_ADD(Port1, 0, PIPELINE_PCM_1, PIPELINE_PCM_2) -PCM_CAPTURE_ADD(DMIC, 1, PIPELINE_PCM_3) -PCM_PLAYBACK_ADD(HDMI1, 2, PIPELINE_PCM_4) -PCM_PLAYBACK_ADD(HDMI2, 3, PIPELINE_PCM_5) -PCM_PLAYBACK_ADD(HDMI3, 4, PIPELINE_PCM_6) -PCM_CAPTURE_ADD(DMIC16kHz, 8, PIPELINE_PCM_8) - -# -# BE configurations - overrides config in ACPI if present -# - -#SSP SSP_INDEX (ID: 0) -DAI_CONFIG(SSP, SSP_INDEX, 0, SSP_NAME, - SSP_CONFIG(I2S, SSP_CLOCK(mclk, SSP_MCLK_RATE, codec_mclk_in), - SSP_CLOCK(bclk, 2400000, codec_slave), - SSP_CLOCK(fsync, 48000, codec_slave), - SSP_TDM(2, 25, 3, 3), - SSP_CONFIG_DATA(SSP, SSP_INDEX, 24))) - -# dmic01 (ID: 1) -DAI_CONFIG(DMIC, 0, 1, dmic01, - DMIC_CONFIG(1, 2400000, 4800000, 40, 60, 48000, - DMIC_WORD_LENGTH(s32le), 400, DMIC, 0, - PDM_CONFIG(DMIC, 0, FOUR_CH_PDM0_PDM1))) - -# dmic16k (ID: 2) -DAI_CONFIG(DMIC, 1, 2, dmic16k, - DMIC_CONFIG(1, 2400000, 4800000, 40, 60, 16000, - DMIC_WORD_LENGTH(s32le), 400, DMIC, 1, - PDM_CONFIG(DMIC, 1, STEREO_PDM0))) - -# 3 HDMI/DP outputs (ID: 3,4,5) -DAI_CONFIG(HDA, 0, 3, iDisp1, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 0, 48000, 2))) -DAI_CONFIG(HDA, 1, 4, iDisp2, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 1, 48000, 2))) -DAI_CONFIG(HDA, 2, 5, iDisp3, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 2, 48000, 2))) - -DEBUG_END diff --git a/tools/topology/topology1/sof-ehl-rt5660.m4 b/tools/topology/topology1/sof-ehl-rt5660.m4 deleted file mode 100644 index 132740bbb10f..000000000000 --- a/tools/topology/topology1/sof-ehl-rt5660.m4 +++ /dev/null @@ -1,222 +0,0 @@ -# -# Topology for ELKHARTLAKE with rt5660 codec -# - -# Include topology builder -include(`utils.m4') -include(`dai.m4') -include(`pipeline.m4') -include(`ssp.m4') -include(`hda.m4') - -# Include TLV library -include(`common/tlv.m4') - -# Include Token library -include(`sof/tokens.m4') - -# Include Elkhartlake DSP configuration -include(`platform/intel/ehl.m4') -include(`platform/intel/dmic.m4') - -DEBUG_START - -# -# Define the pipelines -# -# PCM0 <---> volume <----> SSP0 BE dailink 0 -# PCM1 <---- volume <----- DMIC48k (dmic48k, BE dailink 1) - -ifelse(HDMI, `1', -` -# PCM2 ----> volume -----> iDisp1 (HDMI/DP playback, BE link 5) -# PCM3 ----> volume -----> iDisp2 (HDMI/DP playback, BE link 6) -# PCM4 ----> volume -----> iDisp3 (HDMI/DP playback, BE link 7) -# PCM5 ----> volume -----> iDisp3 (HDMI/DP playback, BE link 8) -') - -dnl PIPELINE_PCM_ADD(pipeline, -dnl pipe id, pcm, max channels, format, -dnl period, priority, core, -dnl pcm_min_rate, pcm_max_rate, pipeline_rate, -dnl time_domain, sched_comp) -# time_domain and sched_comp is used for a "branched" pipeline, -# which is not applicable in ehl-rt5660. - -# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le. -# Schedule 48 frames per 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 1, 0, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le. -# Schedule 48 frames per 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4, - 2, 0, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency capture pipeline 3 on PCM 1 using max 4 channels of s32le. -# Schedule 48 frames per 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4, - 3, 1, 4, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Passthrough capture pipeline 4 on PCM 3 using max 2 channels. -# Schedule 16 frames per 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4, - 4, 3, 2, s16le, - 1000, 0, 0, - 16000, 16000, 16000) - -ifelse(HDMI, `1', -` -# Low Latency playback pipeline 4 on PCM 2 using max 2 channels of s32le. -# Schedule 48 frames per 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 5, 2, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency playback pipeline 5 on PCM 3 using max 2 channels of s32le. -# Schedule 48 frames per 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 6, 3, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency playback pipeline 6 on PCM 4 using max 2 channels of s32le. -# Schedule 48 frames per 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 7, 4, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) - -# Low Latency playback pipeline 7 on PCM 5 using max 2 channels of s32le. -# Schedule 48 frames per 1000us deadline with priority 0 on core 0 -PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4, - 8, 5, 2, s32le, - 1000, 0, 0, - 48000, 48000, 48000) -') - -# -# DAIs configuration -# - -dnl DAI_ADD(pipeline, -dnl pipe id, dai type, dai_index, dai_be, -dnl buffer, periods, format, -dnl period , priority, core, time_domain) - -# playback DAI is SSP0 using 2 periods -# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 1, SSP, 0, SSP0-Codec, - PIPELINE_SOURCE_1, 2, s24le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# capture DAI is SSP0 using 2 periods -# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-capture.m4, - 2, SSP, 0, SSP0-Codec, - PIPELINE_SINK_2, 2, s24le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# capture DAI is DMIC48k using 2 periods -# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-capture.m4, - 3, DMIC, 0, dmic48k, - PIPELINE_SINK_3, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# capture DAI is DMIC16k using 2 periods -# Buffers use s16le format, with 16 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-capture.m4, - 4, DMIC, 1, dmic16k, - PIPELINE_SINK_4, 2, s16le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) -ifelse(HDMI, `1', -` -# playback DAI is iDisp1 using 2 periods -# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 5, HDA, 0, iDisp1, - PIPELINE_SOURCE_5, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp2 using 2 periods -# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 6, HDA, 1, iDisp2, - PIPELINE_SOURCE_6, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp3 using 2 periods -# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 7, HDA, 2, iDisp3, - PIPELINE_SOURCE_7, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) - -# playback DAI is iDisp4 using 2 periods -# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0 -DAI_ADD(sof/pipe-dai-playback.m4, - 8, HDA, 3, iDisp4, - PIPELINE_SOURCE_8, 2, s32le, - 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) -') - -# PCM Low Latency, id 0 -dnl PCM_PLAYBACK_ADD(name, pcm_id, playback) -PCM_DUPLEX_ADD(Headset, 0, PIPELINE_PCM_1, PIPELINE_PCM_2) -PCM_CAPTURE_ADD(DMIC, 1, PIPELINE_PCM_3) -PCM_CAPTURE_ADD(DMIC16kHz, 2, PIPELINE_PCM_4) - -ifelse(HDMI, `1', -` -PCM_PLAYBACK_ADD(HDMI1, 3, PIPELINE_PCM_5) -PCM_PLAYBACK_ADD(HDMI2, 4, PIPELINE_PCM_6) -PCM_PLAYBACK_ADD(HDMI3, 5, PIPELINE_PCM_7) -PCM_PLAYBACK_ADD(HDMI4, 6, PIPELINE_PCM_8) -') - -# -# BE configurations - overrides config in ACPI if present -# -#SSP 2 (ID: 0) -DAI_CONFIG(SSP, 0, 0, SSP0-Codec, - SSP_CONFIG(I2S, SSP_CLOCK(mclk, 9600000, codec_mclk_in), - SSP_CLOCK(bclk, 2400000, codec_slave), - SSP_CLOCK(fsync, 48000, codec_slave), - SSP_TDM(2, 25, 3, 3), - SSP_CONFIG_DATA(SSP, 0, 24))) - -# dmic48k (ID: 1) -DAI_CONFIG(DMIC, 0, 1, dmic48k, - DMIC_CONFIG(1, 2400000, 4800000, 40, 60, 48000, - DMIC_WORD_LENGTH(s32le), 400, DMIC, 0, - PDM_CONFIG(DMIC, 0, FOUR_CH_PDM0_PDM1))) - -# dmic16k (ID: 2) -DAI_CONFIG(DMIC, 1, 2, dmic16k, - DMIC_CONFIG(1, 2400000, 4800000, 40, 60, 16000, - DMIC_WORD_LENGTH(s16le), 400, DMIC, 1, - PDM_CONFIG(DMIC, 1, STEREO_PDM0))) - -ifelse(HDMI, `1', -` -# 4 HDMI/DP outputs (ID: 5,6,7,8) -DAI_CONFIG(HDA, 0, 5, iDisp1, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 0, 48000, 2))) -DAI_CONFIG(HDA, 1, 6, iDisp2, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 1, 48000, 2))) -DAI_CONFIG(HDA, 2, 7, iDisp3, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 2, 48000, 2))) -DAI_CONFIG(HDA, 3, 8, iDisp4, - HDA_CONFIG(HDA_CONFIG_DATA(HDA, 3, 48000, 2))) -') - -DEBUG_END diff --git a/tools/topology/topology2/cavs-benchmark-hda.conf b/tools/topology/topology2/cavs-benchmark-hda.conf index e47866791af5..ee6470447659 100644 --- a/tools/topology/topology2/cavs-benchmark-hda.conf +++ b/tools/topology/topology2/cavs-benchmark-hda.conf @@ -1,12 +1,9 @@ +<include/components/dcblock.conf> + Define { ANALOG_PLAYBACK_PCM 'Analog Playback' ANALOG_CAPTURE_PCM 'Analog Capture' - HDA_ANALOG_DAI_NAME 'Analog' - DEEP_BUFFER_PIPELINE_ID 15 - DEEP_BUFFER_PCM_ID 31 - DEEP_BUFFER_PIPELINE_SRC 'mixin.15.1' - DEEP_BUFFER_PIPELINE_SINK 'mixout.2.1' - DEEP_BUFFER_PCM_NAME 'Deepbuffer HDA Analog' + HDA_ANALOG_DAI_NAME 'Analog' } Object.Dai.HDA [ @@ -22,114 +19,6 @@ Object.Dai.HDA [ } ] -Object.Pipeline { - mixout-dai-copier-playback [ - { - index 3 - - Object.Widget.dai-copier.1 { - node_type $HDA_LINK_OUTPUT_CLASS - stream_name $HDA_ANALOG_DAI_NAME - dai_type "HDA" - copier_type "HDA" - } - } - ] - - mixout-aria-gain-mixin-playback [ - { - index 2 - - Object.Widget.gain.1 { - Object.Control.mixer.1 { - name 'Post Mixer $ANALOG_PLAYBACK_PCM Volume' - } - } - Object.Widget.aria.1 { - num_input_audio_formats 1 - num_output_audio_formats 1 - # 32-bit 48KHz 2ch - Object.Base.input_audio_format [ - { - in_bit_depth 32 - in_valid_bit_depth 32 - } - ] - Object.Base.output_audio_format [ - { - out_bit_depth 32 - out_valid_bit_depth 32 - } - ] - Object.Control.bytes."1" { - name "SSP2 Aria Control" - } - } - } - ] - - host-copier-gain-mixin-playback [ - { - index 1 - - Object.Widget.host-copier.1 { - stream_name $ANALOG_PLAYBACK_PCM - pcm_id 0 - } - - Object.Widget.gain.1 { - Object.Control.mixer.1 { - name 'Pre Mixer $ANALOG_PLAYBACK_PCM Volume' - } - } - } - ] - - host-gateway-capture [ - { - index 3 - Object.Widget.host-copier.1 { - stream_name $ANALOG_CAPTURE_PCM - pcm_id 0 - } - } - ] - - highpass-capture-be [ - { - index 4 - direction capture - - Object.Widget.dai-copier."1" { - dai_type "HDA" - type "dai_out" - copier_type "HDA" - stream_name $HDA_ANALOG_DAI_NAME - node_type $HDA_LINK_INPUT_CLASS - num_output_pins 1 - num_input_audio_formats 1 - num_output_audio_formats 1 - Object.Base.input_audio_format [ - { - in_bit_depth 32 - in_valid_bit_depth 32 - } - ] - Object.Base.output_audio_format [ - { - out_bit_depth 32 - out_valid_bit_depth 32 - } - ] - } - Object.Widget.eqiir.1 { - Object.Control.bytes."1" { - name '$ANALOG_CAPTURE_PCM IIR Eq' - } - } - } - ] -} Object.PCM.pcm [ { id 0 @@ -151,30 +40,207 @@ Object.PCM.pcm [ } ] -# top-level pipeline connections -Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'mixout.3.1' +IncludeByKey.BENCH_CONFIG { + "benchmark" { + Object.Pipeline { + mixout-dai-copier-playback [ + { + index 3 + + Object.Widget.dai-copier.1 { + node_type $HDA_LINK_OUTPUT_CLASS + stream_name $HDA_ANALOG_DAI_NAME + dai_type "HDA" + copier_type "HDA" + } + } + ] + + mixout-aria-gain-mixin-playback [ + { + index 2 + + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $ANALOG_PLAYBACK_PCM Volume' + } + } + Object.Widget.aria.1 { + num_input_audio_formats 1 + num_output_audio_formats 1 + # 32-bit 48KHz 2ch + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + Object.Control.bytes."1" { + name "SSP2 Aria Control" + } + } + } + ] + + host-copier-gain-mixin-playback [ + { + index 1 + + Object.Widget.host-copier.1 { + stream_name $ANALOG_PLAYBACK_PCM + pcm_id 0 + } + + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $ANALOG_PLAYBACK_PCM Volume' + } + } + } + ] + + host-gateway-capture [ + { + index 3 + Object.Widget.host-copier.1 { + stream_name $ANALOG_CAPTURE_PCM + pcm_id 0 + } + } + ] + + highpass-capture-be [ + { + index 4 + direction capture + + Object.Widget.dai-copier."1" { + dai_type "HDA" + type "dai_out" + copier_type "HDA" + stream_name $HDA_ANALOG_DAI_NAME + node_type $HDA_LINK_INPUT_CLASS + num_output_pins 1 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.eqiir.1 { + Object.Control.bytes."1" { + name '$ANALOG_CAPTURE_PCM IIR Eq' + } + } + } + ] + } + + # top-level pipeline connections + Object.Base.route [ + { + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + source 'mixout.3.1' + } + { + source 'mixin.2.1' + sink 'mixout.3.1' + } + { + source 'mixin.1.1' + sink 'mixout.2.1' + } + { + source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' + sink 'eqiir.4.1' + } + { + source 'eqiir.4.1' + sink 'host-copier.0.capture' + } + { + source 'host-copier.0.playback' + sink 'gain.1.1' + } + ] } - { - source 'mixin.2.1' - sink 'mixout.3.1' + + # + # DCblock component + # + + "dcblock16" { + <include/bench/dcblock_s16.conf> } - { - source 'mixin.1.1' - sink 'mixout.2.1' + + "dcblock24" { + <include/bench/dcblock_s24.conf> } - { - source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' - sink 'eqiir.4.1' + + "dcblock32" { + <include/bench/dcblock_s32.conf> } - { - source 'eqiir.4.1' - sink 'host-copier.0.capture' + + # + # DRC component + # + + "drc16" { + <include/bench/drc_s16.conf> } - { - source 'host-copier.0.playback' - sink 'gain.1.1' + + "drc24" { + <include/bench/drc_s24.conf> } -] + + "drc32" { + <include/bench/drc_s32.conf> + } + + # + # EQFIR component + # + + "eqfir16" { + <include/bench/eqfir_s16.conf> + } + + "eqfir24" { + <include/bench/eqfir_s24.conf> + } + + "eqfir32" { + <include/bench/eqfir_s32.conf> + } + + # + # EQIIR component + # + + "eqiir16" { + <include/bench/eqiir_s16.conf> + } + + "eqiir24" { + <include/bench/eqiir_s24.conf> + } + + "eqiir32" { + <include/bench/eqiir_s32.conf> + } +} diff --git a/tools/topology/topology2/cavs-mixin-mixout-efx-hda.conf b/tools/topology/topology2/cavs-mixin-mixout-efx-hda.conf index 076191afd289..2ce8e2fa2cbd 100644 --- a/tools/topology/topology2/cavs-mixin-mixout-efx-hda.conf +++ b/tools/topology/topology2/cavs-mixin-mixout-efx-hda.conf @@ -28,38 +28,81 @@ Object.Dai.HDA [ ] Object.Pipeline { - mixout-gain-efx-dai-copier-playback [ - { - index 2 + IncludeByKey.EFX_DRC_COMPONENT { + "singleband" { + mixout-gain-efx-dai-copier-playback [ + { + index 2 - Object.Widget.dai-copier.1 { - node_type $HDA_LINK_OUTPUT_CLASS - stream_name $HDA_ANALOG_DAI_NAME - dai_type "HDA" - copier_type "HDA" - } - Object.Widget.gain.1 { - Object.Control.mixer.1 { - name 'Post Mixer $ANALOG_PLAYBACK_PCM Volume' - } - } - Object.Widget.eqiir.1 { - Object.Control.bytes."1" { - name 'Post Mixer $ANALOG_PLAYBACK_PCM IIR Eq' - } - } - Object.Widget.eqfir.1 { - Object.Control.bytes."1" { - name 'Post Mixer $ANALOG_PLAYBACK_PCM FIR Eq' - } - } - Object.Widget.drc.1 { - Object.Control.bytes."1" { - name '2 Main playback DRC' - } - } - } - ] + Object.Widget.dai-copier.1 { + node_type $HDA_LINK_OUTPUT_CLASS + stream_name $HDA_ANALOG_DAI_NAME + dai_type "HDA" + copier_type "HDA" + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $ANALOG_PLAYBACK_PCM Volume' + } + } + Object.Widget.eqiir.1 { + Object.Control.bytes."1" { + name 'Post Mixer $ANALOG_PLAYBACK_PCM IIR Eq' + } + } + Object.Widget.eqfir.1 { + Object.Control.bytes."1" { + name 'Post Mixer $ANALOG_PLAYBACK_PCM FIR Eq' + } + } + Object.Widget.drc.1 { + Object.Control.bytes."1" { + name 'Post Mixer $ANALOG_PLAYBACK_PCM DRC' + } + } + } + ] + } + "multiband" { + mixout-gain-efx-mbdrc-dai-copier-playback [ + { + index 2 + + Object.Widget.dai-copier.1 { + node_type $HDA_LINK_OUTPUT_CLASS + stream_name $HDA_ANALOG_DAI_NAME + dai_type "HDA" + copier_type "HDA" + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $ANALOG_PLAYBACK_PCM Volume' + } + } + Object.Widget.eqiir.1 { + Object.Control.bytes."1" { + name 'Post Mixer $ANALOG_PLAYBACK_PCM IIR Eq' + } + } + Object.Widget.eqfir.1 { + Object.Control.bytes."1" { + name 'Post Mixer $ANALOG_PLAYBACK_PCM FIR Eq' + } + } + Object.Widget.multiband_drc.1 { + Object.Control { + bytes."1" { + name 'Post Mixer $ANALOG_PLAYBACK_PCM MBDRC bytes' + } + mixer."1" { + name 'Post Mixer $ANALOG_PLAYBACK_PCM MBDRC switch' + } + } + } + } + ] + } + } host-copier-gain-mixin-playback [ { @@ -140,21 +183,45 @@ Object.PCM.pcm [ ] # top-level pipeline connections -Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'drc.2.1' - } - { - source 'mixin.1.1' - sink 'mixout.2.1' - } - { - source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' - sink 'host-copier.0.capture' - } - { - source 'host-copier.0.playback' - sink 'gain.1.1' - } -] +IncludeByKey.EFX_DRC_COMPONENT { + "singleband" { + Object.Base.route [ + { + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + source 'drc.2.1' + } + { + source 'mixin.1.1' + sink 'mixout.2.1' + } + { + source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' + sink 'host-copier.0.capture' + } + { + source 'host-copier.0.playback' + sink 'gain.1.1' + } + ] + } + "multiband" { + Object.Base.route [ + { + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + source 'multiband_drc.2.1' + } + { + source 'mixin.1.1' + sink 'mixout.2.1' + } + { + source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' + sink 'host-copier.0.capture' + } + { + source 'host-copier.0.playback' + sink 'gain.1.1' + } + ] + } +} diff --git a/tools/topology/topology2/cavs-rt5682.conf b/tools/topology/topology2/cavs-rt5682.conf index f3cdc8d47aeb..070f1301920e 100644 --- a/tools/topology/topology2/cavs-rt5682.conf +++ b/tools/topology/topology2/cavs-rt5682.conf @@ -87,7 +87,6 @@ Define { INCLUDE_ECHO_REF false ECHO_REF_HOST_PIPELINE_ID 7 ECHO_REF_DAI_PIPELINE_ID 8 - ECHO_REF_COPIER_MODULE 'module-copier.8.2' ECHO_REF_PCM_ID 29 ECHO_REF_CORE_ID 0 # override BT default definitions @@ -96,13 +95,17 @@ Define { BT_PB_DAI_PIPELINE_SRC "copier.host.9.1" BT_PB_PIPELINE_STREAM_NAME "dai-copier.SSP.10.1" GOOGLE_RTC_AEC_SUPPORT 0 - GOOGLE_RTC_AEC_REF_SOURCE 'module-copier.8.2' GOOGLE_AEC_CORE_ID 0 HEADSET_PCM_NAME "Headset" HEADSET_PCM_ID 0 SPEAKER_PCM_NAME "Speakers" SPEAKER_PCM_ID 1 INCLUDE_BT_OFFLOAD true + GOOGLE_AEC_HOST_PIPELINE_PRIORITY 3 + GOOGLE_AEC_PIPELINE_PRIORITY 2 + DMIC_PIPELINE_PRIORITY 1 + ECHO_REF_PIPELINE_PRIORITY 0 + SSP_CLKS_CONTROL "0" } # override defaults with platform-specific config @@ -151,6 +154,7 @@ Object.Dai.SSP [ default_hw_conf_id 0 sample_bits 32 io_clk $MCLK + clks_control $SSP_CLKS_CONTROL Object.Base.hw_config.1 { name $HEADSET_HW_CONFIG_NAME @@ -179,6 +183,7 @@ Object.Dai.SSP [ default_hw_conf_id 0 sample_bits 32 io_clk $MCLK + clks_control $SSP_CLKS_CONTROL Object.Base.hw_config.1 { name $SPEAKER_HW_CONFIG_NAME diff --git a/tools/topology/topology2/cavs-sdw-src-gain-mixin.conf b/tools/topology/topology2/cavs-sdw-src-gain-mixin.conf index b4c5cc4244dd..17acf2ceac4f 100644 --- a/tools/topology/topology2/cavs-sdw-src-gain-mixin.conf +++ b/tools/topology/topology2/cavs-sdw-src-gain-mixin.conf @@ -120,11 +120,6 @@ Object.Pipeline { Object.Widget.host-copier.1 { stream_name "Passthrough Capture 0" pcm_id 1 - Object.Base.audio_format.1 { - # 32 -> 16 bits conversion is done here, - # so in_bit_depth is 32 (and out_bit_depth is 16). - in_bit_depth 32 - } } } ] diff --git a/tools/topology/topology2/development/tplg-targets.cmake b/tools/topology/topology2/development/tplg-targets.cmake index a2245db252a3..528b9af59450 100644 --- a/tools/topology/topology2/development/tplg-targets.cmake +++ b/tools/topology/topology2/development/tplg-targets.cmake @@ -81,6 +81,22 @@ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-efx-generic-4ch.bin,USE_CHAIN_DMA= DEEPBUFFER_FW_DMA_MS=100,EFX_FIR_PARAMS=passthrough,EFX_IIR_PARAMS=passthrough,\ EFX_DRC_PARAMS=passthrough" +"sof-hda-generic\;sof-hda-efx-mbdrc-generic\;\ +HDA_CONFIG=efx,USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100,\ +EFX_FIR_PARAMS=passthrough,EFX_IIR_PARAMS=passthrough,\ +EFX_DRC_COMPONENT=multiband,EFX_MBDRC_PARAMS=passthrough" + +"sof-hda-generic\;sof-hda-efx-mbdrc-generic-2ch\;\ +HDA_CONFIG=efx,NUM_DMICS=2,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-fir-generic-2ch.bin,\ +USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100,EFX_FIR_PARAMS=passthrough,EFX_IIR_PARAMS=passthrough,\ +EFX_DRC_COMPONENT=multiband,EFX_MBDRC_PARAMS=passthrough" + +"sof-hda-generic\;sof-hda-efx-mbdrc-generic-4ch\;\ +HDA_CONFIG=efx,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-hda-efx-generic-4ch.bin,USE_CHAIN_DMA=true,\ +DEEPBUFFER_FW_DMA_MS=100,EFX_FIR_PARAMS=passthrough,EFX_IIR_PARAMS=passthrough,\ +EFX_DRC_COMPONENT=multiband,EFX_MBDRC_PARAMS=passthrough" + # CAVS HDA topology with gain and SRC before mixin for HDA and passthrough pipelines for HDMI "sof-hda-generic\;sof-hda-src-generic\;HDA_CONFIG=src,USE_CHAIN_DMA=true,DEEPBUFFER_FW_DMA_MS=100" @@ -100,9 +116,23 @@ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-nocodec-bt-mtl-lbm.bin" # CAVS HDA topology for benchmarking performance # Copier - peak volume - mixin - mixout - aria - peak volume - mixin - mixout - copier -"sof-hda-generic\;sof-hda-benchmark-generic-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,USE_CHAIN_DMA=true" -"sof-hda-generic\;sof-hda-benchmark-generic-mtl\;PLATFORM=MTL,HDA_CONFIG=benchmark,USE_CHAIN_DMA=true" -"sof-hda-generic\;sof-hda-benchmark-generic-lnl\;PLATFORM=LNL,HDA_CONFIG=benchmark,USE_CHAIN_DMA=true" +"sof-hda-generic\;sof-hda-benchmark-generic-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,USE_CHAIN_DMA=true,BENCH_CONFIG=benchmark" +"sof-hda-generic\;sof-hda-benchmark-generic-mtl\;PLATFORM=MTL,HDA_CONFIG=benchmark,USE_CHAIN_DMA=true,BENCH_CONFIG=benchmark" +"sof-hda-generic\;sof-hda-benchmark-generic-lnl\;PLATFORM=LNL,HDA_CONFIG=benchmark,USE_CHAIN_DMA=true,BENCH_CONFIG=benchmark" + +# Test topologies for simple one source and sink processing components +"sof-hda-generic\;sof-hda-benchmark-dcblock16-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=dcblock16,BENCH_DCBLOCK_PARAMS=default" +"sof-hda-generic\;sof-hda-benchmark-dcblock24-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=dcblock24,BENCH_DCBLOCK_PARAMS=default" +"sof-hda-generic\;sof-hda-benchmark-dcblock32-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=dcblock32,BENCH_DCBLOCK_PARAMS=default" +"sof-hda-generic\;sof-hda-benchmark-drc16-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=drc16,BENCH_DRC_PARAMS=enabled" +"sof-hda-generic\;sof-hda-benchmark-drc24-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=drc24,BENCH_DRC_PARAMS=enabled" +"sof-hda-generic\;sof-hda-benchmark-drc32-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=drc32,BENCH_DRC_PARAMS=enabled" +"sof-hda-generic\;sof-hda-benchmark-eqiir16-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=eqiir16,BENCH_EQIIR_PARAMS=highpass_50hz_0db_48khz" +"sof-hda-generic\;sof-hda-benchmark-eqiir24-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=eqiir24,BENCH_EQIIR_PARAMS=highpass_50hz_0db_48khz" +"sof-hda-generic\;sof-hda-benchmark-eqiir32-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=eqiir32,BENCH_EQIIR_PARAMS=highpass_50hz_0db_48khz" +"sof-hda-generic\;sof-hda-benchmark-eqfir16-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=eqfir16,BENCH_EQFIR_PARAMS=loudness" +"sof-hda-generic\;sof-hda-benchmark-eqfir24-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=eqfir24,BENCH_EQFIR_PARAMS=loudness" +"sof-hda-generic\;sof-hda-benchmark-eqfir32-tgl\;PLATFORM=TGL,HDA_CONFIG=benchmark,BENCH_CONFIG=eqfir32,BENCH_EQFIR_PARAMS=loudness" # Topology to test IPC4 Crossover "development/cavs-nocodec-crossover\;sof-tgl-nocodec-crossover-2way\;PLATFORM=tgl,\ diff --git a/tools/topology/topology2/doc/CMakeLists.txt b/tools/topology/topology2/doc/CMakeLists.txt new file mode 100644 index 000000000000..303d06da3d15 --- /dev/null +++ b/tools/topology/topology2/doc/CMakeLists.txt @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.13) + +project(SOF_TOPOLOGY2_DOC NONE) + +set(SOF_ROOT_SOURCE_DIRECTORY "${PROJECT_SOURCE_DIR}/..") + +set(top_srcdir "${SOF_ROOT_SOURCE_DIRECTORY}") +set(top_bindir "${PROJECT_BINARY_DIR}") + +configure_file( + "${PROJECT_SOURCE_DIR}/sof.doxygen.in" + "${PROJECT_BINARY_DIR}/sof.doxygen" +) + +file(GLOB_RECURSE topology2_sources "${SOF_ROOT_SOURCE_DIRECTORY}/*.conf") +file(GLOB_RECURSE extra_sources "${PROJECT_SOURCE_DIR}/extra-contents/*.doxy") + +add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/contents.doxy + COMMAND ${PROJECT_SOURCE_DIR}/topology2-generate-contents.sh > ${PROJECT_BINARY_DIR}/contents.doxy + DEPENDS ${PROJECT_SOURCE_DIR}/topology2-generate-contents.sh + DEPENDS ${topology2_sources} + VERBATIM +) + +add_custom_target(doc-contents + DEPENDS ${PROJECT_BINARY_DIR}/contents.doxy +) + +add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/doxygen/html/index.html + COMMAND doxygen sof.doxygen + DEPENDS ${PROJECT_BINARY_DIR}/sof.doxygen + DEPENDS ${PROJECT_SOURCE_DIR}/topology2-filter.py + DEPENDS doc-contents + DEPENDS ${extra_sources} + DEPENDS ${topology2_sources} + VERBATIM + USES_TERMINAL +) + +add_custom_target(doc ALL + DEPENDS ${PROJECT_BINARY_DIR}/doxygen/html/index.html + VERBATIM +) diff --git a/tools/topology/topology2/doc/README b/tools/topology/topology2/doc/README new file mode 100644 index 000000000000..a412e1d2d707 --- /dev/null +++ b/tools/topology/topology2/doc/README @@ -0,0 +1,7 @@ +To build the topology2 source documentation do following steps: + +cd tools/topology/topology2/doc +cmake -B build/ +cmake --build build/ -v + +After the last command you should find the html documentation under: sof/tools/topology/topology2/doc/build/doxygen/html diff --git a/tools/topology/topology2/doc/extra-contents/mainpage.doxy b/tools/topology/topology2/doc/extra-contents/mainpage.doxy new file mode 100644 index 000000000000..4b2a2bfcabc8 --- /dev/null +++ b/tools/topology/topology2/doc/extra-contents/mainpage.doxy @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2023 Intel Corporation. All rights reserved. */ +/*! \mainpage Sound Open Firmware Topology2 + * + * \section this_document This Document + * + * This document is generated from SOF topology2 sources and its + * purpose is provide examples of how SOF ALSA topologies are built + * through instantiating toppology2 classes. + * + * The documentation is provided using Doxygen package and a Doxygen + * filter that translates the topology2 classes into C-structures. The + * filter is implemented in python and can be found from + * tools/topology/topology2/doc/topology2-filter.py + * + * The topology2 language syntax is described in detail <a + * href="https://thesofproject.github.io/latest/developer_guides/topology2/topology2.html">here</a>. + * + * \subsection doc_reading Reading the document + * + * The purpose of the translated C code is not to document actual + * topology2 code, but only to provide anchors for Doxygen to form a + * network of links through which to navigate the topology sources and + * find the pieces of related Doxygen documentation. The filter also + * creates separate pages of the original code and add links next to + * the pages in the C struct definition and instance documentation. + * + * The most essential part of the documentation is the documentation of + * classes that shown as C structs in this Doxygen documentation. + * + * \copydoc doc_contents + */ diff --git a/tools/topology/topology2/doc/sof.doxygen.in b/tools/topology/topology2/doc/sof.doxygen.in new file mode 100644 index 000000000000..d964c58258da --- /dev/null +++ b/tools/topology/topology2/doc/sof.doxygen.in @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-3-Clause +PROJECT_NAME = "Sound Open Firmware Topology2" +OUTPUT_DIRECTORY = doxygen +GENERATE_LATEX = NO +GENERATE_RTF = NO +GENERATE_MAN = NO +GENERATE_XML = YES + +CASE_SENSE_NAMES = NO +INPUT = @top_srcdir@ \ + @top_srcdir@/doc/extra-contents/ \ + @top_bindir@/contents.doxy + +RECURSIVE = YES +FILE_PATTERNS = *.conf +IMAGE_PATH = +QUIET = YES +WARN_LOGFILE = doxygen_warnings.txt + +EXTRACT_ALL = YES +EXTRACT_STATIC = YES +WARN_IF_UNDOCUMENTED = NO +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = YES +INHERIT_DOCS = YES + +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +OPTIMIZE_OUTPUT_FOR_C = YES + +HTML_TIMESTAMP = NO + +EXTENSION_MAPPING = conf=C,doxy=C +FILTER_PATTERNS = *.conf=@top_srcdir@/doc/topology2-filter.py diff --git a/tools/topology/topology2/doc/topology2-filter.py b/tools/topology/topology2/doc/topology2-filter.py new file mode 100755 index 000000000000..7ff465c66be7 --- /dev/null +++ b/tools/topology/topology2/doc/topology2-filter.py @@ -0,0 +1,745 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2023 Intel Corporation. All rights reserved. +# +# The usage of this command is simple. It takes one argument, a path +# to a SOF topology2 source file, and it produces to stdout something +# that can be parsed by Doxygen as C source. Produced output contains +# C struct definitions and instantiations analogous to the topology2 +# classes and object instances. +# +# The purpose of the translated C code is not to document actual +# topology2 code, but only to provide anchors for Doxygen to form a +# network of links through which to navigate the topology sources and +# find the pieces of related Doxygen documentation. The filter also +# creates separate pages of the original code and adds links next to the +# pages in the C struct definition, instance documentation and their +# possible Doxygen documentation. + +import sys +import os +import re +import io +import logging + +logging.basicConfig(filename='filter_debug.txt', filemode='a', encoding='utf-8', + level=logging.DEBUG) + +def fname(): + try: + name = sys._getframe(1).f_code.co_name + except (IndexError, TypeError, AttributeError): + name = "<unknown>" + return name + +def cbracket_count(line): + val = line.count("{") - line.count("}") + return val + +def sbracket_count(line): + val = line.count("[") - line.count("]") + return val + +def doxy_check_add(doxy, line): + if line.find("##") >= 0: + doxy = doxy + line[line.find("##"):].replace("##", "//!", 1) + if line.find("#") >= 0: + line = line[0:line.find("#")] + return (doxy, line) + +def print_doxy(doxy, file = sys.stdout): + if len(doxy): + print(doxy, file=file) + return "" + return doxy + +def parse_include_str(line): + if re.search(r"^\s*\<[A-Za-z0-9\/_\-\.]+\>\s*", line): + tok = line.split() + return "#include " + tok[0] + "\n" + return None + +def parse_include(line): + str = parse_include_str(line) + if str: + print(str) + return True + return False + +def parse_define_block(fline, instream): + """Parses topology2 Define { } block and outputs C-preprocessor #define macros + + Parameters: + fline (string): First input line that was read by the caller + instream (stream): Input stream of topology2 file we are decoding + + Returns: + string: The original code that was translated + """ + if re.search(r"^\s*Define\s+\{", fline): + logging.debug("fline: %s", fline) + doxy = "" + for line in instream: + if cbracket_count(line) < 0: + break + (doxy, line) = doxy_check_add(doxy, line) + doxy = print_doxy(doxy) + tok = line.split(maxsplit = 2) + if len(tok) < 2: + continue + val = trim_value(line[line.find(tok[0]) + len(tok[0]):]) + print("#define %s\t%s" % (trim_c_id(tok[0]), val)) + return True + return False + +def parse_include_by_key(fline, instream, file): # For now just skip + """Handles IncludeByKey { } blocks, currently handles only actual + includes, not nested {} blocks but everything is included into + raw_code return value. + + Parameters: + fline (string): First input line that was read by the caller + instream (stream): Input stream of topology2 file we are decoding + file (stream): Output stream for the translated output + + Returns: + string: The original code that was translated + + """ + if re.search(r"^\s*IncludeByKey\.", fline): + logging.debug("fline: %s", fline) + bsum = cbracket_count(fline) + if bsum == 1: + # Assume IncludeByKey.<variable> { + tok = fline.split() + tok = tok[0].split(".") + name = tok[1] + raw_code = "" + ifstr = "if" + for line in instream: + raw_code = raw_code + line + bsum = bsum + cbracket_count(line) + tok = line.split("\"") + if len(tok) >= 4: + print("#%s %s == \"%s\"\n#include <%s>" % + (ifstr, name, tok[1], tok[3]), file = file) + if ifstr == "if": + ifstr = "elif" + if bsum < 1: + if ifstr != "if": + print("#endif", file = file) + return raw_code + return None + +def trim_value(val): + val = val.strip(" \t\n$") + end = len(val) - 1 + if val[0:1] == "\"" and val[end:] == "\"": + return val + if val.isidentifier() or val.isnumeric(): + return val + if val[0:1] == "\'" and val[end:] == "\'": + val = val.strip("\'") + return "\"" + val + "\"" + +def trim_c_id(name): + name = name.strip(" \t\n\"\'") + name = name.replace("-", "_") + name = name.replace(" ", "_") + return name + + +def parse_attribute_constraints(instream, name): + """Parses a Constraints { } block and produces a C enum definition if possible + + Parameters: + instream (stream): Input stream of topology2 file we are decoding + name (string): Attribute name of this constraints block belongs to + + Returns: + string: C enum definition or an empty string + + """ + logging.debug("name: %s", name) + valid_values = [] + tuple_values = [] + doxy = "" # This is thrown away since there is no C anchror to connect it- + raw_code = "" + enum = "" + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if cbracket_count(line) < 0: + break + if re.search(r"^\s*\!valid_values\s+\[", line): + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + valid_values.append(trim_c_id(line)) + if re.search(r"^\s*\!tuple_values\s+\[", line): + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + tuple_values.append(trim_value(line)) + if len(valid_values) > 1 and len(valid_values) == len(tuple_values): + enum = "enum " + name + " {\n" + for i in range(len(valid_values)): + enum = enum + "\t\t" + valid_values[i] + " =\t" + tuple_values[i] + ",\n" + enum = enum + "\t}" + elif len(valid_values) > 1 and len(tuple_values) == 0: + enum = "enum " + name + " {\n" + for i in range(len(valid_values)): + enum = enum + "\t\t" + valid_values[i] + "," + if valid_values[i][0:1] == "$": # If its a variable add a reference to it + enum = enum + " //!< \\ref " + valid_values[i][1:] + enum = enum + "\n" + enum = enum + "\t}" + return (raw_code, enum) + +def parse_class_attribute(attributes, doxy, instream, fline): + """Parses a DefineAttribute { } block and collects the information into + attributes dict. Any already accumulated Doxygen documentation is + also stored there under the attribute name- + + Parameters: + attributes (dict): A dictionary where data about the attribute is stored + doxy (strung): Doxygen documentation collected just before the attribute + instream (stream): Input stream of topology2 file we are decoding + fline (string): First input line that was read by the caller + + Returns: + string: The original code that was translated + """ + logging.debug("fline: %s", fline) + tok = fline.split("\"") + if len(tok) > 1: + name = tok[1] + else: + tok = fline.split(".") + tok = tok[1].split(" ") + name = tok[0] + (doxy, fline) = doxy_check_add(doxy, fline) + bsum = cbracket_count(fline) + typestr = "" + token_ref = "" + ref_type = "" + enum = "" + raw_code = "" + if bsum < 1: + # Assume: DefineAttribute.name {} + typestr = "int" + else: + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + bsum = bsum + cbracket_count(line) + if bsum < 1: + break + if re.search(r"^\s*constraints\s+\{", line) and bsum == 2: + (code, enum) = parse_attribute_constraints(instream, name) + raw_code = raw_code + code + bsum = 1 + elif re.search(r"^\s*type\s", line): + tok = line.split() + typestr = tok[1].strip(" \t\n\"\'") + elif re.search(r"^\s*token_ref\s", line): + tok = line.split() + token_ref = tok[1].strip(" \t\n\"\'") + tok = token_ref.split(".") + ref_type = tok[1] + logging.debug("type %s token_ref %s ref_type %s enum %s", + typestr, token_ref, ref_type, enum) + if enum != "" and ref_type != "bool": + typestr = enum + if ref_type == "string": + doxy = doxy + "//! \\em string type\n" + elif typestr == "" or ref_type == "bool": + typestr = ref_type + attributes[name] = { "type": typestr, "doxy": doxy, "token_ref": token_ref } + return raw_code + +def print_attributes(attributes): + """Print out struct members and their doxygen documentation from attributes dict. + + Parameters: + attributes (dict): A dictionary where data about the attributes was stored + """ + for name in attributes: + doxy = "" + if attributes[name].get("doxy"): + doxy = attributes[name]["doxy"] + "\n" + if attributes[name].get("type"): + typestr = attributes[name]["type"] + print("%s\t%s %s;\n" % (doxy, typestr, name)) + +def set_attribute_flag(attributes, attribute, flag): + if not attributes.get(attribute): + attributes[attribute] = {} + attributes[attribute][flag] = True + +def parse_attributes_block(instream, attributes, attrib_doxy): + """Parse attributes block inside class definition and store the flags in attributes dict + + Parameters: + instream (stream): Input stream of topology2 file we are decoding + attributes (dict): Dict where data about the attributes is stored + attrib_doxy (dict): Dict to store doxygen docs associated with the attributes block + + Returns: + string: The original code that was translated + """ + logging.debug("called") + raw_code = "" + doxy = "" + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if cbracket_count(line) < 0: + break + if re.search(r"^\s*\!constructor\s+\[", line): + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + set_attribute_flag(attributes, trim_c_id(line), "constructor") + attrib_doxy["constructor"] = doxy + doxy = "" + elif re.search(r"^\s*\!mandatory\s+\[", line): + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + set_attribute_flag(attributes, trim_c_id(line), "mandatory") + attrib_doxy["mandatory"] = doxy + doxy = "" + elif re.search(r"^\s*\!immutable\s+\[", line): + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + set_attribute_flag(attributes, trim_c_id(line), "immutable") + attrib_doxy["immutable"] = doxy + doxy = "" + elif re.search(r"^\s*\!deprecated\s+\[", line): + attrib_doxy["deprecated"] = doxy + doxy = "" + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + set_attribute_flag(attributes, trim_c_id(line), "deprecated") + elif re.search(r"^\s*unique\s+", line): + tok = line.split() + attrib_doxy["unique"] = doxy + doxy = "" + set_attribute_flag(attributes, trim_c_id(tok[1]), "unique") + return raw_code + +def attribute_block_print(class_name, attributes, attrib_doxy): + """Generates a Doxygen documentation section from attribute flags + and doxygen docs stored to attrib_doxy + + Parameters: + class_name (string): Name of the class we are processing + attributes (dict): Dict where data about the attributes was stored + attrib_doxy (dict): Dict where doxygen docs of the attributes block was stored + + """ + logging.debug("class_name \'%s\'", class_name) + for field in attrib_doxy: + # Only add attribute paragraph if there are doxygen comment for it + if attrib_doxy[field] != "": + print("//! \\par %s attributes:\n//!" % field.capitalize()) + for attr in attributes: + if attributes[attr].get(field): + print("//! \\link %s::%s \\endlink \\n" % (class_name, attr)) + print("//! \\n\n%s" % attrib_doxy[field]) + +def attribute_block_info_add(attributes, attrib_doxy): + """Add simple bullets in the attribute (= struct members) documentation if + the attribute has constructor, mandatory, immutable, deprecated, or unique + property. + + Parameters: + attributes (dict): Dict where data about the attributes was stored + attrib_doxy (dict): Dict where doxygen docs of the attributes block was stored + + """ + # TODO: Add short documentation about the attribute properties and link to it. + for field in attrib_doxy: + for attr in attributes: + if attributes[attr].get(field): + if not attributes[attr].get("doxy"): + attributes[attr]["doxy"] = "" + attributes[attr]["doxy"] = "//! - \\em " + field + " attribute.\\n\n" + attributes[attr]["doxy"] + +def parse_class_contents(class_name, attributes, attrib_doxy, objs, defaults, + instream, includef = ""): + """Translates the contents inside a class definition { } block + + Parameters: + class_name (string): Class name + attributes (dict): Dict where data about the attributes is stored + attrib_doxy (dict): Dict to store doxygen docs associated with the attributes block + objs (dict): Dict to store fist level contained objects with Docxyge docs + defaults (streaM): Stream where the instances of the objects are printed + instream (stream): Input stream of topology2 file we are decoding + includef (string): Include file from where the attributes and objects inline included from + + Returns: + string: The original code that was translated + """ + bsum = 1 + doxy_addition = "" + if includef != "": + doxy_addition = "//! - Included from <" + includef + ">\\n\n" + doxy = "" + raw_code = "" + for line in instream: + raw_code = raw_code + line + if parse_include_str(line): + # Inline files that are included from within a class definition + filename = line[line.find("<") + 1:line.find(">")] + logging.debug("try to inline include \'%s\' from \'%s\'", + filename, os.getcwd()) + # NOTE: The path is relative to when the script exists so + # two levels up and we are at topology2 root + with open("../../" + filename, "r+", encoding="ascii") as ifile: + parse_class_contents(class_name, attributes, attrib_doxy, objs, + defaults, ifile, filename) + continue + if (code := parse_include_by_key(line, instream, sys.stdout)): + raw_code = raw_code + code + continue + if re.search(r"^\s*DefineAttribute\.", line): + doxy = doxy_addition + doxy + raw_code = raw_code + parse_class_attribute(attributes, doxy, instream, line) + doxy = "" + elif re.search(r"^\s*DefineArgument\.", line): + for line in instream: # Just skip, this is only used in bytes.conf + if cbracket_count(line) < 0: + break + elif re.search(r"^\s*attributes\s+\{", line): + doxy = "" # Doxy comments before attributes block end in weird places + raw_code = raw_code + parse_attributes_block(instream, attributes, attrib_doxy) + elif re.search(r"^\s*Object\.", line): + # TODO: Pass collected doxy comments to parse_object and store in objs + doxy = "" + raw_code = raw_code + parse_object(instream, line, file = defaults, + objects = objs, tabs = "\t", ending = ",") + else: # If nothing else matched, assume a default value definition for an attribute + (doxy, line) = doxy_check_add(doxy, line) + tok = line.split() + if len(tok) == 2 and tok[0].isidentifier(): + if doxy != "": + print(doxy, file = defaults) + doxy = "" + val = trim_value(line[line.find(tok[0]) + len(tok[0]):]) + print("\t.%s =\t%s," % (trim_c_id(tok[0]), val), + file = defaults) + bsum = bsum + cbracket_count(line) + if bsum < 1: + break + return raw_code + +def parse_class(instream, fline): + """Parse class definition and print out C struct definition + + Parameters: + fline (string): First input line that was read by the caller + instream (stream): Input stream of topology2 file we are decoding + """ + logging.debug("fline: %s", fline) + tok = fline.split(maxsplit = 2) + cdef = tok[0].split(".") + # base = cdef[1] # Just in case we go back to C++ tralation + class_name = cdef[2] + class_name = trim_c_id(class_name) + attributes = {} + attrib_doxy = {} + defaults = io.StringIO() + objs = {} + raw_code = fline + parse_class_contents(class_name, attributes, attrib_doxy, + objs, defaults, instream) + attribute_block_print(class_name, attributes, attrib_doxy) + attribute_block_info_add(attributes, attrib_doxy) + print("//! \\ref %s_rawcode" % class_name) + print("struct %s {" % class_name) + print_attributes(attributes) + for obj in objs: + if objs[obj]["count"] > 1: + for i in range(objs[obj]["count"]): + print(objs[obj]["doxy"][i]) + print("\tstruct %s %s%d;" % (obj, obj, i)) + else: + print(objs[obj]["doxy"][0]) + print("\tstruct %s %s;" % (obj, obj)) + print("};\n") + print("/*! \\page %s_rawcode The %s class definition in topology2 code\n\t\\code{.unparsed}" % + (class_name, class_name)) + print(raw_code) + print("\t\\endcode\n*/") + print("//! \\var struct %s %s_defaults" % (class_name, class_name)) + print("//! \\brief %s class default values" % class_name) + print("struct %s %s_defaults = {\n" % (class_name, class_name)) + print(defaults.getvalue()) + print("};\n") + defaults.close() + +def parse_members(instream, cbsum, tabs, file): + """Parse attribute initializations from object instantiation + + Parameters: + instream (stream): Input stream of topology2 file we are decoding + cbsum (int): The amount of curly brackets "{" WE HAVE OPEN + tabs (string): Current level of indentation + + Returns: + string: The original code that was translated + """ + doxy = "" + raw_code = "" + for line in instream: + raw_code = raw_code + line + if (code := parse_include_by_key(line, instream, file)): + raw_code = raw_code + code + continue + cbsum = cbsum + cbracket_count(line) + (doxy, line) = doxy_check_add(doxy, line) + # Assume ending } to be alone on its own line + if cbsum < 1: + break + if re.search(r"^\s*Object\.", line): + logging.debug("object-line: %s", line) + obj = line.split(".") + if cbsum == 2: + # Assume Object.Base.name.1 { + doxy = print_doxy(doxy, file = file) + raw_code = raw_code + parse_object(instream, line, file = file, tabs = tabs, ending = ",") + cbsum = 1 + elif cbsum == 1: + # Assume Object.Base.name.1 {} + doxy = print_doxy(doxy, file = file) + print("%s.%s = {}," % (tabs, obj[2]), file = file) + else: + tok = line.split(maxsplit = 1) + if len(tok) >=2: + name = tok[0] + val = trim_value(tok[1]) + doxy = print_doxy(doxy, file = file) + print("%s.%s = %s," % (tabs, name, val), file = file) + return raw_code + +# +def object_instance_prefix(name, ending): + """Decide "struct name name =" or ".name =" based on instantiation ending in ',' or ';' + + Parameters: + name (string): Name of the object instance + ending (string): Either ',' or ';' indication if this is an instance or a definition + + """ + if ending == ";": + return "struct " + name + " " + return "." + +def parse_object(instream, fline, file = sys.stdout, objects = {}, tabs = "", ending = ";"): + """Translates all Object instatiation into initialized C structs + Note that dict arguments in python are passed as reference + + Parameters: + instream (stream): Input stream of topology2 file we are decoding + fline (string): First input line that was read by the caller + file (stream): Where the C struct instance or definition is printed + objects (dict): Dict to store fist level contained objects with Docxyge docs + ending (string): Either ',' or ';' indication if this is an instance or a definition + tabs (string): Current level of indentation + + Returns: + string: The original code that was translated + """ + logging.debug("fline: %s", fline) + tok = fline.split(maxsplit = 2) + obj = tok[0].split(".") + cbsum = cbracket_count(fline) + sbsum = sbracket_count(fline) + name = "" + doxy = "" + raw_code = "" + if len(obj) == 4 and sbsum == 0 and cbsum == 0: + # Assume Object.Base.name.1 { } + name = obj[2] + name = trim_c_id(name) + doxy = print_doxy(doxy, file = file) + prefix = object_instance_prefix(name, ending) + print("%s%s = {}%s" % (prefix, name, ending), file = file) + objects[name] = { "count": 1, "doxy": [doxy] } + elif len(obj) == 4 and sbsum == 0 and cbsum == 1: + # Assume Object.Base.name.1 { + name = obj[2] + name = trim_c_id(name) + doxy = print_doxy(doxy, file = file) + prefix = object_instance_prefix(name, ending) + print("%s%s%s = {" % (tabs, prefix, name), file = file) + raw_code = raw_code + parse_members(instream, cbsum, tabs + "\t", file) + print("%s}%s" % (tabs, ending), file = file) + objects[name] = { "count": 1, "doxy": [doxy] } + elif len(obj) == 3 and sbsum == 1 and cbsum == 0: + # Assume Object.Base.name [ + name = obj[2] + name = trim_c_id(name) + doxy = print_doxy(doxy, file = file) + prefix = object_instance_prefix(name, ending) + print("%s%s%s[] = {" % (tabs, prefix, name), file = file) + objects[name] = { "count": 0, "doxy": [] } + for line in instream: + raw_code = raw_code + line + if parse_include(line): + continue + if (code := parse_include_by_key(line, instream, sys.stdout)): + raw_code = raw_code + code + continue + sbsum = sbsum + sbracket_count(line) + cbsum = cbsum + cbracket_count(line) + (doxy, line) = doxy_check_add(doxy, line) + if sbsum < 1: + print("%s}%s" % (tabs, ending), file = file) + break + if cbsum == 1: # Assume starting { on its own line + objects[name]["count"] = objects[name]["count"] + 1 + objects[name]["doxy"].append(doxy) + doxy = print_doxy(doxy, file = file) + print("%s\t{" % tabs, file = file) + raw_code = raw_code + parse_members(instream, cbsum, tabs + "\t\t", file) + cbsum = 0 + print("%s\t}," % tabs, file = file) + elif len(obj) == 2 and sbsum == 0 and cbsum == 1: + # Assume Object.Base { + for line in instream: + raw_code = raw_code + line + if parse_include(line): + continue + if (code := parse_include_by_key(line, instream, file)): + raw_code = raw_code + code + continue + sbsum = sbsum + sbracket_count(line) + cbsum = cbsum + cbracket_count(line) + (doxy, line) = doxy_check_add(doxy, line) + if cbsum < 1: # Ending } found + break + if sbsum == 1 and cbsum == 1 and sbracket_count(line) > 0: + # Assume Class_name [ + tok = line.split() + name = trim_c_id(tok[0]) + objects[name] = { "count": 0, "doxy": [] } + doxy = print_doxy(doxy, file = file) + prefix = object_instance_prefix(name, ending) + print("%s%s%s[] = {" % (tabs, prefix, name), file = file) + elif sbsum == 1 and cbsum == 2: + # Assume class_name [ \n { \n + objects[name]["count"] = objects[name]["count"] + 1 + objects[name]["doxy"].append(doxy) + doxy = print_doxy(doxy, file = file) + print("%s\t{" % tabs, file = file) + raw_code = raw_code + parse_members(instream, 1, tabs + "\t\t", file) + print("%s\t}," % tabs, file = file) + cbsum = 1 + elif sbsum == 0 and cbsum == 1 and sbracket_count(line) < 0: + # Assume ending ] of class table alone one its own line + print("%s}%s" % (tabs, ending), file = file) + elif sbsum == 0 and cbsum == 1 and line.count("}") == 1: + # Assume name."1" {} + # No init values, so no instantiation code needed, but we still need + # to store the object into objexts dict. + tok = line.split() + tok = tok[0].split(".") + name = trim_c_id(tok[0]) + if not objects.get(name): + objects[name] = { "count": 0, "doxy": [] } + objects[name]["count"] = objects[name]["count"] + 1 + objects[name]["doxy"].append(doxy) + doxy = print_doxy(doxy, file = file) + elif sbsum == 0 and cbsum == 2 and cbracket_count(line) == 1: + # Assume name."1" { + tok = line.split() + tok = tok[0].split(".") + name = trim_c_id(tok[0]) + mname = name + if len(tok) > 1: + idx = tok[1].strip(" \"\'") + if idx.isidentifier() or idx.isnumeric(): + mname = mname + "_" + idx + if not objects.get(name): + objects[name] = { "count": 0, "doxy": [] } + objects[name]["count"] = objects[name]["count"] + 1 + objects[name]["doxy"].append(doxy) + doxy = print_doxy(doxy, file = file) + prefix = object_instance_prefix(name, ending) + print("%s%s%s = {" % (tabs, prefix, mname), file = file) + raw_code = raw_code + parse_members(instream, 1, tabs + "\t", file) + cbsum = 1 + print("%s}%s" % (tabs, ending), file = file) + return raw_code + +def parse_object_and_make_raw_code_page(filename, index, instream, fline): + """Parses an object instance outputs its C equivalent, and creates a raw code page of + of it and prints a reference to it. Handles an "Object.... {}" instance completely + and produces possibly multiple initialized C structs, but always just one raw code + block containing the "Object.... {}" block completely. + + Parameters: + filename (stream): Name of the file we are paring + index (int): The index of the decoded Object block in this file we are handling + instream (stream): Input stream of topology2 file we are decoding + fline (string): First input line that was read by the caller + + """ + tok = filename.split("/") + filename = fname = tok[len(tok)-1] + fname = fname.replace("-", "_") + fname = fname.replace(".", "_") + c_instances = io.StringIO() + raw_code = fline + parse_object(instream, fline, c_instances) + print("/*! \\page %s_%d_rawcode The %s instances #%d in topology2 code\n\t\\code{.unparsed}" % + (fname, index, filename, index)) + print(raw_code) + print("\t\\endcode\n*/") + print("//! \\brief \\ref %s_%d_rawcode" % (fname, index)) + print(c_instances.getvalue()) + c_instances.close() + +# Main starts here, apart from debug file opening +filename = sys.argv[1] +logging.info("file: %s", filename) +with open(filename, "r+", encoding="ascii") as instream: + block_idx = 0 + + shortfname = filename[filename.find("/topology2/"):] + print("//! \\file %s" % shortfname[11:]) + print("//! Source file can be found " + + "<a href=\"https://github.com/thesofproject/sof/tree/main/tools/topology%s\">here</a>." + % shortfname) + for line in instream: + if parse_include(line): + continue + if parse_define_block(line, instream): + continue + if parse_include_by_key(line, instream, sys.stdout): + continue + if re.search(r"^\s*Class\.", line): + parse_class(instream, line) + elif re.search(r"^\s*Object\.", line): + parse_object_and_make_raw_code_page(filename, block_idx, instream, line) + block_idx = block_idx + 1 + elif line.find("##") >= 0: + sys.stdout.write(line.replace("##", "//!", 1)) + else: + sys.stdout.write("\n") diff --git a/tools/topology/topology2/doc/topology2-generate-contents.sh b/tools/topology/topology2/doc/topology2-generate-contents.sh new file mode 100755 index 000000000000..ea5b4ed059cb --- /dev/null +++ b/tools/topology/topology2/doc/topology2-generate-contents.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2023 Intel Corporation. All rights reserved. +# This script generates the contents page and stores it in extra-contents/contents.doxy + +set -e +cd "$(dirname "$0")" + +generate_contents () +{ + cat <<EOF +# This contents list is automatically generated by $0. +/*! \page doc_contents + \section doc_classes Classes +EOF + for ctype in Base Widget Control Dai Pipeline + do + echo " \subsection doc_${ctype,}_classes $ctype Classes" + find .. -name \*.conf -print0 | + xargs -0 awk "/^Class\.$ctype\./ "'{ + split($1, a, "\\."); + name = a[3]; gsub("\"", "", name); gsub("-", "_", name); + print "\t\\li \\ref " name + }' | sort -u + echo + done + + echo '*/' +} + +generate_contents diff --git a/tools/topology/topology2/include/bench/bench_comp_generate.sh b/tools/topology/topology2/include/bench/bench_comp_generate.sh new file mode 100755 index 000000000000..2fe84698360b --- /dev/null +++ b/tools/topology/topology2/include/bench/bench_comp_generate.sh @@ -0,0 +1,104 @@ +#!/bin/bash + +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2023 Intel Corporation. All rights reserved. + +set -e + +main () { + if [ "$#" -ne 1 ]; then + echo "Usage: $0 <component>" + exit 1 + fi + comp=$1 + FULL_CMD=( "$0" "$@" ) + generate_comp "s16" + generate_comp "s24" + generate_comp "s32" + generate_route + generate_playback_controls + generate_capture_controls +} + +generate_comp () +{ + format=$1 + fn=${comp}_${format}.conf + echo Creating file "$fn" + cat > "$fn" <<EOF_COMP + # Created with script "${FULL_CMD[@]}" + Object.Widget.${comp}.1 { + index 1 + <include/bench/one_input_output_format_${format}.conf> + <include/bench/${comp}_control_bytes_playback.conf> + } + Object.Widget.${comp}.2 { + index 3 + <include/bench/one_input_output_format_${format}.conf> + <include/bench/${comp}_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_${format}.conf> + <include/bench/${comp}_hda_route.conf> +EOF_COMP +} + +generate_route () +{ + fn=${comp}_hda_route.conf + echo Creating file "$fn" + cat > "$fn" <<EOF_ROUTE + # Created with script "${FULL_CMD[@]}" + Object.Base.route [ + { + sink 'dai-copier.HDA.\$HDA_ANALOG_DAI_NAME.playback' + source '${comp}.1.1' + } + { + sink '${comp}.1.1' + source 'host-copier.0.playback' + } + { + source 'dai-copier.HDA.\$HDA_ANALOG_DAI_NAME.capture' + sink '${comp}.3.2' + } + { + source '${comp}.3.2' + sink 'host-copier.0.capture' + } + ] +EOF_ROUTE +} + +generate_playback_controls () +{ + fn=${comp}_control_bytes_playback.conf + echo Creating file "$fn" + cat > "$fn" <<EOF_PLAYBACK_BYTES + # Created initially with script "${FULL_CMD[@]}" + # may need edits to modify controls + Object.Control.bytes."1" { + name '\$ANALOG_PLAYBACK_PCM ${comp^^} bytes' + IncludeByKey.BENCH_${comp^^}_PARAMS { + "default" "include/components/${comp}/default.conf" + } + } +EOF_PLAYBACK_BYTES +} + +generate_capture_controls () +{ + fn=${comp}_control_bytes_capture.conf + echo Creating file "$fn" + cat > "$fn" <<EOF_CAPTURE_BYTES + # Created initially with script "${FULL_CMD[@]}" + # may need edits to modify controls + Object.Control.bytes."1" { + name '\$ANALOG_CAPTURE_PCM ${comp^^} bytes' + IncludeByKey.BENCH_${comp^^}_PARAMS { + "default" "include/components/${comp}/default.conf" + } + } +EOF_CAPTURE_BYTES +} + +main "$@" diff --git a/tools/topology/topology2/include/bench/dcblock_control_bytes_capture.conf b/tools/topology/topology2/include/bench/dcblock_control_bytes_capture.conf new file mode 100644 index 000000000000..3d39d5cc8874 --- /dev/null +++ b/tools/topology/topology2/include/bench/dcblock_control_bytes_capture.conf @@ -0,0 +1,8 @@ + # Created initially with script "./bench_comp_generate.sh dcblock" + # may need edits to modify controls + Object.Control.bytes."1" { + name '$ANALOG_CAPTURE_PCM DCBLOCK bytes' + IncludeByKey.BENCH_DCBLOCK_PARAMS { + "default" "include/components/dcblock/default.conf" + } + } diff --git a/tools/topology/topology2/include/bench/dcblock_control_bytes_playback.conf b/tools/topology/topology2/include/bench/dcblock_control_bytes_playback.conf new file mode 100644 index 000000000000..09885bcf561f --- /dev/null +++ b/tools/topology/topology2/include/bench/dcblock_control_bytes_playback.conf @@ -0,0 +1,8 @@ + # Created initially with script "./bench_comp_generate.sh dcblock" + # may need edits to modify controls + Object.Control.bytes."1" { + name '$ANALOG_PLAYBACK_PCM DCBLOCK bytes' + IncludeByKey.BENCH_DCBLOCK_PARAMS { + "default" "include/components/dcblock/default.conf" + } + } diff --git a/tools/topology/topology2/include/bench/dcblock_hda_route.conf b/tools/topology/topology2/include/bench/dcblock_hda_route.conf new file mode 100644 index 000000000000..2b494c67e839 --- /dev/null +++ b/tools/topology/topology2/include/bench/dcblock_hda_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh dcblock" + Object.Base.route [ + { + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + source 'dcblock.1.1' + } + { + sink 'dcblock.1.1' + source 'host-copier.0.playback' + } + { + source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' + sink 'dcblock.3.2' + } + { + source 'dcblock.3.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/dcblock_s16.conf b/tools/topology/topology2/include/bench/dcblock_s16.conf new file mode 100644 index 000000000000..ae90114a2a16 --- /dev/null +++ b/tools/topology/topology2/include/bench/dcblock_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh dcblock" + Object.Widget.dcblock.1 { + index 1 + <include/bench/one_input_output_format_s16.conf> + <include/bench/dcblock_control_bytes_playback.conf> + } + Object.Widget.dcblock.2 { + index 3 + <include/bench/one_input_output_format_s16.conf> + <include/bench/dcblock_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s16.conf> + <include/bench/dcblock_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/dcblock_s24.conf b/tools/topology/topology2/include/bench/dcblock_s24.conf new file mode 100644 index 000000000000..ae24936a05a9 --- /dev/null +++ b/tools/topology/topology2/include/bench/dcblock_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh dcblock" + Object.Widget.dcblock.1 { + index 1 + <include/bench/one_input_output_format_s24.conf> + <include/bench/dcblock_control_bytes_playback.conf> + } + Object.Widget.dcblock.2 { + index 3 + <include/bench/one_input_output_format_s24.conf> + <include/bench/dcblock_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s24.conf> + <include/bench/dcblock_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/dcblock_s32.conf b/tools/topology/topology2/include/bench/dcblock_s32.conf new file mode 100644 index 000000000000..37bea24dd7a3 --- /dev/null +++ b/tools/topology/topology2/include/bench/dcblock_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh dcblock" + Object.Widget.dcblock.1 { + index 1 + <include/bench/one_input_output_format_s32.conf> + <include/bench/dcblock_control_bytes_playback.conf> + } + Object.Widget.dcblock.2 { + index 3 + <include/bench/one_input_output_format_s32.conf> + <include/bench/dcblock_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s32.conf> + <include/bench/dcblock_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/drc_control_bytes_capture.conf b/tools/topology/topology2/include/bench/drc_control_bytes_capture.conf new file mode 100644 index 000000000000..f688576394ac --- /dev/null +++ b/tools/topology/topology2/include/bench/drc_control_bytes_capture.conf @@ -0,0 +1,10 @@ + # Created initially with script "./bench_comp_generate.sh drc" + # may need edits to modify controls + Object.Control.bytes."1" { + name '$ANALOG_CAPTURE_PCM DRC bytes' + IncludeByKey.BENCH_DRC_PARAMS { + "default" "include/components/drc/default.conf" + "enabled" "include/components/drc/enabled.conf" + "passthrough" "include/components/drc/passthrough.conf" + } + } diff --git a/tools/topology/topology2/include/bench/drc_control_bytes_playback.conf b/tools/topology/topology2/include/bench/drc_control_bytes_playback.conf new file mode 100644 index 000000000000..ce7438e91410 --- /dev/null +++ b/tools/topology/topology2/include/bench/drc_control_bytes_playback.conf @@ -0,0 +1,10 @@ + # Created initially with script "./bench_comp_generate.sh drc" + # may need edits to modify controls + Object.Control.bytes."1" { + name '$ANALOG_PLAYBACK_PCM DRC bytes' + IncludeByKey.BENCH_DRC_PARAMS { + "default" "include/components/drc/default.conf" + "enabled" "include/components/drc/enabled.conf" + "passthrough" "include/components/drc/passthrough.conf" + } + } diff --git a/tools/topology/topology2/include/bench/drc_hda_route.conf b/tools/topology/topology2/include/bench/drc_hda_route.conf new file mode 100644 index 000000000000..8e9f475bd777 --- /dev/null +++ b/tools/topology/topology2/include/bench/drc_hda_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh drc" + Object.Base.route [ + { + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + source 'drc.1.1' + } + { + sink 'drc.1.1' + source 'host-copier.0.playback' + } + { + source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' + sink 'drc.3.2' + } + { + source 'drc.3.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/drc_s16.conf b/tools/topology/topology2/include/bench/drc_s16.conf new file mode 100644 index 000000000000..7d02416c1eac --- /dev/null +++ b/tools/topology/topology2/include/bench/drc_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh drc" + Object.Widget.drc.1 { + index 1 + <include/bench/one_input_output_format_s16.conf> + <include/bench/drc_control_bytes_playback.conf> + } + Object.Widget.drc.2 { + index 3 + <include/bench/one_input_output_format_s16.conf> + <include/bench/drc_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s16.conf> + <include/bench/drc_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/drc_s24.conf b/tools/topology/topology2/include/bench/drc_s24.conf new file mode 100644 index 000000000000..c0d9689a7908 --- /dev/null +++ b/tools/topology/topology2/include/bench/drc_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh drc" + Object.Widget.drc.1 { + index 1 + <include/bench/one_input_output_format_s24.conf> + <include/bench/drc_control_bytes_playback.conf> + } + Object.Widget.drc.2 { + index 3 + <include/bench/one_input_output_format_s24.conf> + <include/bench/drc_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s24.conf> + <include/bench/drc_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/drc_s32.conf b/tools/topology/topology2/include/bench/drc_s32.conf new file mode 100644 index 000000000000..0ca828c30ec4 --- /dev/null +++ b/tools/topology/topology2/include/bench/drc_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh drc" + Object.Widget.drc.1 { + index 1 + <include/bench/one_input_output_format_s32.conf> + <include/bench/drc_control_bytes_playback.conf> + } + Object.Widget.drc.2 { + index 3 + <include/bench/one_input_output_format_s32.conf> + <include/bench/drc_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s32.conf> + <include/bench/drc_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/eqfir_control_bytes_capture.conf b/tools/topology/topology2/include/bench/eqfir_control_bytes_capture.conf new file mode 100644 index 000000000000..a63e00c85ad9 --- /dev/null +++ b/tools/topology/topology2/include/bench/eqfir_control_bytes_capture.conf @@ -0,0 +1,10 @@ + # Created initially with script "./bench_comp_generate.sh eqfir" + # may need edits to modify controls + Object.Control.bytes."1" { + name '$ANALOG_CAPTURE_PCM EQFIR bytes' + IncludeByKey.BENCH_EQFIR_PARAMS { + "default" "include/components/eqfir/default.conf" + "loudness" "include/components/eqfir/loudness.conf" + "passthrough" "include/components/eqfir/passthrough.conf" + } + } diff --git a/tools/topology/topology2/include/bench/eqfir_control_bytes_playback.conf b/tools/topology/topology2/include/bench/eqfir_control_bytes_playback.conf new file mode 100644 index 000000000000..aa0c0c8da8ea --- /dev/null +++ b/tools/topology/topology2/include/bench/eqfir_control_bytes_playback.conf @@ -0,0 +1,10 @@ + # Created initially with script "./bench_comp_generate.sh eqfir" + # may need edits to modify controls + Object.Control.bytes."1" { + name '$ANALOG_PLAYBACK_PCM EQFIR bytes' + IncludeByKey.BENCH_EQFIR_PARAMS { + "default" "include/components/eqfir/default.conf" + "loudness" "include/components/eqfir/loudness.conf" + "passthrough" "include/components/eqfir/passthrough.conf" + } + } diff --git a/tools/topology/topology2/include/bench/eqfir_hda_route.conf b/tools/topology/topology2/include/bench/eqfir_hda_route.conf new file mode 100644 index 000000000000..fd30c793326c --- /dev/null +++ b/tools/topology/topology2/include/bench/eqfir_hda_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh eqfir" + Object.Base.route [ + { + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + source 'eqfir.1.1' + } + { + sink 'eqfir.1.1' + source 'host-copier.0.playback' + } + { + source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' + sink 'eqfir.3.2' + } + { + source 'eqfir.3.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/eqfir_s16.conf b/tools/topology/topology2/include/bench/eqfir_s16.conf new file mode 100644 index 000000000000..461323944062 --- /dev/null +++ b/tools/topology/topology2/include/bench/eqfir_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh eqfir" + Object.Widget.eqfir.1 { + index 1 + <include/bench/one_input_output_format_s16.conf> + <include/bench/eqfir_control_bytes_playback.conf> + } + Object.Widget.eqfir.2 { + index 3 + <include/bench/one_input_output_format_s16.conf> + <include/bench/eqfir_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s16.conf> + <include/bench/eqfir_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/eqfir_s24.conf b/tools/topology/topology2/include/bench/eqfir_s24.conf new file mode 100644 index 000000000000..ce2b303fe8f3 --- /dev/null +++ b/tools/topology/topology2/include/bench/eqfir_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh eqfir" + Object.Widget.eqfir.1 { + index 1 + <include/bench/one_input_output_format_s24.conf> + <include/bench/eqfir_control_bytes_playback.conf> + } + Object.Widget.eqfir.2 { + index 3 + <include/bench/one_input_output_format_s24.conf> + <include/bench/eqfir_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s24.conf> + <include/bench/eqfir_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/eqfir_s32.conf b/tools/topology/topology2/include/bench/eqfir_s32.conf new file mode 100644 index 000000000000..0e3dfa3732b4 --- /dev/null +++ b/tools/topology/topology2/include/bench/eqfir_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh eqfir" + Object.Widget.eqfir.1 { + index 1 + <include/bench/one_input_output_format_s32.conf> + <include/bench/eqfir_control_bytes_playback.conf> + } + Object.Widget.eqfir.2 { + index 3 + <include/bench/one_input_output_format_s32.conf> + <include/bench/eqfir_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s32.conf> + <include/bench/eqfir_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/eqiir_control_bytes_capture.conf b/tools/topology/topology2/include/bench/eqiir_control_bytes_capture.conf new file mode 100644 index 000000000000..a8b72846b969 --- /dev/null +++ b/tools/topology/topology2/include/bench/eqiir_control_bytes_capture.conf @@ -0,0 +1,9 @@ + # Created initially with script "./bench_comp_generate.sh eqiir" + # may need edits to modify controls + Object.Control.bytes."1" { + name '$ANALOG_CAPTURE_PCM EQIIR bytes' + IncludeByKey.BENCH_EQIIR_PARAMS { + "default" "include/components/eqiir/default.conf" + "highpass_50hz_0db_48khz" "include/components/eqiir/highpass_50hz_0db_48khz.conf" + } + } diff --git a/tools/topology/topology2/include/bench/eqiir_control_bytes_playback.conf b/tools/topology/topology2/include/bench/eqiir_control_bytes_playback.conf new file mode 100644 index 000000000000..5ae6ad905ee4 --- /dev/null +++ b/tools/topology/topology2/include/bench/eqiir_control_bytes_playback.conf @@ -0,0 +1,9 @@ + # Created initially with script "./bench_comp_generate.sh eqiir" + # may need edits to modify controls + Object.Control.bytes."1" { + name '$ANALOG_PLAYBACK_PCM EQIIR bytes' + IncludeByKey.BENCH_EQIIR_PARAMS { + "default" "include/components/eqiir/default.conf" + "highpass_50hz_0db_48khz" "include/components/eqiir/highpass_50hz_0db_48khz.conf" + } + } diff --git a/tools/topology/topology2/include/bench/eqiir_hda_route.conf b/tools/topology/topology2/include/bench/eqiir_hda_route.conf new file mode 100644 index 000000000000..5f066b741969 --- /dev/null +++ b/tools/topology/topology2/include/bench/eqiir_hda_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh eqiir" + Object.Base.route [ + { + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + source 'eqiir.1.1' + } + { + sink 'eqiir.1.1' + source 'host-copier.0.playback' + } + { + source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' + sink 'eqiir.3.2' + } + { + source 'eqiir.3.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/eqiir_s16.conf b/tools/topology/topology2/include/bench/eqiir_s16.conf new file mode 100644 index 000000000000..bcb01383e3d5 --- /dev/null +++ b/tools/topology/topology2/include/bench/eqiir_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh eqiir" + Object.Widget.eqiir.1 { + index 1 + <include/bench/one_input_output_format_s16.conf> + <include/bench/eqiir_control_bytes_playback.conf> + } + Object.Widget.eqiir.2 { + index 3 + <include/bench/one_input_output_format_s16.conf> + <include/bench/eqiir_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s16.conf> + <include/bench/eqiir_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/eqiir_s24.conf b/tools/topology/topology2/include/bench/eqiir_s24.conf new file mode 100644 index 000000000000..aa327545beec --- /dev/null +++ b/tools/topology/topology2/include/bench/eqiir_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh eqiir" + Object.Widget.eqiir.1 { + index 1 + <include/bench/one_input_output_format_s24.conf> + <include/bench/eqiir_control_bytes_playback.conf> + } + Object.Widget.eqiir.2 { + index 3 + <include/bench/one_input_output_format_s24.conf> + <include/bench/eqiir_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s24.conf> + <include/bench/eqiir_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/eqiir_s32.conf b/tools/topology/topology2/include/bench/eqiir_s32.conf new file mode 100644 index 000000000000..c6bf9b4e0fb7 --- /dev/null +++ b/tools/topology/topology2/include/bench/eqiir_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh eqiir" + Object.Widget.eqiir.1 { + index 1 + <include/bench/one_input_output_format_s32.conf> + <include/bench/eqiir_control_bytes_playback.conf> + } + Object.Widget.eqiir.2 { + index 3 + <include/bench/one_input_output_format_s32.conf> + <include/bench/eqiir_control_bytes_capture.conf> + } + <include/bench/host_io_gateway_pipelines_s32.conf> + <include/bench/eqiir_hda_route.conf> diff --git a/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s16.conf b/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s16.conf new file mode 100644 index 000000000000..b6ecea830367 --- /dev/null +++ b/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s16.conf @@ -0,0 +1,126 @@ + Object.Pipeline { + host-gateway-playback [ + { + index 1 + + Object.Widget.host-copier.1 { + stream_name $ANALOG_PLAYBACK_PCM + pcm_id 0 + num_input_audio_formats 3 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + ] + } + } + ] + + io-gateway [ + { + index 2 + direction playback + + Object.Widget.dai-copier.1 { + node_type $HDA_LINK_OUTPUT_CLASS + stream_name $HDA_ANALOG_DAI_NAME + dai_type "HDA" + copier_type "HDA" + num_input_pins 1 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + host-gateway-capture [ + { + index 3 + Object.Widget.host-copier.1 { + stream_name $ANALOG_CAPTURE_PCM + pcm_id 0 + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + io-gateway-capture [ + { + index 4 + direction capture + + Object.Widget.dai-copier."1" { + dai_type "HDA" + type "dai_out" + copier_type "HDA" + stream_name $HDA_ANALOG_DAI_NAME + node_type $HDA_LINK_INPUT_CLASS + num_output_pins 1 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + ] + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s24.conf b/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s24.conf new file mode 100644 index 000000000000..4cac2acd2b8b --- /dev/null +++ b/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s24.conf @@ -0,0 +1,126 @@ + Object.Pipeline { + host-gateway-playback [ + { + index 1 + + Object.Widget.host-copier.1 { + stream_name $ANALOG_PLAYBACK_PCM + pcm_id 0 + num_input_audio_formats 3 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 24 + } + ] + } + } + ] + + io-gateway [ + { + index 2 + direction playback + + Object.Widget.dai-copier.1 { + node_type $HDA_LINK_OUTPUT_CLASS + stream_name $HDA_ANALOG_DAI_NAME + dai_type "HDA" + copier_type "HDA" + num_input_pins 1 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 24 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + host-gateway-capture [ + { + index 3 + Object.Widget.host-copier.1 { + stream_name $ANALOG_CAPTURE_PCM + pcm_id 0 + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 24 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + io-gateway-capture [ + { + index 4 + direction capture + + Object.Widget.dai-copier."1" { + dai_type "HDA" + type "dai_out" + copier_type "HDA" + stream_name $HDA_ANALOG_DAI_NAME + node_type $HDA_LINK_INPUT_CLASS + num_output_pins 1 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 24 + } + ] + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s32.conf b/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s32.conf new file mode 100644 index 000000000000..c598efcd3e06 --- /dev/null +++ b/tools/topology/topology2/include/bench/host_io_gateway_pipelines_s32.conf @@ -0,0 +1,126 @@ + Object.Pipeline { + host-gateway-playback [ + { + index 1 + + Object.Widget.host-copier.1 { + stream_name $ANALOG_PLAYBACK_PCM + pcm_id 0 + num_input_audio_formats 3 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_bit_depth 32 + in_valid_bit_depth 24 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + io-gateway [ + { + index 2 + direction playback + + Object.Widget.dai-copier.1 { + node_type $HDA_LINK_OUTPUT_CLASS + stream_name $HDA_ANALOG_DAI_NAME + dai_type "HDA" + copier_type "HDA" + num_input_pins 1 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + host-gateway-capture [ + { + index 3 + Object.Widget.host-copier.1 { + stream_name $ANALOG_CAPTURE_PCM + pcm_id 0 + num_input_audio_formats 1 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + io-gateway-capture [ + { + index 4 + direction capture + + Object.Widget.dai-copier."1" { + dai_type "HDA" + type "dai_out" + copier_type "HDA" + stream_name $HDA_ANALOG_DAI_NAME + node_type $HDA_LINK_INPUT_CLASS + num_output_pins 1 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + } + diff --git a/tools/topology/topology2/include/bench/one_input_output_format_s16.conf b/tools/topology/topology2/include/bench/one_input_output_format_s16.conf new file mode 100644 index 000000000000..2f23335b7c6d --- /dev/null +++ b/tools/topology/topology2/include/bench/one_input_output_format_s16.conf @@ -0,0 +1,13 @@ + num_input_audio_formats 1 + num_output_audio_formats 1 + + # 32-bit 48KHz 2ch + Object.Base.audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + out_bit_depth 16 + out_valid_bit_depth 16 + } + ] + diff --git a/tools/topology/topology2/include/bench/one_input_output_format_s24.conf b/tools/topology/topology2/include/bench/one_input_output_format_s24.conf new file mode 100644 index 000000000000..4d83f5426dc1 --- /dev/null +++ b/tools/topology/topology2/include/bench/one_input_output_format_s24.conf @@ -0,0 +1,13 @@ + num_input_audio_formats 1 + num_output_audio_formats 1 + + # 32-bit 48KHz 2ch + Object.Base.audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 24 + out_bit_depth 32 + out_valid_bit_depth 24 + } + ] + diff --git a/tools/topology/topology2/include/bench/one_input_output_format_s32.conf b/tools/topology/topology2/include/bench/one_input_output_format_s32.conf new file mode 100644 index 000000000000..5ef867327013 --- /dev/null +++ b/tools/topology/topology2/include/bench/one_input_output_format_s32.conf @@ -0,0 +1,13 @@ + num_input_audio_formats 1 + num_output_audio_formats 1 + + # 32-bit 48KHz 2ch + Object.Base.audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + diff --git a/tools/topology/topology2/include/common/audio_format.conf b/tools/topology/topology2/include/common/audio_format.conf index 8ee2e6bed86c..d572f3c00085 100644 --- a/tools/topology/topology2/include/common/audio_format.conf +++ b/tools/topology/topology2/include/common/audio_format.conf @@ -1,43 +1,44 @@ -# Class definition for audio format object -# audio_format objects can be instantiated as: -# -# Object.Base.audio_format."0" { -# in_rate 48000 -# in_sample_container_size 16 -# in_valid_bit_depth 16 -# in_interleaving_style "interleaved" -# out_rate 48000 -# out_sample_container_size 16 -# out_valid_bit_depth 16 -# out_interleaving_style "interleaved" - -# } -# +## \struct audio_format +## \brief Class definition for audio format object +## +## audio_format objects can be instantiated as: +## +## Object.Base.audio_format."0" { +## in_rate 48000 +## in_sample_container_size 16 +## in_valid_bit_depth 16 +## in_interleaving_style "interleaved" +## out_rate 48000 +## out_sample_container_size 16 +## out_valid_bit_depth 16 +## out_interleaving_style "interleaved" +## } +## Class.Base."audio_format" { DefineAttribute."instance" { } - # input sampling rate + ## input sampling rate DefineAttribute."in_rate" { # Token set reference name token_ref "cavs_audio_format.word" } - # input bit depth + # #input bit depth DefineAttribute."in_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # input valid bit depth + ## input valid bit depth DefineAttribute."in_valid_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # input channel count + ## input channel count DefineAttribute."in_channels" { # Token set reference name token_ref "cavs_audio_format.word" @@ -47,19 +48,19 @@ Class.Base."audio_format" { } } - # input channel map + ## input channel map DefineAttribute."in_ch_map" { # Token set reference name token_ref "cavs_audio_format.word" } - # input channel config + ## input channel config DefineAttribute."in_ch_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } - # input interleaving style + ## input interleaving style DefineAttribute."in_interleaving_style" { type "string" # Token set reference name @@ -76,19 +77,20 @@ Class.Base."audio_format" { } } - # input format config + ## input format config DefineAttribute."in_fmt_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } - # output sampling rate + ## output sampling rate DefineAttribute."out_rate" { # Token set reference name token_ref "cavs_audio_format.word" } - # input sample_type + ## Input sample_type. + ## Valid values for sample type are defined in common_definitions.conf. DefineAttribute."in_sample_type" { type string # Token set reference name @@ -104,19 +106,19 @@ Class.Base."audio_format" { } } - # output bit depth + ## output bit depth DefineAttribute."out_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # output valid bit depth + ## output valid bit depth DefineAttribute."out_valid_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # output channel count + ## output channel count DefineAttribute."out_channels" { # Token set reference name token_ref "cavs_audio_format.word" @@ -126,19 +128,19 @@ Class.Base."audio_format" { } } - # output channel map + ## output channel map DefineAttribute."out_ch_map" { # Token set reference name token_ref "cavs_audio_format.word" } - # output channel config + ## output channel config DefineAttribute."out_ch_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } - # output interleaving style + ## output interleaving style DefineAttribute."out_interleaving_style" { type "string" # Token set reference name @@ -155,14 +157,14 @@ Class.Base."audio_format" { } } - # output format config + ## output format config DefineAttribute."out_fmt_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } # - # input buffer size + ## input buffer size # DefineAttribute."ibs" { # Token set reference name and type @@ -170,14 +172,15 @@ Class.Base."audio_format" { } # - # output buffer size + ## output buffer size # DefineAttribute."obs" { # Token set reference name and type token_ref "cavs_audio_format.word" } - #output sample_type + ## Output sample_type. + ## Valid values for sample type are defined in common_definitions.conf. DefineAttribute."out_sample_type" { type string # Token set reference name diff --git a/tools/topology/topology2/include/common/data.conf b/tools/topology/topology2/include/common/data.conf index 84655302224e..02900ee192a4 100644 --- a/tools/topology/topology2/include/common/data.conf +++ b/tools/topology/topology2/include/common/data.conf @@ -1,10 +1,12 @@ -# Class definition for data object -# Data objects can be instantiated as: -# -# Object.Base.data."SOF ABI" { -# bytes "0x3, 0x12,0x1" -# } -# +## \struct data +## \brief Class definition for data object +## +## Data objects can be instantiated as: +## +## Object.Base.data."SOF ABI" { +## bytes "0x3, 0x12,0x1" +## } +## Class.Base."data" { DefineAttribute."instance" {} diff --git a/tools/topology/topology2/include/common/fe_dai.conf b/tools/topology/topology2/include/common/fe_dai.conf index 8310c298c73b..e67d8aa4d22b 100644 --- a/tools/topology/topology2/include/common/fe_dai.conf +++ b/tools/topology/topology2/include/common/fe_dai.conf @@ -1,15 +1,17 @@ -# -# FE DAI Class definition. All attributes defined herein are namespaced -# by alsatplg to "Object.Base.fe_dai.instance.attribute_name". -# -# Usage: FE DAI objects can be instantiated as -# -# Object.Base.fe_dai.1 { -# id 0 -# } -# -# where NAME is the unique instance name for the FE DAI object within the -# same alsaconf node. +## \struct fe_dai +## \brief FE DAI Class definition +## +## All attributes defined herein are namespaced by alsatplg to +## "Object.Base.fe_dai.instance.attribute_name". +## +## Usage: FE DAI objects can be instantiated as +## +## Object.Base.fe_dai.1 { +## id 0 +## } +## +## where NAME is the unique instance name for the FE DAI object within the +## same alsaconf node. Class.Base."fe_dai" { diff --git a/tools/topology/topology2/include/common/input_audio_format.conf b/tools/topology/topology2/include/common/input_audio_format.conf index f5b9956d841b..795f3cdb46b0 100644 --- a/tools/topology/topology2/include/common/input_audio_format.conf +++ b/tools/topology/topology2/include/common/input_audio_format.conf @@ -1,14 +1,16 @@ -# Class definition for input pin audio format object -# audio_format objects can be instantiated as: -# -# Object.Base.input_audio_format."0" { -# in_rate 48000 -# in_sample_container_size 16 -# in_valid_bit_depth 16 -# in_interleaving_style "interleaved" - -# } -# +## \struct input_audio_format +## \brief Volume playback pipeline +## +## Class definition for input pin audio format object +## audio_format objects can be instantiated as: +## +## Object.Base.input_audio_format."0" { +## in_rate 48000 +## in_sample_container_size 16 +## in_valid_bit_depth 16 +## in_interleaving_style "interleaved" +## } +## Class.Base."input_audio_format" { @@ -20,25 +22,25 @@ Class.Base."input_audio_format" { token_ref "cavs_audio_format.word" } - # input sampling rate + ## input sampling rate DefineAttribute."in_rate" { # Token set reference name token_ref "cavs_audio_format.word" } - # input bit depth + ## input bit depth DefineAttribute."in_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # input valid bit depth + ## input valid bit depth DefineAttribute."in_valid_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # input channel count + ## input channel count DefineAttribute."in_channels" { # Token set reference name token_ref "cavs_audio_format.word" @@ -48,19 +50,19 @@ Class.Base."input_audio_format" { } } - # input channel map + ## input channel map DefineAttribute."in_ch_map" { # Token set reference name token_ref "cavs_audio_format.word" } - # input channel config + ## input channel config DefineAttribute."in_ch_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } - # input interleaving style + ## input interleaving style DefineAttribute."in_interleaving_style" { type "string" # Token set reference name @@ -77,13 +79,14 @@ Class.Base."input_audio_format" { } } - # input format config + ## input format config DefineAttribute."in_fmt_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } - # input sample_type + ## Input sample_type. + ## Valid values for sample type are defined in common_definitions.conf. DefineAttribute."in_sample_type" { type string # Token set reference name @@ -100,7 +103,7 @@ Class.Base."input_audio_format" { } # - # input buffer size + ## input buffer size # DefineAttribute."ibs" { # Token set reference name and type diff --git a/tools/topology/topology2/include/components/dcblock.conf b/tools/topology/topology2/include/components/dcblock.conf new file mode 100644 index 000000000000..4b0815173db3 --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock.conf @@ -0,0 +1,65 @@ +# +# +# A generic dcblock component. All attributes defined herein are namespaced +# by alsatplg to "Object.Widget.dcblock.attribute_name" +# +# Usage: this component can be used by declaring in the parent object. i.e. +# +# Object.Widget.dcblock."N" { +# index 1 +# } +# } + +# +# Where M is pipeline ID and N is a unique integer in the parent object. + +Class.Widget."dcblock" { + # + # Pipeline ID + # + DefineAttribute."index" { + type "integer" + } + + # + # Unique instance for EQ IIR widget + # + DefineAttribute."instance" { + type "integer" + } + + # Include common widget attributes definition + <include/components/widget-common.conf> + + attributes { + !constructor [ + "index" + "instance" + ] + !mandatory [ + "num_input_pins" + "num_output_pins" + "num_input_audio_formats" + "num_output_audio_formats" + ] + + !immutable [ + "uuid" + "type" + ] + !deprecated [ + "preload_count" + ] + unique "instance" + } + + # + # Default attributes for dcblock + # + # b809efaf-5681-42b1-9ed6-04bb012dd384 + uuid "af:ef:09:b8:81:56:b1:42:9e:d6:04:bb:01:2d:d3:84" + type "effect" + no_pm "true" + num_input_pins 1 + num_output_pins 1 +} diff --git a/tools/topology/topology2/include/components/dcblock/100hz_16khz.conf b/tools/topology/topology2/include/components/dcblock/100hz_16khz.conf new file mode 100644 index 000000000000..9bda1ed41447 --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/100hz_16khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x41,0xe3,0x6f,0x3d,0x41,0xe3,0x6f,0x3d, + 0x41,0xe3,0x6f,0x3d,0x41,0xe3,0x6f,0x3d, + 0x41,0xe3,0x6f,0x3d,0x41,0xe3,0x6f,0x3d, + 0x41,0xe3,0x6f,0x3d,0x41,0xe3,0x6f,0x3d" +} diff --git a/tools/topology/topology2/include/components/dcblock/100hz_48khz.conf b/tools/topology/topology2/include/components/dcblock/100hz_48khz.conf new file mode 100644 index 000000000000..82c09e90b9c3 --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/100hz_48khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x92,0x20,0x28,0x3f,0x92,0x20,0x28,0x3f, + 0x92,0x20,0x28,0x3f,0x92,0x20,0x28,0x3f, + 0x92,0x20,0x28,0x3f,0x92,0x20,0x28,0x3f, + 0x92,0x20,0x28,0x3f,0x92,0x20,0x28,0x3f" +} diff --git a/tools/topology/topology2/include/components/dcblock/200hz_16khz.conf b/tools/topology/topology2/include/components/dcblock/200hz_16khz.conf new file mode 100644 index 000000000000..cc869bb12fd5 --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/200hz_16khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x73,0x09,0xc6,0x3a,0x73,0x09,0xc6,0x3a, + 0x73,0x09,0xc6,0x3a,0x73,0x09,0xc6,0x3a, + 0x73,0x09,0xc6,0x3a,0x73,0x09,0xc6,0x3a, + 0x73,0x09,0xc6,0x3a,0x73,0x09,0xc6,0x3a" +} diff --git a/tools/topology/topology2/include/components/dcblock/200hz_48khz.conf b/tools/topology/topology2/include/components/dcblock/200hz_48khz.conf new file mode 100644 index 000000000000..c4c9046f82ea --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/200hz_48khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xd4,0x6d,0x4d,0x3e,0xd4,0x6d,0x4d,0x3e, + 0xd4,0x6d,0x4d,0x3e,0xd4,0x6d,0x4d,0x3e, + 0xd4,0x6d,0x4d,0x3e,0xd4,0x6d,0x4d,0x3e, + 0xd4,0x6d,0x4d,0x3e,0xd4,0x6d,0x4d,0x3e" +} diff --git a/tools/topology/topology2/include/components/dcblock/20hz_16khz.conf b/tools/topology/topology2/include/components/dcblock/20hz_16khz.conf new file mode 100644 index 000000000000..165ae2968d23 --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/20hz_16khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x7c,0xd0,0x7e,0x3f,0x7c,0xd0,0x7e,0x3f, + 0x7c,0xd0,0x7e,0x3f,0x7c,0xd0,0x7e,0x3f, + 0x7c,0xd0,0x7e,0x3f,0x7c,0xd0,0x7e,0x3f, + 0x7c,0xd0,0x7e,0x3f,0x7c,0xd0,0x7e,0x3f" +} diff --git a/tools/topology/topology2/include/components/dcblock/20hz_48khz.conf b/tools/topology/topology2/include/components/dcblock/20hz_48khz.conf new file mode 100644 index 000000000000..d7b8198218ad --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/20hz_48khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xf6,0x0c,0xd5,0x3f,0xf6,0x0c,0xd5,0x3f, + 0xf6,0x0c,0xd5,0x3f,0xf6,0x0c,0xd5,0x3f, + 0xf6,0x0c,0xd5,0x3f,0xf6,0x0c,0xd5,0x3f, + 0xf6,0x0c,0xd5,0x3f,0xf6,0x0c,0xd5,0x3f" +} diff --git a/tools/topology/topology2/include/components/dcblock/30hz_16khz.conf b/tools/topology/topology2/include/components/dcblock/30hz_16khz.conf new file mode 100644 index 000000000000..bc5013ac9acd --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/30hz_16khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x63,0xd7,0x3d,0x3f,0x63,0xd7,0x3d,0x3f, + 0x63,0xd7,0x3d,0x3f,0x63,0xd7,0x3d,0x3f, + 0x63,0xd7,0x3d,0x3f,0x63,0xd7,0x3d,0x3f, + 0x63,0xd7,0x3d,0x3f,0x63,0xd7,0x3d,0x3f" +} diff --git a/tools/topology/topology2/include/components/dcblock/30hz_48khz.conf b/tools/topology/topology2/include/components/dcblock/30hz_48khz.conf new file mode 100644 index 000000000000..c4a21f83a10c --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/30hz_48khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xa6,0x88,0xbf,0x3f,0xa6,0x88,0xbf,0x3f, + 0xa6,0x88,0xbf,0x3f,0xa6,0x88,0xbf,0x3f, + 0xa6,0x88,0xbf,0x3f,0xa6,0x88,0xbf,0x3f, + 0xa6,0x88,0xbf,0x3f,0xa6,0x88,0xbf,0x3f" +} diff --git a/tools/topology/topology2/include/components/dcblock/40hz_16khz.conf b/tools/topology/topology2/include/components/dcblock/40hz_16khz.conf new file mode 100644 index 000000000000..5552350b9da3 --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/40hz_16khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3c,0x9d,0xfc,0x3e,0x3c,0x9d,0xfc,0x3e, + 0x3c,0x9d,0xfc,0x3e,0x3c,0x9d,0xfc,0x3e, + 0x3c,0x9d,0xfc,0x3e,0x3c,0x9d,0xfc,0x3e, + 0x3c,0x9d,0xfc,0x3e,0x3c,0x9d,0xfc,0x3e" +} diff --git a/tools/topology/topology2/include/components/dcblock/40hz_48khz.conf b/tools/topology/topology2/include/components/dcblock/40hz_48khz.conf new file mode 100644 index 000000000000..77b497ba73a1 --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/40hz_48khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x22,0xfd,0xa9,0x3f,0x22,0xfd,0xa9,0x3f, + 0x22,0xfd,0xa9,0x3f,0x22,0xfd,0xa9,0x3f, + 0x22,0xfd,0xa9,0x3f,0x22,0xfd,0xa9,0x3f, + 0x22,0xfd,0xa9,0x3f,0x22,0xfd,0xa9,0x3f" +} diff --git a/tools/topology/topology2/include/components/dcblock/50hz_16khz.conf b/tools/topology/topology2/include/components/dcblock/50hz_16khz.conf new file mode 100644 index 000000000000..81e6cf5db9ea --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/50hz_16khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe6,0x21,0xbb,0x3e,0xe6,0x21,0xbb,0x3e, + 0xe6,0x21,0xbb,0x3e,0xe6,0x21,0xbb,0x3e, + 0xe6,0x21,0xbb,0x3e,0xe6,0x21,0xbb,0x3e, + 0xe6,0x21,0xbb,0x3e,0xe6,0x21,0xbb,0x3e" +} diff --git a/tools/topology/topology2/include/components/dcblock/50hz_48khz.conf b/tools/topology/topology2/include/components/dcblock/50hz_48khz.conf new file mode 100644 index 000000000000..ced86dd64d0e --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/50hz_48khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x6a,0x6a,0x94,0x3f,0x6a,0x6a,0x94,0x3f, + 0x6a,0x6a,0x94,0x3f,0x6a,0x6a,0x94,0x3f, + 0x6a,0x6a,0x94,0x3f,0x6a,0x6a,0x94,0x3f, + 0x6a,0x6a,0x94,0x3f,0x6a,0x6a,0x94,0x3f" +} diff --git a/tools/topology/topology2/include/components/dcblock/80hz_16khz.conf b/tools/topology/topology2/include/components/dcblock/80hz_16khz.conf new file mode 100644 index 000000000000..0bb539df5288 --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/80hz_16khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x96,0x27,0xf5,0x3d,0x96,0x27,0xf5,0x3d, + 0x96,0x27,0xf5,0x3d,0x96,0x27,0xf5,0x3d, + 0x96,0x27,0xf5,0x3d,0x96,0x27,0xf5,0x3d, + 0x96,0x27,0xf5,0x3d,0x96,0x27,0xf5,0x3d" +} diff --git a/tools/topology/topology2/include/components/dcblock/80hz_48khz.conf b/tools/topology/topology2/include/components/dcblock/80hz_48khz.conf new file mode 100644 index 000000000000..7be93fe17c22 --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/80hz_48khz.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xfa,0x86,0x53,0x3f,0xfa,0x86,0x53,0x3f, + 0xfa,0x86,0x53,0x3f,0xfa,0x86,0x53,0x3f, + 0xfa,0x86,0x53,0x3f,0xfa,0x86,0x53,0x3f, + 0xfa,0x86,0x53,0x3f,0xfa,0x86,0x53,0x3f" +} diff --git a/tools/topology/topology2/include/components/dcblock/default.conf b/tools/topology/topology2/include/components/dcblock/default.conf new file mode 100644 index 000000000000..cbadfc6c6cbd --- /dev/null +++ b/tools/topology/topology2/include/components/dcblock/default.conf @@ -0,0 +1,13 @@ +# Exported with script example_dcblock.m 04-Oct-2023 +# cd tools/tune/dcblock; octave example_dcblock.m +Object.Base.data."dcblock_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xec,0x51,0xb8,0x3e,0xec,0x51,0xb8,0x3e, + 0xec,0x51,0xb8,0x3e,0xec,0x51,0xb8,0x3e, + 0xec,0x51,0xb8,0x3e,0xec,0x51,0xb8,0x3e, + 0xec,0x51,0xb8,0x3e,0xec,0x51,0xb8,0x3e" +} diff --git a/tools/topology/topology2/include/components/gain.conf b/tools/topology/topology2/include/components/gain.conf index 395edb64ba94..9167c7df546b 100644 --- a/tools/topology/topology2/include/components/gain.conf +++ b/tools/topology/topology2/include/components/gain.conf @@ -1,29 +1,29 @@ -# -# Common pipeline gain (volume) -# -# A generic gain (volume) widget. All attributes defined herein are namespaced -# by alsatplg to "Object.Widget.gain.N.attribute_name" -# -# Usage: this component can be used by declaring int a parent object. i.e. -# -# Object.Widget.gain."N" { -# index 1 -# format s24le -# no_pm "true" -# } -# -# Where N is the unique instance number for gain widget in the same alsaconf node. +## \struct gain +## \brief Common pipeline gain (volume) +## +## A generic gain (volume) widget. All attributes defined herein are namespaced +## by alsatplg to "Object.Widget.gain.N.attribute_name" +## +## Usage: this component can be used by declaring int a parent object. i.e. +## +## Object.Widget.gain."N" { +## index 1 +## format s24le +## no_pm "true" +## } +## +## Where N is the unique instance number for gain widget in the same alsaconf node. <include/controls/mixer.conf> Class.Widget."gain" { # - # Pipeline ID for the gain widget object + ## Pipeline ID for the gain widget object # DefineAttribute."index" {} # - # gain object instance + ## gain object instance # DefineAttribute."instance" {} @@ -35,9 +35,9 @@ Class.Widget."gain" { # # - # Gain curve type. The values provided will be translated to integer values - # as specified in the tuple_values array. - # For example: "linear" is translated to 0, "log" to 1 etc. + ## Gain curve type. The values provided will be translated to integer values + ## as specified in the tuple_values array. + ## For example: "linear" is translated to 0, "log" to 1 etc. # DefineAttribute."curve_type" { type "string" @@ -45,18 +45,26 @@ Class.Widget."gain" { token_ref "gain.word" constraints { !valid_values [ - "no_fade" - "fade" + "windows_no_fade" + "windows_fade" + "linear" + "log" + "linear_zc" + "log_zc" ] !tuple_values [ 0 1 + 2 + 3 + 4 + 5 ] } } # - # Gain curve in milliseconds + ## Gain curve in milliseconds # DefineAttribute."curve_duration" { # Token set reference name @@ -71,8 +79,8 @@ Class.Widget."gain" { # Attribute categories attributes { # - # The PGA widget name would be constructed using the index and instance attributes. - # For ex: "gain.1.1" or "gain.10.2" etc. + ## The PGA widget name would be constructed using the index and instance attributes. + ## For ex: "gain.1.1" or "gain.10.2" etc. # !constructor [ "index" @@ -114,9 +122,9 @@ Class.Widget."gain" { # gain widget mixer controls # Object.Control { - # gain mixer control + ## gain mixer control mixer."1" { - #Channel register and shift for Front Left/Right + ## Channel register and shift for Front Left/Right Object.Base.channel.1 { name "fl" shift 0 @@ -128,7 +136,7 @@ Class.Widget."gain" { Object.Base.ops.1 { name "ctl" info "volsw" - #256 binds the mixer control to volume get/put handlers + ## get = 256 binds the mixer control to volume get/put handlers get 256 put 256 } @@ -151,7 +159,7 @@ Class.Widget."gain" { uuid "A8:A9:BC:61:D0:18:18:4A:8E:7B:26:39:21:98:04:B7" no_pm "true" cpc 10183 - curve_type "fade" + curve_type "windows_fade" curve_duration 200000 # 20 ms init_value 0x7fffffff num_input_pins 1 diff --git a/tools/topology/topology2/include/components/google-rtc-aec.conf b/tools/topology/topology2/include/components/google-rtc-aec.conf index e2df7a9dbeac..2d6ed613b469 100644 --- a/tools/topology/topology2/include/components/google-rtc-aec.conf +++ b/tools/topology/topology2/include/components/google-rtc-aec.conf @@ -87,35 +87,47 @@ Class.Widget."google-rtc-aec" { unique "instance" } - num_audio_formats 2 - num_input_audio_formats 2 - num_output_audio_formats 1 + num_input_audio_formats 3 + num_output_audio_formats 2 # pin0 is the data captured by DMIC and pin1 is the ref data from playback stream - Object.Base.input_audio_format { - 1 { + Object.Base.input_audio_format [ + # 2ch 16-bit on Pin 0 + { input_pin_index 0 in_bit_depth 16 in_valid_bit_depth 16 - out_bit_depth 16 - out_valid_bit_depth 16 } - 2 { + # 4ch 16-bit on Pin 0 + { + input_pin_index 0 + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + # 2ch 16-bit on Pin 1 + { input_pin_index 1 in_bit_depth 16 in_valid_bit_depth 16 + } + ] + + Object.Base.output_audio_format [ + { out_bit_depth 16 out_valid_bit_depth 16 } - } - - Object.Base.output_audio_format { - 1 { - in_bit_depth 16 - in_valid_bit_depth 16 + # 4ch 16-bit + { out_bit_depth 16 out_valid_bit_depth 16 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 } - } + ] # Default attribute values for google-rtc-aec widget # UUID: B780A0A6-269F-466F-B477-23DFA05AF758 diff --git a/tools/topology/topology2/include/components/google-rtc-aec/rtc-aec-blob.conf b/tools/topology/topology2/include/components/google-rtc-aec/rtc-aec-blob.conf deleted file mode 100644 index f31ed7a0a747..000000000000 --- a/tools/topology/topology2/include/components/google-rtc-aec/rtc-aec-blob.conf +++ /dev/null @@ -1,19 +0,0 @@ -# aec blob data - -Object.Base.data."google-rtc-aec_blob" { - bytes " - 0x53, 0x4f, 0x46, 0x34, 0x00, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x80, 0xbb, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x10, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, - - 0x80, 0xbb, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x10, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00" -} diff --git a/tools/topology/topology2/include/components/multiband_drc.conf b/tools/topology/topology2/include/components/multiband_drc.conf new file mode 100644 index 000000000000..d363e930e77b --- /dev/null +++ b/tools/topology/topology2/include/components/multiband_drc.conf @@ -0,0 +1,85 @@ +# +# +# A generic MULTIBAND_DRC component. All attributes defined herein are namespaced +# by alsatplg to "Object.Widget.multiband_drc.attribute_name" +# +# Usage: this component can be used by declaring in the parent object. i.e. +# +# Object.Widget.multiband_drc."N" { +# index 1 +# } +# } + +# +# Where M is pipeline ID and N is a unique integer in the parent object. + +Class.Widget."multiband_drc" { + # + # Pipeline ID + # + DefineAttribute."index" { + type "integer" + } + + # + # Unique instance for MULTIBAND_DRC widget + # + DefineAttribute."instance" { + type "integer" + } + + # Include common widget attributes definition + <include/components/widget-common.conf> + + attributes { + !constructor [ + "index" + "instance" + ] + !mandatory [ + "num_input_pins" + "num_output_pins" + "num_input_audio_formats" + "num_output_audio_formats" + ] + + !immutable [ + "uuid" + "type" + ] + !deprecated [ + "preload_count" + ] + unique "instance" + } + + # + # multiband_drc widget switch control + # + Object.Control { + mixer."1" { + Object.Base.channel.1 { + name "fc" + shift 0 + } + Object.Base.ops.1 { + name "ctl" + info "volsw" + #259 binds the mixer control to switch get/put handlers + get 259 + put 259 + } + max 1 + } + } + + # + # Default attributes for multiband_drc + # + + uuid "56:22:9f:0d:4f:8e:b3:47:84:48:23:9a:33:4f:11:91" + type "effect" + no_pm "true" + num_input_pins 1 + num_output_pins 1 +} diff --git a/tools/topology/topology2/include/components/multiband_drc/default.conf b/tools/topology/topology2/include/components/multiband_drc/default.conf new file mode 100644 index 000000000000..e42467528301 --- /dev/null +++ b/tools/topology/topology2/include/components/multiband_drc/default.conf @@ -0,0 +1,82 @@ +# Exported with script example_multiband_drc.m 01-Sep-2023 +Object.Base.data."multiband_drc_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x4c,0x02,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x4c,0x02,0x00,0x00,0x03,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x7b,0x8e,0x88,0xfe, + 0x36,0x79,0x57,0x17,0x5f,0x19,0x6f,0x06, + 0xe8,0x79,0x67,0xd4,0x00,0x00,0x00,0x40, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x5f,0x6d,0x19,0xe7,0x39,0xc4,0xd4,0x50, + 0x0c,0x9b,0x09,0x24,0xad,0x76,0x82,0x9f, + 0x00,0x00,0x00,0x40,0xff,0xff,0xff,0xff, + 0x43,0x72,0x00,0x00,0xa1,0xe6,0x90,0xf9, + 0x18,0x86,0x98,0x2b,0xe3,0x32,0xef,0x00, + 0x4b,0xf7,0x20,0xf1,0x18,0x69,0xc6,0x28, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0xf4,0x64,0xf6,0xdb,0x53,0x89,0x7d,0x60, + 0x5c,0x14,0xf2,0x0a,0x84,0x0d,0x78,0xdc, + 0xda,0xef,0x21,0x1c,0x00,0x00,0x00,0x00, + 0x00,0x40,0x00,0x00,0x6f,0x82,0x53,0xc2, + 0x3e,0x77,0xa1,0x7d,0x95,0xc1,0x02,0x00, + 0x2a,0x83,0x05,0x00,0x95,0xc1,0x02,0x00, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x6f,0x82,0x53,0xc2,0x3e,0x77,0xa1,0x7d, + 0x34,0x7d,0xd3,0x3e,0x99,0x05,0x59,0x82, + 0x34,0x7d,0xd3,0x3e,0x00,0x00,0x00,0x00, + 0x00,0x40,0x00,0x00,0x2d,0x3a,0xcd,0xd3, + 0xc0,0xf5,0x82,0x68,0x05,0xf4,0xeb,0x00, + 0x0a,0xe8,0xd7,0x01,0x05,0xf4,0xeb,0x00, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x2d,0x3a,0xcd,0xd3,0xc0,0xf5,0x82,0x68, + 0xe5,0x6e,0x2d,0x35,0x36,0x22,0xa5,0x95, + 0xe5,0x6e,0x2d,0x35,0x00,0x00,0x00,0x00, + 0x00,0x40,0x00,0x00,0x2d,0x3a,0xcd,0xd3, + 0xc0,0xf5,0x82,0x68,0x05,0xf4,0xeb,0x00, + 0x0a,0xe8,0xd7,0x01,0x05,0xf4,0xeb,0x00, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x2d,0x3a,0xcd,0xd3,0xc0,0xf5,0x82,0x68, + 0xe5,0x6e,0x2d,0x35,0x36,0x22,0xa5,0x95, + 0xe5,0x6e,0x2d,0x35,0x00,0x00,0x00,0x00, + 0x00,0x40,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0xe8,0x00,0x00,0x00,0x1e, + 0x00,0x00,0x00,0x0c,0xd3,0x4d,0x62,0x00, + 0xb1,0xc2,0x09,0x04,0x55,0x55,0x55,0x05, + 0x50,0xfa,0x1e,0x00,0x55,0x60,0x94,0x00, + 0x7e,0x98,0x6a,0xff,0x83,0xc9,0xfe,0x01, + 0x64,0x47,0x47,0x22,0x17,0x56,0x74,0x01, + 0x1c,0xc7,0x71,0x00,0x77,0x77,0x77,0xff, + 0xd8,0x77,0x1f,0x00,0x05,0x00,0x00,0x00, + 0x00,0x00,0x36,0x00,0xdf,0x97,0x03,0x00, + 0xe7,0x3e,0x1e,0x00,0xdf,0x97,0x07,0x00, + 0x5b,0x91,0x00,0x00,0x02,0x00,0x00,0x00, + 0x00,0x00,0x00,0xe8,0x00,0x00,0x00,0x1e, + 0x00,0x00,0x00,0x0c,0xd3,0x4d,0x62,0x00, + 0xb1,0xc2,0x09,0x04,0x55,0x55,0x55,0x05, + 0x50,0xfa,0x1e,0x00,0x55,0x60,0x94,0x00, + 0x7e,0x98,0x6a,0xff,0x83,0xc9,0xfe,0x01, + 0x64,0x47,0x47,0x22,0x17,0x56,0x74,0x01, + 0x1c,0xc7,0x71,0x00,0x77,0x77,0x77,0xff, + 0xd8,0x77,0x1f,0x00,0x05,0x00,0x00,0x00, + 0x00,0x00,0x36,0x00,0xdf,0x97,0x03,0x00, + 0xe7,0x3e,0x1e,0x00,0xdf,0x97,0x07,0x00, + 0x5b,0x91,0x00,0x00,0x03,0x00,0x00,0x00, + 0x00,0x00,0x00,0xe8,0x00,0x00,0x00,0x1e, + 0x00,0x00,0x00,0x0c,0xd3,0x4d,0x62,0x00, + 0xb1,0xc2,0x09,0x04,0x55,0x55,0x55,0x05, + 0x50,0xfa,0x1e,0x00,0x55,0x60,0x94,0x00, + 0x7e,0x98,0x6a,0xff,0x83,0xc9,0xfe,0x01, + 0x64,0x47,0x47,0x22,0x17,0x56,0x74,0x01, + 0x1c,0xc7,0x71,0x00,0x77,0x77,0x77,0xff, + 0xd8,0x77,0x1f,0x00,0x05,0x00,0x00,0x00, + 0x00,0x00,0x36,0x00,0xdf,0x97,0x03,0x00, + 0xe7,0x3e,0x1e,0x00,0xdf,0x97,0x07,0x00, + 0x5b,0x91,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/multiband_drc/passthrough.conf b/tools/topology/topology2/include/components/multiband_drc/passthrough.conf new file mode 100644 index 000000000000..09cb3c4f4ac8 --- /dev/null +++ b/tools/topology/topology2/include/components/multiband_drc/passthrough.conf @@ -0,0 +1,71 @@ +# Exported with script example_multiband_drc.m 01-Sep-2023 +Object.Base.data."multiband_drc_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0xf4,0x01,0x00,0x00,0x00,0xa0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xf4,0x01,0x00,0x00,0x02,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x7b,0x8e,0x88,0xfe, + 0x36,0x79,0x57,0x17,0x5f,0x19,0x6f,0x06, + 0xe8,0x79,0x67,0xd4,0x00,0x00,0x00,0x40, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x5f,0x6d,0x19,0xe7,0x39,0xc4,0xd4,0x50, + 0x0c,0x9b,0x09,0x24,0xad,0x76,0x82,0x9f, + 0x00,0x00,0x00,0x40,0xff,0xff,0xff,0xff, + 0x43,0x72,0x00,0x00,0xa1,0xe6,0x90,0xf9, + 0x18,0x86,0x98,0x2b,0xe3,0x32,0xef,0x00, + 0x4b,0xf7,0x20,0xf1,0x18,0x69,0xc6,0x28, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0xf4,0x64,0xf6,0xdb,0x53,0x89,0x7d,0x60, + 0x5c,0x14,0xf2,0x0a,0x84,0x0d,0x78,0xdc, + 0xda,0xef,0x21,0x1c,0x00,0x00,0x00,0x00, + 0x00,0x40,0x00,0x00,0x6f,0x82,0x53,0xc2, + 0x3e,0x77,0xa1,0x7d,0x95,0xc1,0x02,0x00, + 0x2a,0x83,0x05,0x00,0x95,0xc1,0x02,0x00, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x6f,0x82,0x53,0xc2,0x3e,0x77,0xa1,0x7d, + 0x34,0x7d,0xd3,0x3e,0x99,0x05,0x59,0x82, + 0x34,0x7d,0xd3,0x3e,0x00,0x00,0x00,0x00, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40, + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xe8,0x00,0x00,0x00,0x1e, + 0x00,0x00,0x00,0x0c,0xd3,0x4d,0x62,0x00, + 0xb1,0xc2,0x09,0x04,0x55,0x55,0x55,0x05, + 0x50,0xfa,0x1e,0x00,0x55,0x60,0x94,0x00, + 0x7e,0x98,0x6a,0xff,0x83,0xc9,0xfe,0x01, + 0x64,0x47,0x47,0x22,0x17,0x56,0x74,0x01, + 0x1c,0xc7,0x71,0x00,0x77,0x77,0x77,0xff, + 0xd8,0x77,0x1f,0x00,0x05,0x00,0x00,0x00, + 0x00,0x00,0x36,0x00,0xdf,0x97,0x03,0x00, + 0xe7,0x3e,0x1e,0x00,0xdf,0x97,0x07,0x00, + 0x5b,0x91,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xe8,0x00,0x00,0x00,0x1e, + 0x00,0x00,0x00,0x0c,0xd3,0x4d,0x62,0x00, + 0xb1,0xc2,0x09,0x04,0x55,0x55,0x55,0x05, + 0x50,0xfa,0x1e,0x00,0x55,0x60,0x94,0x00, + 0x7e,0x98,0x6a,0xff,0x83,0xc9,0xfe,0x01, + 0x64,0x47,0x47,0x22,0x17,0x56,0x74,0x01, + 0x1c,0xc7,0x71,0x00,0x77,0x77,0x77,0xff, + 0xd8,0x77,0x1f,0x00,0x05,0x00,0x00,0x00, + 0x00,0x00,0x36,0x00,0xdf,0x97,0x03,0x00, + 0xe7,0x3e,0x1e,0x00,0xdf,0x97,0x07,0x00, + 0x5b,0x91,0x00,0x00" +} diff --git a/tools/topology/topology2/include/components/widget-common.conf b/tools/topology/topology2/include/components/widget-common.conf index af87e4e70f7d..3c398300ef89 100644 --- a/tools/topology/topology2/include/components/widget-common.conf +++ b/tools/topology/topology2/include/components/widget-common.conf @@ -2,12 +2,12 @@ # Common widget attribute definitions # -# instance of the widget object +## instance of the widget object DefineAttribute."instance" {} # -# no_pm - maps to the DAPM widget's reg field -# "false" value indicates that there is no direct DAPM for this widget +## no_pm - maps to the DAPM widget's reg field +## "false" value indicates that there is no direct DAPM for this widget # DefineAttribute."no_pm" { type "string" @@ -20,26 +20,26 @@ DefineAttribute."no_pm" { } # -# Widget Type - maps to the widget ID with values of type enum SND_SOC_TPLG_DAPM_* +## Widget Type - maps to the widget ID with values of type enum SND_SOC_TPLG_DAPM_* # DefineAttribute."type" { type "string" } # -# Stream name - maps to the DAPM widget's stream name +## Stream name - maps to the DAPM widget's stream name # DefineAttribute."stream_name" { type "string" } # -# Event type widget binds to +## Event type widget binds to # DefineAttribute.event_type {} # -# Widget event flags +## Widget event flags # DefineAttribute.event_flags {} @@ -47,7 +47,7 @@ DefineAttribute.event_flags {} # Attributes with a "token_ref" value will be added to widget's private data # -# widget format +## widget format DefineAttribute."format" { type "string" # Token set reference name and type @@ -62,49 +62,50 @@ DefineAttribute."format" { } } -# ID of the core this widget should be scheduled on +## ID of the core this widget should be scheduled on DefineAttribute."core_id" { # Token set reference name and type token_ref "comp.word" } -# number of periods to preload +## number of periods to preload DefineAttribute."preload_count" { # Token set reference name and type token_ref "comp.word" } -# Number of sink pins a widget can support +## Number of sink pins a widget can support DefineAttribute."num_input_pins" { # Token set reference name and type token_ref "comp.word" } -# Number of source pins a widget can support +## Number of source pins a widget can support DefineAttribute."num_output_pins" { # Token set reference name and type token_ref "comp.word" } -# Number of supported sink(input) audio formats +## Number of supported sink(input) audio formats DefineAttribute."num_input_audio_formats" { # Token set reference name and type token_ref "comp.word" } -# Number of supported source(output) audio formats +## Number of supported source(output) audio formats DefineAttribute."num_output_audio_formats" { # Token set reference name and type token_ref "comp.word" } -# Widget UUID +## Widget UUID DefineAttribute.uuid { type "string" # Token set reference name and type token_ref "comp.uuid" } +## Whether to add this widget's name to the beginning of all its associated mixer names DefineAttribute."no_wname_in_kcontrol_name" { type "string" # Token set reference name diff --git a/tools/topology/topology2/include/controls/common.conf b/tools/topology/topology2/include/controls/common.conf index 77593fccc1fb..0cf249914070 100644 --- a/tools/topology/topology2/include/controls/common.conf +++ b/tools/topology/topology2/include/controls/common.conf @@ -1,15 +1,19 @@ -# Common class definitions for controls - -# -# Class for channel objects. These are instantiated as: -# Object.Base.channel."fl" { -# reg 1 -# shift 0 -# } -# +## \file common.conf +## \brief Common class definitions for controls. + +## \struct channel +## \brief Class for channel objects. +## These are instantiated as: +## +## Object.Base.channel."fl" { +## reg 1 +## shift 0 +## } +## + Class.Base."channel" { DefineAttribute."instance" {} - # name of the channel + ## name of the channel DefineAttribute."name" { type "string" } @@ -33,13 +37,18 @@ Class.Base."channel" { shift 1 } -# Class definition for control ops. These are instantiated as: -# Object.Base.ops."ctl" { -# info "volsw" -# get "259" -# put "259" -# } -# +## \struct ops +## \brief Class definition for control ops. +## +## These are instantiated as: +## +## Object.Base.ops."ctl" { +## info "volsw" +## get "259" +## put "259" +## } +## + Class.Base."ops" { DefineAttribute."instance" {} # ops name @@ -68,13 +77,17 @@ Class.Base."ops" { } } -# Class definition for control extops. These are instantiated as: -# Object.Base.extops."ctl" { -# info "volsw" -# get "258" -# put "258" -# } -# +## \struct extops +## \brief Class definition for control extops. +## These are instantiated as: +## +## Object.Base.extops."ctl" { +## info "volsw" +## get "258" +## put "258" +## } +## + Class.Base."extops" { DefineAttribute."instance" {} # extops name @@ -104,12 +117,15 @@ Class.Base."extops" { } } -# -# Class definition for scale objects. These are instantiated as follows: -# Object.Base.scale."name" { -# mute 1 -# } -# +## \struct scale +## \brief Class definition for scale objects. +## These are instantiated as follows: +## +## Object.Base.scale."name" { +## mute 1 +## } +## + Class.Base."scale" { DefineAttribute."instance" {} DefineAttribute."name" { @@ -139,11 +155,17 @@ Class.Base."scale" { mute 1 } -# -# Class definition for tlv objects. These are instantiated as follows: -# Object.Base.tlv."vtlv_m64s2" { -# Object.Base.scale."0" {} -# } +## \struct tlv +## \brief Class definition for tlv objects. +## These are instantiated as follows: +## +## Object.Base.tlv."vtlv_m64s2" { +## Object.Base.scale."0" {} +## } +## +## The linked object instance is \link scale \endlink . +## + Class.Base."tlv" { DefineAttribute."instance" {} DefineAttribute."name" { diff --git a/tools/topology/topology2/include/controls/mixer.conf b/tools/topology/topology2/include/controls/mixer.conf index 66b5085cf857..191230ec5bdc 100644 --- a/tools/topology/topology2/include/controls/mixer.conf +++ b/tools/topology/topology2/include/controls/mixer.conf @@ -1,41 +1,45 @@ -# -# Mixer kcontrol class. All attributes defined herein are namespaced -# by alsatplg to "Object.Control.mixer.N.attribute_name" -# -# Usage: this component can be used by instantiating it in the parent object. i.e. -# -# Object.Control.mixer."N" { -# index 1 -# name "1 Master Playback Volume" -# mas 32 -# Object.Base.channel.1 { -# name "fl" -# shift 0 -# reg 0 -# } -# Object.Base.channel.2 { -# name "fr" -# shift 1 -# reg 1 -# } -# Object.Base.ops."ctl" { -# info "volsw" -# get "258" -# put "258" -# } -# } -# -# Where N is the unique instance number for the buffer object within the same alsaconf node. -# The mixer control object should also include the ops, channels and tlv objects in the object -# instance +## \struct mixer +## \brief Topology Mixer class +## +## All attributes defined herein are namespaced +## by alsatplg to "Object.Control.mixer.N.attribute_name" +## +## Usage: this component can be used by instantiating it in the parent object. i.e. +## +## Object.Control.mixer."N" { +## index 1 +## name "1 Master Playback Volume" +## max 32 +## Object.Base.channel.1 { +## name "fl" +## shift 0 +## reg 0 +## } +## Object.Base.channel.2 { +## name "fr" +## shift 1 +## reg 1 +## } +## Object.Base.ops."ctl" { +## info "volsw" +## get "258" +## put "258" +## } +## } +## +## The linked object instaces are \link channel \endlink and \link ops \endlink . +## +## Where N is the unique instance number for the buffer object within the same alsaconf node. +## The mixer control object should also include the ops, channels and tlv objects in the object +## instance <include/controls/common.conf> Class.Control."mixer" { - # - # Pipeline ID for the mixer object - # - DefineAttribute."index" {} + ## + ## @ Pipeline ID for the mixer object + ## + DefineAttribute."index" {} ##< Automatically given unique index # # Instance of mixer object in the same alsaconf node diff --git a/tools/topology/topology2/include/dais/mic_extension.conf b/tools/topology/topology2/include/dais/mic_extension.conf index 6dc12a1f21b2..31628e9b2241 100644 --- a/tools/topology/topology2/include/dais/mic_extension.conf +++ b/tools/topology/topology2/include/dais/mic_extension.conf @@ -1,3 +1,6 @@ +## \brief Mic extension class +## \struct mic_extension + Class.Base."mic_extension" { DefineAttribute."id" {} diff --git a/tools/topology/topology2/include/dais/pdm_config.conf b/tools/topology/topology2/include/dais/pdm_config.conf index 2a8759a7742c..3745bea7998e 100644 --- a/tools/topology/topology2/include/dais/pdm_config.conf +++ b/tools/topology/topology2/include/dais/pdm_config.conf @@ -1,3 +1,6 @@ +## \brief Class for PDM config +## \struct pdm_config + Class.Base."pdm_config" { DefineAttribute."instance" {} # diff --git a/tools/topology/topology2/include/dais/ssp.conf b/tools/topology/topology2/include/dais/ssp.conf index 6c0d91f2bd69..78470fe24d57 100644 --- a/tools/topology/topology2/include/dais/ssp.conf +++ b/tools/topology/topology2/include/dais/ssp.conf @@ -58,6 +58,25 @@ Class.Dai."SSP" { type "string" } + DefineAttribute."clks_control" { + # Token reference and type + token_ref "intel_ssp.word" + constraints { + !valid_values [ + "0" + "mclk_es" + "bclk_es" + "mclk_aon" + ] + !tuple_values [ + 0 + 64 + 128 + 256 + ] + } + } + # Backend DAI Link ID matching with the machine driver DefineAttribute."id" {} diff --git a/tools/topology/topology2/include/pipelines/cavs/dai-copier-be.conf b/tools/topology/topology2/include/pipelines/cavs/dai-copier-be.conf index d17e651316b9..c8e8699f1294 100644 --- a/tools/topology/topology2/include/pipelines/cavs/dai-copier-be.conf +++ b/tools/topology/topology2/include/pipelines/cavs/dai-copier-be.conf @@ -22,8 +22,6 @@ Class.Pipeline."dai-copier-be" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/dai-copier-eqiir-module-copier-capture.conf b/tools/topology/topology2/include/pipelines/cavs/dai-copier-eqiir-module-copier-capture.conf index 131e5969cd4e..4869a6bb3bd7 100644 --- a/tools/topology/topology2/include/pipelines/cavs/dai-copier-eqiir-module-copier-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/dai-copier-eqiir-module-copier-capture.conf @@ -25,8 +25,6 @@ Class.Pipeline."dai-copier-eqiir-module-copier-capture" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-mixin-capture.conf b/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-mixin-capture.conf index a5ce31f7aa30..7f7a85d4724e 100644 --- a/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-mixin-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-mixin-capture.conf @@ -24,8 +24,6 @@ Class.Pipeline."dai-copier-gain-mixin-capture" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-module-copier-capture.conf b/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-module-copier-capture.conf index 072a5f9be1be..2e38db9f0719 100644 --- a/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-module-copier-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/dai-copier-gain-module-copier-capture.conf @@ -23,8 +23,6 @@ Class.Pipeline."dai-copier-gain-module-copier-capture" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf b/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf index 70bc4f2c8dba..28d2f8c47d74 100644 --- a/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf +++ b/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf @@ -24,8 +24,6 @@ Class.Pipeline."dai-kpb-be" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/deepbuffer-playback.conf b/tools/topology/topology2/include/pipelines/cavs/deepbuffer-playback.conf index fbb19283a9dd..abe5a468ad01 100644 --- a/tools/topology/topology2/include/pipelines/cavs/deepbuffer-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/deepbuffer-playback.conf @@ -24,8 +24,6 @@ Class.Pipeline."deepbuffer-playback" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/gain-capture.conf b/tools/topology/topology2/include/pipelines/cavs/gain-capture.conf index 57e65070b6db..dbee6b08aec7 100644 --- a/tools/topology/topology2/include/pipelines/cavs/gain-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/gain-capture.conf @@ -24,8 +24,6 @@ Class.Pipeline."gain-capture" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { @@ -47,58 +45,173 @@ Class.Pipeline."gain-capture" { Object.Widget { host-copier."1" { type "aif_out" - num_input_audio_formats 3 - num_output_audio_formats 3 + num_input_audio_formats 2 num_input_pins 1 - # 16-bit 48KHz 2ch - Object.Base.audio_format.1 { - in_bit_depth 32 - in_valid_bit_depth 32 - } - # 24-bit 48KHz 2ch - Object.Base.audio_format.2 { - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 24 - } - # 32-bit 48KHz 2ch - Object.Base.audio_format.3 { - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + + num_output_audio_formats 6 + num_output_pins 1 + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + node_type $HDA_HOST_INPUT_CLASS } gain."1" { - num_input_audio_formats 2 - num_output_audio_formats 2 + num_input_audio_formats 4 + num_input_pins 1 + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] - #16-bit 48KHz 2ch - Object.Base.audio_format.1 {} - # 32-bit 48KHz 2ch - Object.Base.audio_format.2 { - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } + num_output_audio_formats 4 + num_output_pins 1 + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] } module-copier."2" { - num_input_audio_formats 2 - num_output_audio_formats 2 - #16-bit 48KHz 2ch - Object.Base.audio_format.1 {} - # 32-bit 48KHz 2ch - Object.Base.audio_format.2 { - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } + num_input_audio_formats 4 + num_input_pins 1 + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + + num_output_audio_formats 4 + num_output_pins 1 + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] } pipeline."1" { diff --git a/tools/topology/topology2/include/pipelines/cavs/gain-copier-capture.conf b/tools/topology/topology2/include/pipelines/cavs/gain-copier-capture.conf index 86ee039fd90e..6642d28d2858 100644 --- a/tools/topology/topology2/include/pipelines/cavs/gain-copier-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/gain-copier-capture.conf @@ -24,8 +24,6 @@ Class.Pipeline."gain-copier-capture" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/gain-module-copier.conf b/tools/topology/topology2/include/pipelines/cavs/gain-module-copier.conf index 416a4c3b59e1..ff9ef84b6d51 100644 --- a/tools/topology/topology2/include/pipelines/cavs/gain-module-copier.conf +++ b/tools/topology/topology2/include/pipelines/cavs/gain-module-copier.conf @@ -23,8 +23,6 @@ Class.Pipeline."gain-module-copier" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/gain-playback.conf b/tools/topology/topology2/include/pipelines/cavs/gain-playback.conf index 81aedde59f7f..e5e5bc41d9a7 100644 --- a/tools/topology/topology2/include/pipelines/cavs/gain-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/gain-playback.conf @@ -23,8 +23,6 @@ Class.Pipeline."gain-playback" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/google-rtc-aec-capture.conf b/tools/topology/topology2/include/pipelines/cavs/google-rtc-aec-capture.conf index 6699ff23bbd0..443113559ffe 100644 --- a/tools/topology/topology2/include/pipelines/cavs/google-rtc-aec-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/google-rtc-aec-capture.conf @@ -25,8 +25,6 @@ Class.Pipeline."google-rtc-aec-capture" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { @@ -55,50 +53,74 @@ Class.Pipeline."google-rtc-aec-capture" { period_sink_count 1 period_source_count 1 num_audio_formats 1 - num_input_audio_formats 1 - num_output_audio_formats 1 - - Object.Base.audio_format.1 { - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 16 - out_valid_bit_depth 16 - } - } - - google-rtc-aec."1" { - Object.Control.bytes."1" { - name google-rtc-aec_blob - access [ - tlv_read - tlv_callback - ] + num_input_audio_formats 2 + num_output_audio_formats 2 - Object.Base.extops."extctl" { - get 258 - put 0 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 } - max 4096 - - IncludeByKey.GOOGLE_RTC_AEC_SUPPORT { - "[1]" "include/components/google-rtc-aec/rtc-aec-blob.conf" + # 4ch 32-bit on Pin 0 + { + input_pin_index 0 + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 } - } - } + + ] + } module-copier."2" { period_sink_count 1 period_source_count 1 - num_audio_formats 1 - num_input_audio_formats 1 - num_output_audio_formats 1 + num_input_audio_formats 2 + num_output_audio_formats 2 - Object.Base.audio_format.1 { - in_bit_depth 16 - in_valid_bit_depth 16 - out_bit_depth 32 - out_valid_bit_depth 32 - } + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + Object.Base.output_audio_format [ + # 2ch 32-bit + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + # 4ch 32-bit + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] } } diff --git a/tools/topology/topology2/include/pipelines/cavs/highpass-capture-be.conf b/tools/topology/topology2/include/pipelines/cavs/highpass-capture-be.conf index 6475b9b719c3..7d43f08f1a61 100644 --- a/tools/topology/topology2/include/pipelines/cavs/highpass-capture-be.conf +++ b/tools/topology/topology2/include/pipelines/cavs/highpass-capture-be.conf @@ -25,8 +25,6 @@ Class.Pipeline."highpass-capture-be" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-mixin-playback.conf b/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-mixin-playback.conf index 814e78252eb8..02f47b204a3b 100644 --- a/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-mixin-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-mixin-playback.conf @@ -24,8 +24,6 @@ Class.Pipeline."host-copier-gain-mixin-playback" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-src-mixin-playback.conf b/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-src-mixin-playback.conf index 05ab5ea46c05..b55f2a18c62f 100644 --- a/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-src-mixin-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/host-copier-gain-src-mixin-playback.conf @@ -26,8 +26,6 @@ Class.Pipeline."host-copier-gain-src-mixin-playback" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/host-gateway-capture.conf b/tools/topology/topology2/include/pipelines/cavs/host-gateway-capture.conf index deb9df7f9650..84a4cc46cf7f 100644 --- a/tools/topology/topology2/include/pipelines/cavs/host-gateway-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/host-gateway-capture.conf @@ -16,14 +16,13 @@ # Where N is the unique pipeline ID within the same alsaconf node. # -<include/common/audio_format.conf> +<include/common/input_audio_format.conf> +<include/common/output_audio_format.conf> <include/components/host-copier.conf> <include/components/pipeline.conf> Class.Pipeline."host-gateway-capture" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { @@ -47,64 +46,57 @@ Class.Pipeline."host-gateway-capture" { type "aif_out" node_type $HDA_HOST_INPUT_CLASS num_input_pins 1 - num_input_audio_formats 6 + num_input_audio_formats 2 num_output_audio_formats 6 - # 16-bit output format 48KHz 2ch. Input sample format is always 32-bit for capture - Object.Base.audio_format.1 { - in_bit_depth 32 - in_valid_bit_depth 32 - } - # 24-bit 48KHz 2ch - Object.Base.audio_format.2 { - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 24 - } - # 32-bit 48KHz 2ch - Object.Base.audio_format.3 { - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } - # 16-bit output format 48KHz 4ch. Input sample format is always 32-bit for capture - Object.Base.audio_format.4 { - in_channels 4 - in_bit_depth 32 - in_valid_bit_depth 32 - out_channels 4 - in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - in_ch_map $CHANNEL_MAP_3_POINT_1 - out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - out_ch_map $CHANNEL_MAP_3_POINT_1 - } - # 24-bit 48KHz 2ch - Object.Base.audio_format.5 { - in_channels 4 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 24 - out_channels 4 - in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - in_ch_map $CHANNEL_MAP_3_POINT_1 - out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - out_ch_map $CHANNEL_MAP_3_POINT_1 - } - # 32-bit 48KHz 4ch - Object.Base.audio_format.6 { - in_channels 4 - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - out_channels 4 - in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - in_ch_map $CHANNEL_MAP_3_POINT_1 - out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 - out_ch_map $CHANNEL_MAP_3_POINT_1 - } + # Input sample format is always 32-bit for capture + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 4 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 24 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_bit_depth 32 + out_valid_bit_depth 24 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_channels 4 + out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + out_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] } pipeline."1" { diff --git a/tools/topology/topology2/include/pipelines/cavs/host-gateway-playback.conf b/tools/topology/topology2/include/pipelines/cavs/host-gateway-playback.conf index 577513ad77b4..a2d42e5e3d46 100644 --- a/tools/topology/topology2/include/pipelines/cavs/host-gateway-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/host-gateway-playback.conf @@ -22,8 +22,6 @@ Class.Pipeline."host-gateway-playback" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/io-gateway-capture.conf b/tools/topology/topology2/include/pipelines/cavs/io-gateway-capture.conf index af2094d32ecf..a50b8ed0dd3c 100644 --- a/tools/topology/topology2/include/pipelines/cavs/io-gateway-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/io-gateway-capture.conf @@ -23,8 +23,6 @@ Class.Pipeline."io-gateway-capture" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/io-gateway.conf b/tools/topology/topology2/include/pipelines/cavs/io-gateway.conf index fd160d0d4721..106a17ec463b 100644 --- a/tools/topology/topology2/include/pipelines/cavs/io-gateway.conf +++ b/tools/topology/topology2/include/pipelines/cavs/io-gateway.conf @@ -24,8 +24,6 @@ Class.Pipeline."io-gateway" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-aria-gain-mixin-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-aria-gain-mixin-playback.conf index 65ae5c009a4e..682b3c47ebe3 100644 --- a/tools/topology/topology2/include/pipelines/cavs/mixout-aria-gain-mixin-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-aria-gain-mixin-playback.conf @@ -25,8 +25,6 @@ Class.Pipeline."mixout-aria-gain-mixin-playback" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-dai-copier-playback.conf index d426a4d0dac8..ba7997a55006 100644 --- a/tools/topology/topology2/include/pipelines/cavs/mixout-dai-copier-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-dai-copier-playback.conf @@ -23,8 +23,6 @@ Class.Pipeline."mixout-dai-copier-playback" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-alh-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-alh-dai-copier-playback.conf index a66f846f7d04..ab8ab712c929 100644 --- a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-alh-dai-copier-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-alh-dai-copier-playback.conf @@ -22,8 +22,6 @@ Class.Pipeline."mixout-gain-alh-dai-copier-playback" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dai-copier-playback.conf index c90d71556224..c40c67e1aaf8 100644 --- a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dai-copier-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-dai-copier-playback.conf @@ -24,8 +24,6 @@ Class.Pipeline."mixout-gain-dai-copier-playback" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-efx-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-efx-dai-copier-playback.conf index 93dc0e64c893..66b7b9c8b1a5 100644 --- a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-efx-dai-copier-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-efx-dai-copier-playback.conf @@ -22,15 +22,13 @@ <include/components/mixout.conf> <include/components/pipeline.conf> <include/controls/bytes.conf> -<include/components/eqfir.conf> <include/components/eqiir.conf> +<include/components/eqfir.conf> <include/components/drc.conf> <platform/intel/efx-default.conf> Class.Pipeline."mixout-gain-efx-dai-copier-playback" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-efx-mbdrc-dai-copier-playback.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-efx-mbdrc-dai-copier-playback.conf new file mode 100644 index 000000000000..87f3e1e34809 --- /dev/null +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-efx-mbdrc-dai-copier-playback.conf @@ -0,0 +1,174 @@ +# +# BE playback pipeline: mixout-gain-efx-mbdrc-dai-copier. +# +# All attributes defined herein are namespaced +# by alsatplg to "Object.Pipeline.mixout-gain-efx-mbdrc-dai-copier-playback.N.attribute_name" +# +# Usage: mixout-gain-efx-mbdrc-dai-copier-playback pipeline object can be instantiated as: +# +# Object.Pipeline.mixout-gain-efx-mbdrc-dai-copier-playback."N" { +# period 1000 +# time_domain "timer" +# channels 2 +# rate 48000 +# } +# +# Where N is the unique pipeline ID within the same alsaconf node. +# + +<include/common/audio_format.conf> +<include/components/dai-copier.conf> +<include/components/gain.conf> +<include/components/mixout.conf> +<include/components/pipeline.conf> +<include/controls/bytes.conf> +<include/components/eqiir.conf> +<include/components/eqfir.conf> +<include/components/multiband_drc.conf> +<platform/intel/efx-default.conf> + +Class.Pipeline."mixout-gain-efx-mbdrc-dai-copier-playback" { + + <include/pipelines/pipeline-common.conf> + + attributes { + !constructor [ + "index" + ] + + !immutable [ + "direction" + ] + + # + # mixout-gain-efx-mbdrc-dai-copier-playback objects instantiated within the same alsaconf node must have + # unique instance attribute + # + unique "instance" + } + + Object.Widget { + mixout."1" {} + dai-copier."1" { + type dai_in + num_input_audio_formats 1 + num_output_audio_formats 1 + num_input_pins 1 + + # copier only supports one format based on mixin/mixout requirements: 32-bit 48KHz 2ch + Object.Base.audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + gain."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 + + # 32-bit 48KHz 2ch + Object.Base.audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + eqiir."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 + + # 32-bit 48KHz 2ch + Object.Base.audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + + Object.Control.bytes."1" { + IncludeByKey.EFX_IIR_PARAMS { + "passthrough" "include/components/eqiir/passthrough.conf" + } + } + } + eqfir."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 + + # 32-bit 48KHz 2ch + Object.Base.audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + + Object.Control.bytes."1" { + IncludeByKey.EFX_FIR_PARAMS { + "passthrough" "include/components/eqfir/passthrough.conf" + } + } + } + multiband_drc."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 + + Object.Base.audio_format.1 { + in_bit_depth 32 + in_valid_bit_depth 32 + out_bit_depth 32 + out_valid_bit_depth 32 + } + + Object.Control.bytes."1" { + IncludeByKey.EFX_MBDRC_PARAMS { + "passthrough" "include/components/multiband_drc/passthrough.conf" + "default" "include/components/multiband_drc/default.conf" + } + } + } + pipeline."1" { + priority 0 + lp_mode 0 + } + } + + Object.Base { + route.1 { + source mixout..1 + sink gain..1 + } + route.2 { + source gain..1 + sink eqiir..1 + } + route.3 { + source eqiir..1 + sink eqfir..1 + } + route.4 { + source eqfir..1 + sink multiband_drc..1 + } + } + + direction "playback" + dynamic_pipeline 1 + time_domain "timer" + channels 2 + channels_min 2 + channels_max 2 + rate 48000 + rate_min 48000 + rate_max 48000 +} diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-host-copier-capture.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-host-copier-capture.conf index 594251d66062..1c9801d89520 100644 --- a/tools/topology/topology2/include/pipelines/cavs/mixout-gain-host-copier-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-gain-host-copier-capture.conf @@ -24,8 +24,6 @@ Class.Pipeline."mixout-gain-host-copier-capture" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/mixout-mixin.conf b/tools/topology/topology2/include/pipelines/cavs/mixout-mixin.conf index 0b895ae36fed..cdd40b90f9af 100644 --- a/tools/topology/topology2/include/pipelines/cavs/mixout-mixin.conf +++ b/tools/topology/topology2/include/pipelines/cavs/mixout-mixin.conf @@ -20,8 +20,6 @@ Class.Pipeline."mixout-mixin" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/src-gain-mixin-playback.conf b/tools/topology/topology2/include/pipelines/cavs/src-gain-mixin-playback.conf index 36a2e29a7824..46d1a6dfc8b9 100644 --- a/tools/topology/topology2/include/pipelines/cavs/src-gain-mixin-playback.conf +++ b/tools/topology/topology2/include/pipelines/cavs/src-gain-mixin-playback.conf @@ -26,8 +26,6 @@ Class.Pipeline."src-gain-mixin-playback" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf b/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf index b804110a921f..dc7805bd0f3e 100644 --- a/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf +++ b/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf @@ -26,8 +26,6 @@ Class.Pipeline."wov-detect" { - DefineAttribute."index" {} - <include/pipelines/pipeline-common.conf> attributes { diff --git a/tools/topology/topology2/include/pipelines/volume-playback.conf b/tools/topology/topology2/include/pipelines/volume-playback.conf index d04830b2168a..fa007609ab4c 100644 --- a/tools/topology/topology2/include/pipelines/volume-playback.conf +++ b/tools/topology/topology2/include/pipelines/volume-playback.conf @@ -1,24 +1,26 @@ -# -# Volume playback pipeline -# -# A simple pipeline. All attributes defined herein are namespaced by alsatplg to -# "Object.Pipeline.volume-playback.N.attribute_name" -# -# Usage: this component can be used by declaring in the top-level topology conf file as follows: -# -# Object.Pipeline.volume-playback."N" { -# format "s16le" -# period 1000 -# time_domain "timer" -# channels 2 -# rate 48000 -# } -# -# where N is the unique pipeline_id for this pipeline object within the same alsaconf node. -# -# -# (source) host.N.playback -> buffer.N.1 -> volume.N.1 -> buffer.N.2 (sink endpoint) -# +## \struct volume_playback +## \brief Volume playback pipeline +## +## \par Instantiating volume-playback pipeline +## +## A simple pipeline. All attributes defined herein are namespaced by alsatplg +## to "Object.Pipeline.volume-playback.N.attribute_name" +## +## Usage: this component can be used by declaring in the top-level topology conf file as follows: +## +## Object.Pipeline.volume-playback."N" { +## format "s16le" +## period 1000 +## time_domain "timer" +## channels 2 +## rate 48000 +## } +## +## where N is the unique pipeline_id for this pipeline object within the same alsaconf node. +## +## +## (source) host.N.playback -> buffer.N.1 -> volume.N.1 -> buffer.N.2 (sink endpoint) +## <include/common/route.conf> <include/components/buffer.conf> @@ -31,7 +33,7 @@ Class.Pipeline."volume-playback" { <include/pipelines/pipeline-common.conf> attributes { - # pipeline name is constructed as "volume-playback.1" + ## pipeline name is constructed as "volume-playback.1" !constructor [ "index" ] @@ -49,9 +51,11 @@ Class.Pipeline."volume-playback" { } Object.Widget { + ## The pipeline object for captured playback pipeline."1" {} host."playback" { + ## "aif_in" is for playback type "aif_in" } diff --git a/tools/topology/topology2/platform/intel/bt-ssp-config-lbm.conf b/tools/topology/topology2/platform/intel/bt-ssp-config-lbm.conf index 694f6939e2f6..d4060ef53c09 100644 --- a/tools/topology/topology2/platform/intel/bt-ssp-config-lbm.conf +++ b/tools/topology/topology2/platform/intel/bt-ssp-config-lbm.conf @@ -23,7 +23,7 @@ Object.Dai.SSP [ tx_slots 1 rx_slots 1 Object.Base.link_config.1 { - clock_source 0 + clock_source 1 } } Object.Base.hw_config.2 { @@ -41,7 +41,7 @@ Object.Dai.SSP [ tx_slots 1 rx_slots 1 Object.Base.link_config.1 { - clock_source 0 + clock_source 1 } } Object.Base.hw_config.3 { @@ -58,7 +58,7 @@ Object.Dai.SSP [ tx_slots 3 rx_slots 3 Object.Base.link_config.1 { - clock_source 0 + clock_source 1 } } } diff --git a/tools/topology/topology2/platform/intel/bt-ssp-config.conf b/tools/topology/topology2/platform/intel/bt-ssp-config.conf index edce4b8d1399..1a5353890f5e 100644 --- a/tools/topology/topology2/platform/intel/bt-ssp-config.conf +++ b/tools/topology/topology2/platform/intel/bt-ssp-config.conf @@ -22,7 +22,7 @@ Object.Dai.SSP [ tx_slots 1 rx_slots 1 Object.Base.link_config.1 { - clock_source 0 + clock_source 1 } } Object.Base.hw_config.2 { @@ -40,7 +40,7 @@ Object.Dai.SSP [ tx_slots 1 rx_slots 1 Object.Base.link_config.1 { - clock_source 0 + clock_source 1 } } Object.Base.hw_config.3 { @@ -57,7 +57,7 @@ Object.Dai.SSP [ tx_slots 3 rx_slots 0 Object.Base.link_config.1 { - clock_source 0 + clock_source 1 } } } diff --git a/tools/topology/topology2/platform/intel/dmic-default.conf b/tools/topology/topology2/platform/intel/dmic-default.conf index 3f1e23526bc5..0bbb288e9e03 100644 --- a/tools/topology/topology2/platform/intel/dmic-default.conf +++ b/tools/topology/topology2/platform/intel/dmic-default.conf @@ -35,4 +35,5 @@ Define { DMIC1_PCM_CAPS 'Passthrough Capture 18' DMIC_CORE_ID 0 PASSTHROUGH "false" + DMIC_PIPELINE_PRIORITY 0 } diff --git a/tools/topology/topology2/platform/intel/dmic-generic.conf b/tools/topology/topology2/platform/intel/dmic-generic.conf index 006505ca011f..6c6ae7ec2da2 100644 --- a/tools/topology/topology2/platform/intel/dmic-generic.conf +++ b/tools/topology/topology2/platform/intel/dmic-generic.conf @@ -102,6 +102,7 @@ IncludeByKey.PASSTHROUGH { } } Object.Widget.gain.1 { + curve_duration 500000 num_input_audio_formats 2 num_output_audio_formats 2 Object.Base.audio_format.1 { @@ -180,6 +181,7 @@ IncludeByKey.PASSTHROUGH { } Object.Widget.pipeline."1" { core $DMIC_CORE_ID + priority $DMIC_PIPELINE_PRIORITY } } ] diff --git a/tools/topology/topology2/platform/intel/efx-default.conf b/tools/topology/topology2/platform/intel/efx-default.conf index ed9304b4c062..6a152e68a1ef 100644 --- a/tools/topology/topology2/platform/intel/efx-default.conf +++ b/tools/topology/topology2/platform/intel/efx-default.conf @@ -3,4 +3,6 @@ Define { EFX_IIR_PARAMS 'passthrough' EFX_CROSSOVER_PARAMS '2way' EFX_DRC_PARAMS 'passthrough' + EFX_MBDRC_PARAMS 'passthrough' + EFX_DRC_COMPONENT 'singleband' } diff --git a/tools/topology/topology2/platform/intel/google-rtc-aec-reference.conf b/tools/topology/topology2/platform/intel/google-rtc-aec-reference.conf index b2e9a88ec1e9..336d31aac2e0 100644 --- a/tools/topology/topology2/platform/intel/google-rtc-aec-reference.conf +++ b/tools/topology/topology2/platform/intel/google-rtc-aec-reference.conf @@ -6,6 +6,7 @@ Object.Pipeline.google-rtc-aec-capture [ Object.Widget.pipeline.1 { stream_name "DMIC0 RTC AEC" core $GOOGLE_AEC_CORE_ID + priority $GOOGLE_AEC_PIPELINE_PRIORITY } Object.Widget.google-rtc-aec.1 { @@ -14,7 +15,7 @@ Object.Pipeline.google-rtc-aec-capture [ } Object.Base.input_pin_binding.2 { - input_pin_binding_name $GOOGLE_RTC_AEC_REF_SOURCE + input_pin_binding_name "dai-copier.SSP.$SPEAKER_CODEC_NAME.capture" } } } @@ -31,6 +32,7 @@ Object.Pipeline.host-gateway-capture[ } Object.Widget.pipeline."1" { core $GOOGLE_AEC_CORE_ID + priority $GOOGLE_AEC_HOST_PIPELINE_PRIORITY } } ] @@ -97,7 +99,7 @@ Object.Base.route [ sink module-copier.18.1 } { - source $GOOGLE_RTC_AEC_REF_SOURCE + source "dai-copier.SSP.$SPEAKER_CODEC_NAME.capture" sink "google-rtc-aec.18.1" } { diff --git a/tools/topology/topology2/platform/intel/speaker-echo-ref.conf b/tools/topology/topology2/platform/intel/speaker-echo-ref.conf index 2ff5f3e22e5e..7119dd1568ad 100644 --- a/tools/topology/topology2/platform/intel/speaker-echo-ref.conf +++ b/tools/topology/topology2/platform/intel/speaker-echo-ref.conf @@ -1,25 +1,5 @@ -Define { - ECHO_REF_STREAM_NAME "Echo reference" -} - Object.Pipeline { - host-gateway-capture [ - { - index $ECHO_REF_HOST_PIPELINE_ID - core_id $ECHO_REF_CORE_ID - - Object.Widget.host-copier.1 { - core_id $ECHO_REF_CORE_ID - stream_name $ECHO_REF_STREAM_NAME - pcm_id $ECHO_REF_PCM_ID - } - Object.Widget.pipeline."1" { - core $ECHO_REF_CORE_ID - } - } - ] - - dai-copier-be [ + io-gateway-capture [ { index $ECHO_REF_DAI_PIPELINE_ID core_id $ECHO_REF_CORE_ID @@ -33,41 +13,25 @@ Object.Pipeline { copier_type "SSP" stream_name $SPEAKER_CODEC_NAME node_type $I2S_LINK_INPUT_CLASS - Object.Base.audio_format.1 { - in_bit_depth 32 - in_valid_bit_depth 32 - out_bit_depth 32 - out_valid_bit_depth 32 - } + num_input_audio_formats 1 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + num_output_audio_formats 1 + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + ] } Object.Widget.pipeline."1" { - core $ECHO_REF_CORE_ID + core $ECHO_REF_CORE_ID + priority $ECHO_REF_PIPELINE_PRIORITY } } ] } - -Object.PCM.pcm [ - { - name "EchoRef" - id $ECHO_REF_PCM_ID - direction "capture" - Object.Base.fe_dai.1 {} - - Object.PCM.pcm_caps.1 { - name $ECHO_REF_STREAM_NAME - formats 'S16_LE,S24_LE,S32_LE' - } - } -] - -Object.Base.route [ - { - source "dai-copier.SSP.$SPEAKER_CODEC_NAME.capture" - sink $ECHO_REF_COPIER_MODULE - } - { - source $ECHO_REF_COPIER_MODULE - sink "host-copier.$ECHO_REF_PCM_ID.capture" - } -] diff --git a/tools/topology/topology2/platform/intel/ssp_aux_config.conf b/tools/topology/topology2/platform/intel/ssp_aux_config.conf index 1a814edef07e..c084faa4195c 100644 --- a/tools/topology/topology2/platform/intel/ssp_aux_config.conf +++ b/tools/topology/topology2/platform/intel/ssp_aux_config.conf @@ -1,3 +1,5 @@ +## \struct mn_config + Class.Base."mn_config" { DefineAttribute."id" {} diff --git a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake index 58837ccb7a5e..16899df252c6 100644 --- a/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake +++ b/tools/topology/topology2/sof-ace-tplg/tplg-targets.cmake @@ -35,6 +35,7 @@ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" USE_CHAIN_DMA=true,NUM_SDW_AMP_LINKS=2,SDW_SPK_STREAM=SDW1-Playback,SDW_SPK_IN_STREAM=SDW1-Capture,\ SDW_DMIC_STREAM=SDW0-Capture" +"cavs-sdw\;sof-mtl-rt713-l0-rt1316-l12-rt1713-l3\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,SDW_DMIC=1" # Below topologies are used on Chromebooks "cavs-rt5682\;sof-mtl-max98357a-rt5682\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ @@ -50,6 +51,14 @@ SPK_ID=6,SPEAKER_SSP_DAI_INDEX=0,HEADSET_CODEC_NAME=SSP2-Codec,SPEAKER_CODEC_NAM BT_NAME=SSP1-BT,BT_INDEX=1,BT_ID=7,BT_PCM_NAME=Bluetooth,INCLUDE_ECHO_REF=true,USE_CHAIN_DMA=true,\ DEEPBUFFER_D0I3_COMPATIBLE=true" +# RT5650 integrated codec support +"cavs-rt5682\;sof-mtl-rt5650\;PLATFORM=mtl,NUM_DMICS=4,PDM1_MIC_A_ENABLE=1,\ +PDM1_MIC_B_ENABLE=1,DMIC0_PCM_ID=99,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-mtl-max98357a-rt5682.bin,DEEPBUFFER_FW_DMA_MS=10,HEADSET_SSP_DAI_INDEX=2,\ +SPK_ID=6,SPEAKER_SSP_DAI_INDEX=0,HEADSET_CODEC_NAME=SSP2-Codec,SPEAKER_CODEC_NAME=SSP0-Codec,\ +BT_NAME=SSP1-BT,BT_INDEX=1,BT_ID=7,BT_PCM_NAME=Bluetooth,INCLUDE_ECHO_REF=true,USE_CHAIN_DMA=true,\ +DEEPBUFFER_D0I3_COMPATIBLE=true,SSP_CLKS_CONTROL=mclk_aon" + "cavs-rt5682\;sof-mtl-max98357a-rt5682-ssp2-ssp0-2ch-pdm1\;PLATFORM=mtl,NUM_DMICS=2,\ PDM0_MIC_A_ENABLE=0,PDM0_MIC_B_ENABLE=0,PDM1_MIC_A_ENABLE=1,PDM1_MIC_B_ENABLE=1,\ DMIC0_PCM_ID=99,PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-mtl-max98357a-rt5682-2ch.bin,\ diff --git a/tools/topology/topology2/sof-hda-generic.conf b/tools/topology/topology2/sof-hda-generic.conf index 1bd06bff796f..260cadb924bc 100644 --- a/tools/topology/topology2/sof-hda-generic.conf +++ b/tools/topology/topology2/sof-hda-generic.conf @@ -17,6 +17,7 @@ <mixout-gain-dai-copier-playback.conf> <mixout-aria-gain-mixin-playback.conf> <mixout-gain-efx-dai-copier-playback.conf> +<mixout-gain-efx-mbdrc-dai-copier-playback.conf> <mixout-gain-host-copier-capture.conf> <dai-copier-eqiir-module-copier-capture.conf> <gain-capture.conf> diff --git a/tools/tplg_parser/CMakeLists.txt b/tools/tplg_parser/CMakeLists.txt index 5ede07db75d6..749868fd2dd2 100644 --- a/tools/tplg_parser/CMakeLists.txt +++ b/tools/tplg_parser/CMakeLists.txt @@ -17,6 +17,12 @@ else() add_library(sof_tplg_parser SHARED "") endif() +if (CONFIG_IPC4) + set(tplg_ipc CONFIG_IPC_MAJOR_4) +else() + set(tplg_ipc CONFIG_IPC_MAJOR_3) +endif() + target_sources(sof_tplg_parser PUBLIC tokens.c process.c @@ -39,12 +45,10 @@ sof_append_relative_path_definitions(sof_tplg_parser) target_include_directories(sof_tplg_parser PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(sof_tplg_parser PRIVATE ${sof_source_directory}/src/include) +target_include_directories(sof_tplg_parser PRIVATE ${sof_source_directory}/src/audio) target_include_directories(sof_tplg_parser PRIVATE ${sof_source_directory}/src/arch/host/include) target_include_directories(sof_tplg_parser PRIVATE ${sof_source_directory}/src/platform/library/include) -target_include_directories(sof_tplg_parser PRIVATE ${sof_source_directory}/src/audio) - -# TODO: The topology parser should NOT need to include RTOS header. FIX. -target_include_directories(sof_tplg_parser PRIVATE ${sof_source_directory}/xtos/include) +target_include_directories(sof_tplg_parser PRIVATE ${sof_source_directory}/posix/include) # Configuration time, make copy configure_file(${default_asoc_h} ${CMAKE_CURRENT_BINARY_DIR}/include/alsa/sound/asoc.h) @@ -62,7 +66,7 @@ endif() target_compile_options(sof_tplg_parser PRIVATE -g -O -Wall -Werror -Wl,-EL -fPIC -DPIC -Wmissing-prototypes ${implicit_fallthrough} - -DCONFIG_LIBRARY -DCONFIG_IPC_MAJOR_3) + -DCONFIG_LIBRARY -D${tplg_ipc}) target_link_libraries(sof_tplg_parser PRIVATE -lm) diff --git a/tools/tplg_parser/include/tplg_parser/topology.h b/tools/tplg_parser/include/tplg_parser/topology.h index 83ddce2ced02..806af047e6f2 100644 --- a/tools/tplg_parser/include/tplg_parser/topology.h +++ b/tools/tplg_parser/include/tplg_parser/topology.h @@ -11,13 +11,16 @@ #define _COMMON_TPLG_H #include <stdbool.h> -#include<stdarg.h> +#include <stdarg.h> #include <stddef.h> #include <ipc/dai.h> #include <ipc/topology.h> #include <ipc/stream.h> +#include <ipc4/copier.h> +#include <ipc4/module.h> #include <kernel/tokens.h> #include <sof/list.h> +#include <volume/peak_volume.h> #ifdef TPLG_DEBUG #define DEBUG_MAX_LENGTH 256 @@ -46,6 +49,7 @@ static inline void tplg_debug(char *fmt, ...) {} #define TPLG_PARSER_SOF_DEV 1 #define TPLG_PARSER_FUZZER_DEV 2 +#define TPLG_MAX_PCM_PIPELINES 16 #define MOVE_POINTER_BY_BYTES(p, b) ((typeof(p))((uint8_t *)(p) + (b))) @@ -95,15 +99,31 @@ struct sof_ipc4_available_audio_format { uint32_t num_output_formats; }; +struct tplg_pipeline_info { + int id; + int instance_id; + int usage_count; + int mem_usage; + char *name; + struct list_item item; /* item in a list */ +}; + struct tplg_comp_info { + struct list_item item; /* item in a list */ + struct sof_ipc4_available_audio_format available_fmt; /* available formats in tplg */ + struct ipc4_module_init_instance module_init; + struct ipc4_base_module_cfg basecfg; + struct tplg_pipeline_info *pipe_info; + struct sof_uuid uuid; char *name; char *stream_name; int id; int type; int pipeline_id; void *ipc_payload; - struct list_item item; /* item in a list */ - struct sof_ipc4_available_audio_format available_fmt; /* available formats in tplg */ + int ipc_size; + int instance_id; + int module_id; }; struct tplg_route_info { @@ -112,12 +132,19 @@ struct tplg_route_info { struct list_item item; /* item in a list */ }; +struct tplg_pipeline_list { + int count; + struct tplg_pipeline_info *pipelines[TPLG_MAX_PCM_PIPELINES]; +}; + struct tplg_pcm_info { char *name; int id; struct tplg_comp_info *playback_host; struct tplg_comp_info *capture_host; struct list_item item; /* item in a list */ + struct tplg_pipeline_list playback_pipeline_list; + struct tplg_pipeline_list capture_pipeline_list; }; /* diff --git a/tools/tplg_parser/pga.c b/tools/tplg_parser/pga.c index 0a65cafa5cbb..5a23f349d679 100644 --- a/tools/tplg_parser/pga.c +++ b/tools/tplg_parser/pga.c @@ -14,11 +14,11 @@ #include <string.h> #include <math.h> #include <ipc/topology.h> -#include <volume/peak_volume.h> #include <sof/lib/uuid.h> #include <sof/ipc/topology.h> #include <tplg_parser/topology.h> #include <tplg_parser/tokens.h> +#include <volume/peak_volume.h> #define SOF_IPC4_VOL_ZERO_DB 0x7fffffff diff --git a/tools/tune/dcblock/dcblock_build_blob.m b/tools/tune/dcblock/dcblock_build_blob.m index 43fa67f5c915..0b4293054f57 100644 --- a/tools/tune/dcblock/dcblock_build_blob.m +++ b/tools/tune/dcblock/dcblock_build_blob.m @@ -1,12 +1,15 @@ -function blob8 = dcblock_build_blob(R_coeffs, endian) +function blob8 = dcblock_build_blob(R_coeffs, endian, ipc_ver) %% Settings -bits_R = 32; %Q2.30 qy_R = 30; if nargin < 2 - endian = 'little' -endif + endian = 'little'; +end + +if nargin < 3 + ipc_ver = 3; +end %% Shift values for little/big endian switch lower(endian) @@ -24,7 +27,7 @@ %% Build Blob data_size = (num_of_coeffs)*4; -[abi_bytes, abi_size] = dcblock_get_abi(data_size); +[abi_bytes, abi_size] = get_abi(data_size, ipc_ver); blob_size = data_size + abi_size; blob8 = uint8(zeros(1, blob_size)); @@ -40,7 +43,7 @@ j=j+4; end -endfunction +end function bytes = word2byte(word, sh) bytes = uint8(zeros(1,4)); diff --git a/tools/tune/dcblock/dcblock_get_abi.m b/tools/tune/dcblock/dcblock_get_abi.m deleted file mode 100644 index b65988cb99ae..000000000000 --- a/tools/tune/dcblock/dcblock_get_abi.m +++ /dev/null @@ -1,17 +0,0 @@ -function [bytes, nbytes] = dcblock_get_abi(setsize) - -%% Use sof-ctl to write ABI header into a file -abifn = 'dcblock_get_abi.bin'; -cmd = sprintf('sof-ctl -g %d -b -o %s', setsize, abifn); -system(cmd); - -%% Read file and delete it -fh = fopen(abifn, 'r'); -if fh < 0 - error("Failed to get ABI header. Is sof-ctl installed?"); -end -[bytes, nbytes] = fread(fh, inf, 'uint8'); -fclose(fh); -delete(abifn); - -end diff --git a/tools/tune/dcblock/dcblock_plot_stepfn.m b/tools/tune/dcblock/dcblock_plot_stepfn.m index 724b4bcfcf40..e0c7c3d14db3 100644 --- a/tools/tune/dcblock/dcblock_plot_stepfn.m +++ b/tools/tune/dcblock/dcblock_plot_stepfn.m @@ -1,4 +1,4 @@ -function dcblock_plot_stepfn(R, fs); +function dcblock_plot_stepfn(R, fs) % Plot the step response of a DC Blocking Filter % For a DC Blocking filter: H(z) = (1-1/z)/(1 - R/z) % Therefore the coefficients are b = [1 -1], a = [1 -R] @@ -13,4 +13,4 @@ tstr = sprintf("DC Blocking Filter Step Response, R = %i", R); title(tstr); -endfunction +end diff --git a/tools/tune/dcblock/dcblock_plot_transferfn.m b/tools/tune/dcblock/dcblock_plot_transferfn.m index 8237222014a6..513a291f666b 100644 --- a/tools/tune/dcblock/dcblock_plot_transferfn.m +++ b/tools/tune/dcblock/dcblock_plot_transferfn.m @@ -1,4 +1,4 @@ -function dcblock_plot_transferfn(R, fs); +function dcblock_plot_transferfn(R, fs) % Plot the transfer function. % For a DC Blocking filter: H(z) = (1-1/z)/(1 - R/z) % Therefore the coefficients are b = [1 -1], a = [1 -R] @@ -7,11 +7,11 @@ f = linspace(1, fs/2, 500); -semilogx(f, 20*log10(freqz(b, a, f, fs))); +semilogx(f, 20*log10(abs(freqz(b, a, f, fs)))); grid on xlabel('Frequency (Hz)'); ylabel('Magnitude (dB)'); tstr = sprintf("DC Blocking Filter Frequency Response, R = %i", R); title(tstr); -endfunction +end diff --git a/tools/tune/dcblock/example_dcblock.m b/tools/tune/dcblock/example_dcblock.m index 74490e5ab159..df8500473369 100644 --- a/tools/tune/dcblock/example_dcblock.m +++ b/tools/tune/dcblock/example_dcblock.m @@ -1,30 +1,38 @@ -function example_dcblock(); +function example_dcblock() % Set the parameters here -tplg_fn = "../../topology/topology1/m4/dcblock_coef_default.m4" % Control Bytes File +tplg1_fn = "../../topology/topology1/m4/dcblock_coef_default.m4"; % Control Bytes File +tplg2_fn = "../../topology/topology2/include/components/dcblock/default.conf"; % Use those files with sof-ctl to update the component's configuration -blob_fn = "../../ctl/dcblock_coef.blob" % Blob binary file -alsa_fn = "../../ctl/dcblock_coef.txt" % ALSA CSV format file +blob3_fn = "../../ctl/ipc3/dcblock_coef.blob"; % Blob binary file +alsa3_fn = "../../ctl/ipc3/dcblock_coef.txt"; % ALSA CSV format file +blob4_fn = "../../ctl/ipc4/dcblock_coef.blob"; % Blob binary file +alsa4_fn = "../../ctl/ipc4/dcblock_coef.txt"; % ALSA CSV format file endian = "little"; R_coeffs = [0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98]; +addpath ./../common + blob8 = dcblock_build_blob(R_coeffs, endian); +blob8_ipc4 = dcblock_build_blob(R_coeffs, endian, 4); % Generate output files -addpath ./../common +tplg_write(tplg1_fn, blob8, "DCBLOCK"); +blob_write(blob3_fn, blob8); +alsactl_write(alsa3_fn, blob8); -tplg_write(tplg_fn, blob8, "DCBLOCK"); -blob_write(blob_fn, blob8); -alsactl_write(alsa_fn, blob8); +tplg2_write(tplg2_fn, blob8_ipc4, "dcblock_config", "Exported with script example_dcblock.m"); +blob_write(blob4_fn, blob8_ipc4); +alsactl_write(alsa4_fn, blob8_ipc4); % Plot Filter's Transfer Function and Step Response % As an example, plot the graphs of the first coefficient -fs = 48e3 +fs = 48e3; dcblock_plot_transferfn(R_coeffs(1), fs); figure dcblock_plot_stepfn(R_coeffs(1), fs); rmpath ./../common -endfunction +end diff --git a/tools/tune/multiband_drc/example_multiband_drc.m b/tools/tune/multiband_drc/example_multiband_drc.m index 892c3fb41638..486e79dd88b2 100644 --- a/tools/tune/multiband_drc/example_multiband_drc.m +++ b/tools/tune/multiband_drc/example_multiband_drc.m @@ -139,7 +139,7 @@ function export_multiband_drc(prm) endian, 4); tplg_write(tplg1_fn, blob8, "MULTIBAND_DRC"); -tplg2_write(tplg2_fn, blob8_ipc4, "multiband_drc_config", 'Exported Control Bytes'); +tplg2_write(tplg2_fn, blob8_ipc4, "multiband_drc_config", "Exported with script example_multiband_drc.m"); blob_write(blob3_fn, blob8); alsactl_write(alsa3_fn, blob8); blob_write(blob4_fn, blob8_ipc4); diff --git a/west.yml b/west.yml index 5f4db594af5d..14bfd48aa368 100644 --- a/west.yml +++ b/west.yml @@ -33,19 +33,17 @@ manifest: # https://github.com/zephyrproject-rtos/zephyr/issues/58212 projects: - - name: rimage - repo-path: rimage - path: sof/rimage - revision: 4fb9fe00575bc2e9f14570803d811987fb27f010 - + # West convenience for Zephyr people who forgot --recursive when + # cloning sof.git. This adds the burden of keeping both tomlc99 + # SHA1s synchronized but in practice it barely ever moves. - name: tomlc99 repo-path: tomlc99 - path: sof/rimage/tomlc99 + path: sof/tools/rimage/tomlc99 revision: e3a03f5ec7d8d33be705c5ce8a632d998ce9b4d1 - name: zephyr repo-path: zephyr - revision: 2f90ef488a4e97c94c2cc5b95dacd1b15de32216 + revision: 3563347b108a8fe323595060576572fccdb81be6 remote: zephyrproject # Import some projects listed in zephyr/west.yml@revision diff --git a/xtos/include/sof/lib/dma.h b/xtos/include/sof/lib/dma.h index 85080e70c18b..2f0bfe940dea 100644 --- a/xtos/include/sof/lib/dma.h +++ b/xtos/include/sof/lib/dma.h @@ -75,6 +75,7 @@ struct comp_buffer; #define DMA_DEV_SP_VIRTUAL BIT(11) /**< connectable to ACP SP VIRTUAL I2S */ #define DMA_DEV_HS_VIRTUAL BIT(12) /**< connectable to ACP HS VIRTUAL I2S */ #define DMA_DEV_HS BIT(13) /**< connectable to ACP HS I2S */ +#define DMA_DEV_MICFIL BIT(14) /**< connectable to MICFIL fifo */ /* DMA access privilege flag */ #define DMA_ACCESS_EXCLUSIVE 1 @@ -254,8 +255,8 @@ struct dma_info { }; struct audio_stream; -typedef int (*dma_process_func)(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, +typedef int (*dma_process_func)(const struct audio_stream *source, + uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t frames); /** @@ -530,8 +531,8 @@ typedef void (*dma_process)(const struct audio_stream *, struct audio_stream *, uint32_t); /* copies data from DMA buffer using provided processing function */ -int dma_buffer_copy_from(struct comp_buffer __sparse_cache *source, - struct comp_buffer __sparse_cache *sink, +int dma_buffer_copy_from(struct comp_buffer *source, + struct comp_buffer *sink, dma_process_func process, uint32_t source_bytes); /* @@ -539,13 +540,13 @@ int dma_buffer_copy_from(struct comp_buffer __sparse_cache *source, * conversion function. DMA buffer consume should be performed after the data has been copied * to all sinks. */ -int dma_buffer_copy_from_no_consume(struct comp_buffer __sparse_cache *source, - struct comp_buffer __sparse_cache *sink, +int dma_buffer_copy_from_no_consume(struct comp_buffer *source, + struct comp_buffer *sink, dma_process_func process, uint32_t source_bytes); /* copies data to DMA buffer using provided processing function */ -int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, - struct comp_buffer __sparse_cache *sink, +int dma_buffer_copy_to(struct comp_buffer *source, + struct comp_buffer *sink, dma_process_func process, uint32_t sink_bytes); /* generic DMA DSP <-> Host copier */ diff --git a/xtos/include/sof/lib/mailbox.h b/xtos/include/sof/lib/mailbox.h index 86fc900138b3..06e2659a5847 100644 --- a/xtos/include/sof/lib/mailbox.h +++ b/xtos/include/sof/lib/mailbox.h @@ -69,9 +69,8 @@ void mailbox_dspbox_read(void *dest, size_t dest_size, #if CONFIG_LIBRARY -static inline -void mailbox_hostbox_write(size_t offset, const void *src, size_t bytes) -{} +#define mailbox_hostbox_write(_offset, _src, _bytes) \ + memcpy((char *)ipc->comp_data + _offset, _src, _bytes) #else diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index e531eaabb690..8deca5155919 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -58,11 +58,11 @@ set(SOF_IPC_PATH "${SOF_SRC_PATH}/ipc") set(SOF_DEBUG_PATH "${SOF_SRC_PATH}/debug") set(SOF_MATH_PATH "${SOF_SRC_PATH}/math") set(SOF_TRACE_PATH "${SOF_SRC_PATH}/trace") +set(RIMAGE_TOP ${sof_top_dir}/tools/rimage) # Save path to rimage configuration files in cmake cache for later use by # rimage during the "west sign" stage -get_filename_component(RIMAGE_CONFIG "../rimage/config" ABSOLUTE) -set(RIMAGE_CONFIG_PATH ${RIMAGE_CONFIG} CACHE PATH +set(RIMAGE_CONFIG_PATH ${RIMAGE_TOP}/config CACHE PATH " Path to rimage board configuration files") include(ExternalProject) @@ -87,7 +87,7 @@ ExternalProject_Add(sof_logger_ep ) # default SOF includes -target_include_directories(SOF INTERFACE ${sof_top_dir}/rimage/src/include) +target_include_directories(SOF INTERFACE ${RIMAGE_TOP}/src/include) target_include_directories(SOF INTERFACE ${SOF_SRC_PATH}/include) target_include_directories(SOF INTERFACE ${SOF_SRC_PATH}/arch/${ARCH}/include) target_include_directories(SOF INTERFACE ${sof_top_dir}/third_party/include) @@ -239,6 +239,7 @@ if (CONFIG_SOC_SERIES_NXP_IMX8M) ${SOF_DRIVERS_PATH}/imx/sdma.c ${SOF_DRIVERS_PATH}/imx/sai.c ${SOF_DRIVERS_PATH}/imx/ipc.c + ${SOF_DRIVERS_PATH}/imx/micfil.c ${SOF_DRIVERS_PATH}/imx/interrupt-irqsteer.c ) @@ -362,6 +363,9 @@ zephyr_library_sources( lib.c ) +if(CONFIG_ZEPHYR_DP_SCHEDULER) + zephyr_library_sources(${SOF_AUDIO_PATH}/dp_queue.c) +endif() if(CONFIG_SCHEDULE_DMA_SINGLE_CHANNEL AND NOT(CONFIG_DMA_DOMAIN)) zephyr_library_sources(${SOF_SRC_PATH}/schedule/dma_single_chan_domain.c) endif() @@ -521,10 +525,19 @@ elseif(CONFIG_IPC_MAJOR_4) ) endif() +if(CONFIG_IPC_MAJOR_3) +zephyr_library_sources_ifdef(CONFIG_COMP_MODULE_ADAPTER + ${SOF_AUDIO_PATH}/module_adapter/module_adapter.c + ${SOF_AUDIO_PATH}/module_adapter/module_adapter_ipc3.c + ${SOF_AUDIO_PATH}/module_adapter/module/generic.c +) +elseif(CONFIG_IPC_MAJOR_4) zephyr_library_sources_ifdef(CONFIG_COMP_MODULE_ADAPTER ${SOF_AUDIO_PATH}/module_adapter/module_adapter.c + ${SOF_AUDIO_PATH}/module_adapter/module_adapter_ipc4.c ${SOF_AUDIO_PATH}/module_adapter/module/generic.c ) +endif() zephyr_library_sources_ifdef(CONFIG_LIBRARY_MANAGER ${SOF_SRC_PATH}/library_manager/lib_manager.c @@ -567,13 +580,25 @@ zephyr_library_sources_ifdef(CONFIG_COMP_CHAIN_DMA ${SOF_AUDIO_PATH}/chain_dma.c ) -zephyr_library_sources_ifdef(CONFIG_COMP_SRC - ${SOF_AUDIO_PATH}/src/src_hifi2ep.c - ${SOF_AUDIO_PATH}/src/src_generic.c - ${SOF_AUDIO_PATH}/src/src_hifi3.c - ${SOF_AUDIO_PATH}/src/src_hifi4.c - ${SOF_AUDIO_PATH}/src/src.c -) +if(CONFIG_IPC_MAJOR_3) + zephyr_library_sources_ifdef(CONFIG_COMP_SRC + ${SOF_AUDIO_PATH}/src/src_hifi2ep.c + ${SOF_AUDIO_PATH}/src/src_generic.c + ${SOF_AUDIO_PATH}/src/src_hifi3.c + ${SOF_AUDIO_PATH}/src/src_hifi4.c + ${SOF_AUDIO_PATH}/src/src.c + ${SOF_AUDIO_PATH}/src/src_ipc3.c + ) +elseif(CONFIG_IPC_MAJOR_4) + zephyr_library_sources_ifdef(CONFIG_COMP_SRC + ${SOF_AUDIO_PATH}/src/src_hifi2ep.c + ${SOF_AUDIO_PATH}/src/src_generic.c + ${SOF_AUDIO_PATH}/src/src_hifi3.c + ${SOF_AUDIO_PATH}/src/src_hifi4.c + ${SOF_AUDIO_PATH}/src/src.c + ${SOF_AUDIO_PATH}/src/src_ipc4.c + ) +endif() zephyr_library_sources_ifdef(CONFIG_COMP_BASEFW_IPC4 ${SOF_AUDIO_PATH}/base_fw.c @@ -689,7 +714,7 @@ zephyr_library_sources_ifdef(CONFIG_COMP_MUX ) zephyr_library_sources_ifdef(CONFIG_COMP_GOOGLE_HOTWORD_DETECT - ${SOF_AUDIO_PATH}/google_hotword_detect.c + ${SOF_AUDIO_PATH}/google/google_hotword_detect.c ) zephyr_library_sources_ifdef(CONFIG_DTS_CODEC diff --git a/zephyr/lib/regions_mm.c b/zephyr/lib/regions_mm.c index cbf94e7f8fc8..dbb1aa087b26 100644 --- a/zephyr/lib/regions_mm.c +++ b/zephyr/lib/regions_mm.c @@ -132,8 +132,8 @@ struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, new_heap->physical_blocks_allocators[i] = new_allocator; /* Fill allocators data based on config and virtual region data */ - new_allocator->num_blocks = cfg->block_bundles_table[i].number_of_blocks; - new_allocator->blk_sz_shift = ilog2(cfg->block_bundles_table[i].block_size); + new_allocator->info.num_blocks = cfg->block_bundles_table[i].number_of_blocks; + new_allocator->info.blk_sz_shift = ilog2(cfg->block_bundles_table[i].block_size); new_allocator->buffer = (uint8_t *)new_heap->virtual_region->addr + offset; /* Create bit array that is a part of mem_block kept as a ptr */ @@ -270,11 +270,11 @@ void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) * mem_block. */ block_size = - 1 << heap->physical_blocks_allocators[mem_block_iterator]->blk_sz_shift; + 1 << heap->physical_blocks_allocators[mem_block_iterator]->info.blk_sz_shift; block_count = SOF_DIV_ROUND_UP((uint64_t)alloc_size, (uint64_t)block_size); if (block_count > - heap->physical_blocks_allocators[mem_block_iterator]->num_blocks) + heap->physical_blocks_allocators[mem_block_iterator]->info.num_blocks) continue; /* Try span alloc on first available mem_block for non span * check if block size is sufficient. @@ -455,7 +455,7 @@ int vmh_free_heap(struct vmh_heap *heap) if (!heap->physical_blocks_allocators[i]) continue; if (!sys_bitarray_is_region_cleared(heap->physical_blocks_allocators[i]->bitmap, - heap->physical_blocks_allocators[i]->num_blocks, 0)) + heap->physical_blocks_allocators[i]->info.num_blocks, 0)) return -ENOTEMPTY; } @@ -492,24 +492,24 @@ int vmh_free(struct vmh_heap *heap, void *ptr) if (heap->core_id != cpu_get_id()) return -EINVAL; - size_t mem_block_iterator, i, size_to_free, block_size, ptr_bit_array_offset, + size_t mem_block_iter, i, size_to_free, block_size, ptr_bit_array_offset, ptr_bit_array_position, physical_block_count, check_offset, check_position, check_size; uintptr_t phys_aligned_ptr, phys_aligned_alloc_end, phys_block_ptr; bool ptr_range_found; /* Get allocator from which ptr was allocated */ - for (mem_block_iterator = 0, ptr_range_found = false; - mem_block_iterator < MAX_MEMORY_ALLOCATORS_COUNT; - mem_block_iterator++) { + for (mem_block_iter = 0, ptr_range_found = false; + mem_block_iter < MAX_MEMORY_ALLOCATORS_COUNT; + mem_block_iter++) { block_size = - 1 << heap->physical_blocks_allocators[mem_block_iterator]->blk_sz_shift; + 1 << heap->physical_blocks_allocators[mem_block_iter]->info.blk_sz_shift; if (vmh_is_ptr_in_memory_range((uintptr_t)ptr, (uintptr_t)heap->physical_blocks_allocators - [mem_block_iterator]->buffer, + [mem_block_iter]->buffer, heap->physical_blocks_allocators - [mem_block_iterator]->num_blocks * block_size)) { + [mem_block_iter]->info.num_blocks * block_size)) { ptr_range_found = true; break; } @@ -528,19 +528,19 @@ int vmh_free(struct vmh_heap *heap, void *ptr) /* Not sure if that is fastest way to find the size comments welcome */ ptr_bit_array_offset = (uintptr_t)ptr - - (uintptr_t)heap->physical_blocks_allocators[mem_block_iterator]->buffer; + - (uintptr_t)heap->physical_blocks_allocators[mem_block_iter]->buffer; ptr_bit_array_position = ptr_bit_array_offset / block_size; /* Allocation bit array check */ int bit_value, prev_bit_value = 0; - sys_bitarray_test_bit(heap->allocation_sizes[mem_block_iterator], + sys_bitarray_test_bit(heap->allocation_sizes[mem_block_iter], ptr_bit_array_position, &bit_value); /* If checked bit is in position 0 we assume it is valid * and assigned 0 for further logic */ if (ptr_bit_array_position) - sys_bitarray_test_bit(heap->allocation_sizes[mem_block_iterator], + sys_bitarray_test_bit(heap->allocation_sizes[mem_block_iter], ptr_bit_array_position - 1, &prev_bit_value); /* If bit is 1 we know we could be at the start of the allocation, @@ -556,7 +556,7 @@ int vmh_free(struct vmh_heap *heap, void *ptr) */ size_t bits_to_check = heap->physical_blocks_allocators - [mem_block_iterator]->num_blocks - ptr_bit_array_position; + [mem_block_iter]->info.num_blocks - ptr_bit_array_position; /* Neeeeeeeds optimization - thinking how to do it properly * each set bit in order after another means one allocated block. @@ -567,7 +567,7 @@ int vmh_free(struct vmh_heap *heap, void *ptr) i < bits_to_check; i++) { - sys_bitarray_test_bit(heap->allocation_sizes[mem_block_iterator], i, + sys_bitarray_test_bit(heap->allocation_sizes[mem_block_iter], i, &bit_value); if (bit_value) size_to_free += block_size; @@ -582,10 +582,10 @@ int vmh_free(struct vmh_heap *heap, void *ptr) } retval = sys_mem_blocks_free_contiguous( - heap->physical_blocks_allocators[mem_block_iterator], ptr, + heap->physical_blocks_allocators[mem_block_iter], ptr, size_to_free / block_size); } else { - retval = sys_mem_blocks_free(heap->physical_blocks_allocators[mem_block_iterator], + retval = sys_mem_blocks_free(heap->physical_blocks_allocators[mem_block_iter], 1, &ptr); } @@ -610,13 +610,13 @@ int vmh_free(struct vmh_heap *heap, void *ptr) phys_block_ptr = phys_aligned_ptr + i * CONFIG_MM_DRV_PAGE_SIZE; check_offset = phys_block_ptr - - (uintptr_t)heap->physical_blocks_allocators[mem_block_iterator]->buffer; + - (uintptr_t)heap->physical_blocks_allocators[mem_block_iter]->buffer; check_position = check_offset / block_size; check_size = CONFIG_MM_DRV_PAGE_SIZE / block_size; if (sys_bitarray_is_region_cleared( - heap->physical_blocks_allocators[mem_block_iterator]->bitmap, + heap->physical_blocks_allocators[mem_block_iter]->bitmap, check_size, check_offset)) sys_mm_drv_unmap_region((void *)phys_block_ptr, CONFIG_MM_DRV_PAGE_SIZE);